From 1d688d0263cb6223650f01d2d157e55c18f657ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C2=A0Ilya=20Atamas?= Date: Mon, 22 Apr 2019 18:56:32 +0300 Subject: [PATCH] docs: extend readme, add inline docs --- go.mod | 12 ------------ go.sum | 29 ----------------------------- proxy/cache.go | 4 ++-- proxy/database_redis.go | 6 ++++++ proxy/doc.go | 5 +++++ proxy/main.go | 6 ++++++ proxy/server.go | 11 ++++++----- readme.md | 39 ++++++++++++++++++++++++++++++++++++--- 8 files changed, 61 insertions(+), 51 deletions(-) create mode 100644 proxy/doc.go diff --git a/go.mod b/go.mod index f7ac83e..0edd37c 100644 --- a/go.mod +++ b/go.mod @@ -3,22 +3,10 @@ module github.com/emeralt/npm-cache-proxy go 1.12 require ( - github.com/gin-contrib/gzip v0.0.1 - github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 // indirect github.com/gin-contrib/zap v0.0.0-20190405225521-7c4b822813e7 github.com/gin-gonic/gin v1.3.0 github.com/go-redis/redis v6.15.2+incompatible - github.com/golang/protobuf v1.3.1 // indirect - github.com/inconshreveable/mousetrap v1.0.0 // indirect - github.com/json-iterator/go v1.1.6 // indirect - github.com/mattn/go-isatty v0.0.7 // indirect github.com/spf13/cobra v0.0.3 github.com/spf13/pflag v1.0.3 // indirect - github.com/stretchr/objx v0.2.0 // indirect go.uber.org/zap v1.9.1 - golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480 // indirect - golang.org/x/net v0.0.0-20190420063019-afa5a82059c6 // indirect - golang.org/x/sync v0.0.0-20190412183630-56d357773e84 // indirect - golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a // indirect - gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect ) diff --git a/go.sum b/go.sum index 60b0f7a..609f9ba 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,6 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc= -github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 h1:AzN37oI0cOS+cougNAV9szl6CVoj2RYwzS3DpUQNtlY= github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= -github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g= -github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/zap v0.0.0-20190405225521-7c4b822813e7 h1:v6rNWmMnVDBVMc1pUUSCTobu2p4BukiPMwoj0pLqBhA= github.com/gin-contrib/zap v0.0.0-20190405225521-7c4b822813e7/go.mod h1:pQKeeey3PeRN2SbZe1jWiIkTJkylO9hL1K0Hf4Wbtt4= github.com/gin-gonic/gin v1.3.0 h1:kCmZyPklC0gVdL728E6Aj20uYBJV93nj/TkwBTKhFbs= @@ -14,16 +9,9 @@ github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDA github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -32,11 +20,7 @@ github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2 h1:EICbibRW4JNKMcY+LsWmuwob+CRS1BmdRdjphAm9mH4= github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= @@ -45,25 +29,12 @@ go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190420063019-afa5a82059c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a h1:XCr/YX7O0uxRkLq2k1ApNQMims9eCioF9UpzIPBDmuo= -golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/proxy/cache.go b/proxy/cache.go index f8ce17d..1848e90 100644 --- a/proxy/cache.go +++ b/proxy/cache.go @@ -8,7 +8,7 @@ import ( "strings" ) -// GetMetadata returns cached NPM response for a given package path +// GetMetadata returns cached NPM response for a given package path. func (proxy Proxy) GetMetadata(name string, originalPath string, request *http.Request) ([]byte, error) { options, err := proxy.GetOptions() if err != nil { @@ -93,7 +93,7 @@ func (proxy Proxy) ListMetadata() ([]string, error) { return deprefixedMetadata, nil } -// PurgeMetadata deletes all cached packages +// PurgeMetadata deletes all cached packages. func (proxy Proxy) PurgeMetadata() error { options, err := proxy.GetOptions() if err != nil { diff --git a/proxy/database_redis.go b/proxy/database_redis.go index f7caa52..588cd20 100644 --- a/proxy/database_redis.go +++ b/proxy/database_redis.go @@ -6,26 +6,32 @@ import ( "github.com/go-redis/redis" ) +// DatabaseRedis implements Database interface for Redis database. type DatabaseRedis struct { Client *redis.Client } +// Get returns data by key. func (db DatabaseRedis) Get(key string) (string, error) { return db.Client.Get(key).Result() } +// Set stores value identified by key with expiration timeout. func (db DatabaseRedis) Set(key string, value string, expiration time.Duration) error { return db.Client.Set(key, value, expiration).Err() } +// Delete deletes data by key. func (db DatabaseRedis) Delete(key string) error { return db.Client.Del(key).Err() } +// Keys returns stored keys filtered by prefix. func (db DatabaseRedis) Keys(prefix string) ([]string, error) { return db.Client.Keys(prefix + "*").Result() } +// Health returns an error if database connection cannot be estabilished. func (db DatabaseRedis) Health() error { return db.Client.Ping().Err() } diff --git a/proxy/doc.go b/proxy/doc.go new file mode 100644 index 0000000..8888271 --- /dev/null +++ b/proxy/doc.go @@ -0,0 +1,5 @@ +// +// Package proxy implements a HTTP caching proxy for Node package registry (NPM). +// See https://github.com/emeralt/npm-cache-proxy/ for more information about proxy. +// +package proxy // import "https://github.com/emeralt/npm-cache-proxy/proxy" diff --git a/proxy/main.go b/proxy/main.go index e5a7398..c45400b 100644 --- a/proxy/main.go +++ b/proxy/main.go @@ -5,6 +5,8 @@ import ( "time" ) +// Proxy is the proxy instance, it contains Database and HttpClient as static options +// and GetOptions as dynamic options provider type Proxy struct { Database Database HttpClient *http.Client @@ -12,12 +14,16 @@ type Proxy struct { GetOptions func() (Options, error) } +// Options provides dynamic options for Proxy. +// This can be used for namespace separation, +// allowing multiple users use the same proxy instance simultaneously. type Options struct { DatabasePrefix string DatabaseExpiration time.Duration UpstreamAddress string } +// Database provides interface for data storage. type Database interface { Get(key string) (string, error) Set(key string, value string, ttl time.Duration) error diff --git a/proxy/server.go b/proxy/server.go index c90d3db..16cd38e 100644 --- a/proxy/server.go +++ b/proxy/server.go @@ -13,15 +13,16 @@ type ServerOptions struct { ListenAddress string } +// Server creates http proxy server func (proxy Proxy) Server(options ServerOptions) *http.Server { router := gin.New() logger, _ := zap.NewProduction() router.Use(ginzap.Ginzap(logger, time.RFC3339, true)) - router.GET("/:scope/:name", proxy.GetPackageHandler) - router.GET("/:scope", proxy.GetPackageHandler) - router.NoRoute(proxy.NoRouteHandler) + router.GET("/:scope/:name", proxy.getPackageHandler) + router.GET("/:scope", proxy.getPackageHandler) + router.NoRoute(proxy.noRouteHandler) return &http.Server{ Handler: router, @@ -29,7 +30,7 @@ func (proxy Proxy) Server(options ServerOptions) *http.Server { } } -func (proxy Proxy) GetPackageHandler(c *gin.Context) { +func (proxy Proxy) getPackageHandler(c *gin.Context) { var name string if c.Param("name") != "" { name = c.Param("scope") + "/" + c.Param("name") @@ -47,7 +48,7 @@ func (proxy Proxy) GetPackageHandler(c *gin.Context) { } } -func (proxy Proxy) NoRouteHandler(c *gin.Context) { +func (proxy Proxy) noRouteHandler(c *gin.Context) { if c.Request.URL.Path == "/" { err := proxy.Database.Health() diff --git a/readme.md b/readme.md index 7c1337f..87b17bc 100644 --- a/readme.md +++ b/readme.md @@ -3,16 +3,26 @@ ![Docker Cloud Build Status](https://img.shields.io/docker/cloud/build/emeralt/npm-cache-proxy.svg?style=for-the-badge) - [npm-cache-proxy](#npm-cache-proxy) - - [Download](#download) + - [Quick start](#quick-start) + - [Deployment](#deployment) - [Usage](#usage) - [`ncp`](#ncp) - [`ncp list`](#ncp-list) - [`ncp purge`](#ncp-purge) - [Programmatic usage](#programmatic-usage) + - [Example](#example) + - [Benchmark](#benchmark) - [License](#license) -## Download -You can download binary for your platform on the [Releases](https://github.com/emeralt/npm-cache-proxy/releases) page. Alternatively, you can use [Docker Image](https://cloud.docker.com/u/emeralt/repository/docker/emeralt/npm-cache-proxy). +## Quick start +Release binaries for different platforms can be downloaded on the [Releases](https://github.com/emeralt/npm-cache-proxy/releases) page. Also, [Docker Image](https://cloud.docker.com/u/emeralt/repository/docker/emeralt/npm-cache-proxy) is provided. + +```bash +docker run -e REDIS_ADDRESS=host.docker.internal:6379 -p 8080:8080 -it emeralt/npm-cache-proxy +``` + +## Deployment +NCP can be deployed using Kubernetes, Docker Compose or any other container orchestration platform. NCP supports running indefinite amount of instances simultaneously. ## Usage @@ -40,7 +50,13 @@ List cached packages. Purge cached packages. ## Programmatic usage +Along with the CLI, go package is provided. Documentation is available on [godoc.org](https://godoc.org/github.com/emeralt/npm-cache-proxy/proxy). +```bash +go get -u github.com/emeralt/npm-cache-proxy/proxy +``` + +### Example ```golang package main @@ -75,6 +91,23 @@ func main() { } ``` +## Benchmark + +```bash +# GOMAXPROCS=1 GIN_MODE=release ncp --listen localhost:8080 + +$ go-wrk -c 100 -d 5 http://localhost:8080/ascii +Running 5s test @ http://localhost:8080/ascii + 100 goroutine(s) running concurrently +33321 requests in 5.00537759s, 212.69MB read +Requests/sec: 6657.04 +Transfer/sec: 42.49MB +Avg Req Time: 15.02169ms +Fastest Request: 230.514µs +Slowest Request: 571.420487ms +Number of Errors: 0 +``` + ## License [MIT](./license)