Skip to content

Commit 62e64e5

Browse files
committed
perf: move dynamic options reciever to server, enable Cache-Control HTTP header
1 parent f821e79 commit 62e64e5

File tree

9 files changed

+88
-91
lines changed

9 files changed

+88
-91
lines changed

cli/list.go

+4-6
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,11 @@ var listCmd = &cobra.Command{
1212
Use: "list",
1313
Short: "List all cached paths",
1414
Run: func(cmd *cobra.Command, args []string) {
15-
proxy := getProxy(func() (npmproxy.Options, error) {
16-
return npmproxy.Options{
17-
DatabasePrefix: persistentOptions.RedisPrefix,
18-
}, nil
19-
})
15+
proxy := getProxy()
2016

21-
metadatas, err := proxy.ListCachedPaths()
17+
metadatas, err := proxy.ListCachedPaths(npmproxy.Options{
18+
DatabasePrefix: persistentOptions.RedisPrefix,
19+
})
2220
if err != nil {
2321
panic(err)
2422
}

cli/main.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func init() {
2525
rootCmd.PersistentFlags().StringVar(&persistentOptions.RedisPrefix, "redis-prefix", getEnvString("REDIS_PREFIX", "ncp-"), "Redis prefix")
2626
}
2727

28-
func getProxy(getOptions func() (npmproxy.Options, error)) *npmproxy.Proxy {
28+
func getProxy() *npmproxy.Proxy {
2929
return &npmproxy.Proxy{
3030
Database: npmproxy.DatabaseRedis{
3131
Client: redis.NewClient(&redis.Options{
@@ -37,7 +37,6 @@ func getProxy(getOptions func() (npmproxy.Options, error)) *npmproxy.Proxy {
3737
HttpClient: &http.Client{
3838
Transport: http.DefaultTransport,
3939
},
40-
GetOptions: getOptions,
4140
}
4241
}
4342

cli/purge.go

+4-6
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,11 @@ var purgeCmd = &cobra.Command{
1010
Use: "purge",
1111
Short: "Purge all cached paths",
1212
Run: func(cmd *cobra.Command, args []string) {
13-
proxy := getProxy(func() (npmproxy.Options, error) {
14-
return npmproxy.Options{
15-
DatabasePrefix: persistentOptions.RedisPrefix,
16-
}, nil
17-
})
13+
proxy := getProxy()
1814

19-
err := proxy.PurgeCachedPaths()
15+
err := proxy.PurgeCachedPaths(npmproxy.Options{
16+
DatabasePrefix: persistentOptions.RedisPrefix,
17+
})
2018
if err != nil {
2119
panic(err)
2220
}

cli/root.go

+18-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cli
22

33
import (
4+
"log"
45
"time"
56

67
npmproxy "github.com/emeralt/npm-cache-proxy/proxy"
@@ -31,16 +32,24 @@ func init() {
3132
}
3233

3334
func run(cmd *cobra.Command, args []string) {
34-
proxy := getProxy(func() (npmproxy.Options, error) {
35-
return npmproxy.Options{
36-
DatabasePrefix: persistentOptions.RedisPrefix,
37-
DatabaseExpiration: time.Duration(rootOptions.CacheTTL) * time.Second,
38-
UpstreamAddress: rootOptions.UpstreamAddress,
39-
}, nil
40-
})
41-
42-
proxy.Server(npmproxy.ServerOptions{
35+
proxy := getProxy()
36+
37+
log.Print("Listening on " + rootOptions.ListenAddress)
38+
39+
err := proxy.Server(npmproxy.ServerOptions{
4340
ListenAddress: rootOptions.ListenAddress,
4441
Silent: rootOptions.Silent,
42+
43+
GetOptions: func() (npmproxy.Options, error) {
44+
return npmproxy.Options{
45+
DatabasePrefix: persistentOptions.RedisPrefix,
46+
DatabaseExpiration: time.Duration(rootOptions.CacheTTL) * time.Second,
47+
UpstreamAddress: rootOptions.UpstreamAddress,
48+
}, nil
49+
},
4550
}).ListenAndServe()
51+
52+
if err != nil {
53+
log.Fatal(err)
54+
}
4655
}

example/main.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,16 @@ func main() {
1818
}),
1919
},
2020
HttpClient: &http.Client{},
21+
}
22+
23+
proxy.Server(npmproxy.ServerOptions{
24+
ListenAddress: "localhost:8080",
2125
GetOptions: func() (npmproxy.Options, error) {
2226
return npmproxy.Options{
2327
DatabasePrefix: "ncp-",
2428
DatabaseExpiration: 1 * time.Hour,
2529
UpstreamAddress: "https://registry.npmjs.org",
2630
}, nil
2731
},
28-
}
29-
30-
proxy.Server(npmproxy.ServerOptions{
31-
ListenAddress: "localhost:8080",
3232
}).ListenAndServe()
3333
}

proxy/cache.go

+3-18
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,7 @@ import (
1010
)
1111

1212
// GetCachedPath returns cached upstream response for a given url path.
13-
func (proxy Proxy) GetCachedPath(path string, request *http.Request) ([]byte, error) {
14-
options, err := proxy.GetOptions()
15-
if err != nil {
16-
return nil, err
17-
}
18-
13+
func (proxy Proxy) GetCachedPath(options Options, path string, request *http.Request) ([]byte, error) {
1914
key := options.DatabasePrefix + path
2015

2116
// get package from database
@@ -72,12 +67,7 @@ func (proxy Proxy) GetCachedPath(path string, request *http.Request) ([]byte, er
7267
}
7368

7469
// ListCachedPaths returns list of all cached url paths.
75-
func (proxy Proxy) ListCachedPaths() ([]string, error) {
76-
options, err := proxy.GetOptions()
77-
if err != nil {
78-
return nil, err
79-
}
80-
70+
func (proxy Proxy) ListCachedPaths(options Options) ([]string, error) {
8171
metadata, err := proxy.Database.Keys(options.DatabasePrefix)
8272
if err != nil {
8373
return nil, err
@@ -92,12 +82,7 @@ func (proxy Proxy) ListCachedPaths() ([]string, error) {
9282
}
9383

9484
// PurgeCachedPaths deletes all cached url paths.
95-
func (proxy Proxy) PurgeCachedPaths() error {
96-
options, err := proxy.GetOptions()
97-
if err != nil {
98-
return err
99-
}
100-
85+
func (proxy Proxy) PurgeCachedPaths(options Options) error {
10186
metadata, err := proxy.Database.Keys(options.DatabasePrefix)
10287
if err != nil {
10388
return err

proxy/proxy.go

-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ import (
1414
type Proxy struct {
1515
Database Database
1616
HttpClient *http.Client
17-
18-
GetOptions func() (Options, error)
1917
}
2018

2119
// Options provides dynamic options for Proxy.

proxy/server.go

+43-34
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ import (
1414
type ServerOptions struct {
1515
ListenAddress string
1616
Silent bool
17+
18+
GetOptions func() (Options, error)
1719
}
1820

1921
// Server creates http proxy server
2022
func (proxy Proxy) Server(options ServerOptions) *http.Server {
23+
gin.SetMode("release")
24+
2125
router := gin.New()
2226

2327
if options.Silent {
@@ -28,55 +32,60 @@ func (proxy Proxy) Server(options ServerOptions) *http.Server {
2832
router.Use(ginzap.RecoveryWithZap(logger, true))
2933
}
3034

31-
router.GET("/:scope/:name", proxy.getPackageHandler)
32-
router.GET("/:scope", proxy.getPackageHandler)
33-
router.NoRoute(proxy.noRouteHandler)
35+
router.GET("/:scope/:name", proxy.getPackageHandler(options))
36+
router.GET("/:scope", proxy.getPackageHandler(options))
37+
router.NoRoute(proxy.noRouteHandler(options))
3438

3539
return &http.Server{
3640
Handler: router,
3741
Addr: options.ListenAddress,
3842
}
3943
}
4044

41-
func (proxy Proxy) getPackageHandler(c *gin.Context) {
42-
pkg, err := proxy.GetCachedPath(c.Request.URL.Path, c.Request)
43-
44-
if err != nil {
45-
c.AbortWithError(500, err)
46-
} else {
47-
// c.Header("Content-Encoding", "gzip")
48-
c.Data(200, "application/json", pkg)
49-
}
50-
}
45+
func (proxy Proxy) getPackageHandler(options ServerOptions) gin.HandlerFunc {
46+
return func(c *gin.Context) {
47+
options, err := options.GetOptions()
5148

52-
func (proxy Proxy) getTarballHabdler(c *gin.Context) {
53-
pkg, err := proxy.GetCachedPath(c.Request.URL.Path, c.Request)
49+
if err != nil {
50+
c.AbortWithError(500, err)
51+
} else {
52+
pkg, err := proxy.GetCachedPath(options, c.Request.URL.Path, c.Request)
5453

55-
if err != nil {
56-
c.AbortWithError(500, err)
57-
} else {
58-
c.Data(200, "application/json", pkg)
54+
if err != nil {
55+
c.AbortWithError(500, err)
56+
} else {
57+
c.Header("Cache-Control", "public, max-age="+string(int(options.DatabaseExpiration.Seconds())))
58+
c.Data(200, "application/json", pkg)
59+
}
60+
}
5961
}
6062
}
6163

62-
func (proxy Proxy) noRouteHandler(c *gin.Context) {
63-
if strings.Contains(c.Request.URL.Path, ".tgz") {
64-
proxy.getTarballHabdler(c)
65-
} else if c.Request.URL.Path == "/" {
66-
err := proxy.Database.Health()
64+
func (proxy Proxy) noRouteHandler(options ServerOptions) gin.HandlerFunc {
65+
tarballHandler := proxy.getPackageHandler(options)
6766

68-
if err != nil {
69-
c.AbortWithStatusJSON(503, err)
70-
} else {
71-
c.AbortWithStatusJSON(200, gin.H{"ok": true})
72-
}
73-
} else {
74-
options, err := proxy.GetOptions()
67+
return func(c *gin.Context) {
68+
if strings.Contains(c.Request.URL.Path, ".tgz") {
69+
// get tarball
70+
tarballHandler(c)
71+
} else if c.Request.URL.Path == "/" {
72+
// get health
73+
err := proxy.Database.Health()
7574

76-
if err != nil {
77-
c.AbortWithStatusJSON(500, err)
75+
if err != nil {
76+
c.AbortWithStatusJSON(503, err)
77+
} else {
78+
c.AbortWithStatusJSON(200, gin.H{"ok": true})
79+
}
7880
} else {
79-
c.Redirect(http.StatusTemporaryRedirect, options.UpstreamAddress+c.Request.URL.Path)
81+
// redirect
82+
options, err := options.GetOptions()
83+
84+
if err != nil {
85+
c.AbortWithStatusJSON(500, err)
86+
} else {
87+
c.Redirect(http.StatusTemporaryRedirect, options.UpstreamAddress+c.Request.URL.Path)
88+
}
8089
}
8190
}
8291
}

readme.md

+11-10
Original file line numberDiff line numberDiff line change
@@ -107,35 +107,36 @@ import (
107107
"time"
108108

109109
npmproxy "github.com/emeralt/npm-cache-proxy/proxy"
110-
redis "github.com/go-redis/redis"
110+
"github.com/go-redis/redis"
111111
)
112112

113113
func main() {
114+
// create proxy
114115
proxy := npmproxy.Proxy{
115-
// you can provide you own Database
116-
// or use an existing one
116+
// use redis as database
117117
Database: npmproxy.DatabaseRedis{
118+
// see github.com/go-redis/redis
118119
Client: redis.NewClient(&redis.Options{
119120
Addr: "localhost:6379",
120121
}),
121122
},
122123

123-
// allows to reuse tcp connections
124+
// reuse connections
124125
HttpClient: &http.Client{},
126+
}
127+
128+
// create and start server
129+
proxy.Server(npmproxy.ServerOptions{
130+
ListenAddress: "localhost:8080",
125131

126-
// allows to get options dynamically
132+
// allow fetching options dynamically on each request
127133
GetOptions: func() (npmproxy.Options, error) {
128134
return npmproxy.Options{
129135
DatabasePrefix: "ncp-",
130136
DatabaseExpiration: 1 * time.Hour,
131137
UpstreamAddress: "https://registry.npmjs.org",
132138
}, nil
133139
},
134-
}
135-
136-
// listen on http://localhost:8080
137-
proxy.Server(npmproxy.ServerOptions{
138-
ListenAddress: "localhost:8080",
139140
}).ListenAndServe()
140141
}
141142
```

0 commit comments

Comments
 (0)