Skip to content

Commit dbd1212

Browse files
authored
Merge pull request #3 from greeddj/main
Add NPM proxy support
2 parents 2f63769 + 4d37a76 commit dbd1212

16 files changed

Lines changed: 566 additions & 27 deletions

.golangci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ linters:
1515
- staticcheck
1616
- unconvert
1717
- unused
18+
- modernize
1819
settings:
1920
goconst:
2021
min-len: 2

README.md

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ server:
88
pypi:
99
pypi.org: https://pypi.org/simple
1010
rubygems:
11-
rubygems.org: https://rubygems.org
11+
rubygems: https://rubygems.org
1212
galaxy:
1313
ansible:
1414
url: https://galaxy.ansible.com
@@ -20,6 +20,8 @@ server:
2020
get_helm: https://get.helm.sh
2121
goproxy:
2222
golang: https://proxy.golang.org
23+
npm:
24+
npmjs: https://registry.npmjs.org
2325
```
2426
2527
## Usage
@@ -74,8 +76,6 @@ source "https://rubygems.org" do
7476
end
7577
```
7678

77-
78-
7979
### Static files
8080

8181
Access cached static files:
@@ -105,3 +105,31 @@ The proxy supports all standard GOPROXY protocol endpoints:
105105
- `/{module}/@v/{version}.mod` - go.mod file for the version
106106
- `/{module}/@v/{version}.zip` - source code archive
107107
- `/{module}/@latest` - latest version info
108+
109+
### NPM
110+
111+
To use HUB as an npm registry proxy, set the `registry` to your HUB instance:
112+
113+
```bash
114+
npm config set registry http://localhost:6587/npm/npmjs
115+
```
116+
117+
For a scoped registry:
118+
119+
```bash
120+
npm config set @my-scope:registry http://localhost:6587/npm/npmjs
121+
```
122+
123+
Or it can be used in the file `.npmrc`
124+
125+
```ini
126+
registry=http://localhost:6587/npm/npmjs
127+
```
128+
129+
The proxy supports the following npm registry endpoints:
130+
131+
- `/{package}` - package metadata (packument)
132+
- `/@scope%2F{name}` - scoped package metadata (packument)
133+
- `/{package}/-/{tarball}.tgz` - package tarball
134+
- `/@scope/{name}/-/{tarball}.tgz` - scoped package tarball
135+
- `/-/v1/search` - search (cached for 10 minutes)

config.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ server:
1515
get_helm: https://get.helm.sh
1616
goproxy:
1717
golang: https://proxy.golang.org
18+
npm:
19+
npmjs: https://registry.npmjs.org

main.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,15 +114,20 @@ func startServer(c *cli.Context) error {
114114
c.Error(err)
115115
}
116116
stop := time.Now()
117+
cacheStatus := res.Header().Get("X-Cache-Status")
118+
if cacheStatus == "" {
119+
cacheStatus = "UNKNOWN"
120+
}
117121
message := fmt.Sprintf(
118-
"[%s] %s %s requested from %s with status %d in %s [%s]",
122+
"[%s] %s %s requested from %s with status %d in %s [%s] cache=%s",
119123
c.Request().Host,
120124
req.Method,
121125
req.RequestURI,
122126
c.RealIP(),
123127
res.Status,
124128
stop.Sub(start).String(),
125129
c.Path(),
130+
cacheStatus,
126131
)
127132

128133
logger := c.Get("logger").(*zap.SugaredLogger)
@@ -186,6 +191,11 @@ func startServer(c *cli.Context) error {
186191
}).Name = fmt.Sprintf("goproxy::%s", k)
187192
}
188193

194+
for k := range cfg.Server.NPM {
195+
n := e.Group(fmt.Sprintf("/npm/%s", k))
196+
n.GET("/*", handlers.NpmProxy(k)).Name = fmt.Sprintf("npm::%s", k)
197+
}
198+
189199
for k, v := range cfg.Server.Galaxy {
190200
g := e.Group(fmt.Sprintf("/galaxy/%s", k))
191201
if v.URL != "" && v.Dir != "" {

pkg/handlers/galaxy_local.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ func GalaxyLocalCollection(key string) echo.HandlerFunc {
4545
collection.HighestVersion.Href = fmt.Sprintf("/api/v3/collections/%s/%s/versions/%s/", namespace, name, collectionLocal.Latest.Version)
4646
collection.UpdatedAt = collectionLocal.Latest.Time.UTC()
4747

48+
c.Response().Header().Add("X-Cache-Status", "LOCAL")
4849
return c.JSON(http.StatusOK, collection)
4950
}
5051
}
@@ -78,6 +79,7 @@ func GalaxyLocalCollectionVersions(key string) echo.HandlerFunc {
7879
collectionVersions.Data = append(collectionVersions.Data, verInfo)
7980
}
8081

82+
c.Response().Header().Add("X-Cache-Status", "LOCAL")
8183
return c.JSON(http.StatusOK, collectionVersions)
8284
}
8385
}
@@ -177,6 +179,7 @@ func GalaxyLocalCollectionVersionInfo(key string) echo.HandlerFunc {
177179
collectionVersionInfo.Metadata.Dependencies = manifest.CollectionInfo.Dependencies
178180
collectionVersionInfo.Files = files
179181

182+
c.Response().Header().Add("X-Cache-Status", "LOCAL")
180183
return c.JSON(http.StatusOK, collectionVersionInfo)
181184
}(c)
182185
}
@@ -201,6 +204,7 @@ func GalaxyLocalCollectionGet(key string) echo.HandlerFunc {
201204
logger.Named(loggerNS).Debugf("Collection not found: %s/%s", namespace, name)
202205
return c.String(http.StatusNotFound, "")
203206
}
207+
c.Response().Header().Add("X-Cache-Status", "LOCAL")
204208
c.Response().Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s-%s-%s.tar.gz\"", namespace, name, version))
205209
return c.File(dest)
206210
}

pkg/handlers/galaxy_proxy.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@ func GalaxyProxyCollection(key string) echo.HandlerFunc {
3232
logger.Named(loggerNS).Errorf("[Downloading] %s", err)
3333
if _, err = os.Stat(dest); errors.Is(err, os.ErrNotExist) {
3434
logger.Named(loggerNS).Errorf("[FS]: %s", err)
35+
c.Response().Header().Add("X-Cache-Status", "ERROR")
3536
return c.String(status, fmt.Sprintf("%v", err))
3637
}
37-
c.Response().Header().Add("X-Cache-Status", "HIT")
38+
c.Response().Header().Add("X-Cache-Status", "STALE")
3839
logger.Named(loggerNS).Debugf("Remote %s served from local file %s", url, dest)
3940
} else {
41+
c.Response().Header().Add("X-Cache-Status", "MISS")
4042
logger.Named(loggerNS).Debugf("Remote %s saved as %s", url, dest)
4143
}
4244
var collection types.GalaxyCollection
@@ -69,11 +71,13 @@ func GalaxyProxyCollectionVersions(key string) echo.HandlerFunc {
6971
logger.Named(loggerNS).Errorf("[Downloading] %s", err)
7072
if _, err = os.Stat(dest); errors.Is(err, os.ErrNotExist) {
7173
logger.Named(loggerNS).Errorf("[FS]: %s", err)
74+
c.Response().Header().Add("X-Cache-Status", "ERROR")
7275
return c.String(status, fmt.Sprintf("%v", err))
7376
}
74-
c.Response().Header().Add("X-Cache-Status", "HIT")
77+
c.Response().Header().Add("X-Cache-Status", "STALE")
7578
logger.Named(loggerNS).Debugf("Remote %s served from local file %s", url, dest)
7679
} else {
80+
c.Response().Header().Add("X-Cache-Status", "MISS")
7781
logger.Named(loggerNS).Debugf("Remote %s saved as %s", url, dest)
7882
}
7983
var collectionVersions types.GalaxyCollectionVersions
@@ -107,11 +111,13 @@ func GalaxyProxyCollectionVersionInfo(key string) echo.HandlerFunc {
107111
logger.Named(loggerNS).Errorf("[Downloading] %s", err)
108112
if _, err = os.Stat(dest); errors.Is(err, os.ErrNotExist) {
109113
logger.Named(loggerNS).Errorf("[FS]: %s", err)
114+
c.Response().Header().Add("X-Cache-Status", "ERROR")
110115
return c.String(http.StatusNotFound, "")
111116
}
112-
c.Response().Header().Add("X-Cache-Status", "HIT")
117+
c.Response().Header().Add("X-Cache-Status", "STALE")
113118
logger.Named(loggerNS).Debugf("Remote %s served from local file %s", url, dest)
114119
} else {
120+
c.Response().Header().Add("X-Cache-Status", "MISS")
115121
logger.Named(loggerNS).Debugf("Remote %s saved as %s", url, dest)
116122
}
117123
var CollectionVersionInfo types.GalaxyCollectionVersionInfo
@@ -148,6 +154,7 @@ func GalaxyProxyCollectionGet(key string) echo.HandlerFunc {
148154
_, err := misc.DownloadFile(url, versionFile, headers)
149155
if err != nil {
150156
logger.Named(loggerNS).Errorf("[Downloading] %s", err)
157+
c.Response().Header().Add("X-Cache-Status", "ERROR")
151158
return c.String(http.StatusBadRequest, "Downloading error")
152159
}
153160
logger.Named(loggerNS).Debugf("Remote %s saved as %s", url, versionFile)
@@ -167,6 +174,7 @@ func GalaxyProxyCollectionGet(key string) echo.HandlerFunc {
167174
status, err := misc.DownloadFile(url, dest, headers)
168175
if err != nil {
169176
logger.Named(loggerNS).Errorf("[Downloading] %s", err)
177+
c.Response().Header().Add("X-Cache-Status", "ERROR")
170178
return c.String(status, fmt.Sprintf("%v", err))
171179
}
172180
c.Response().Header().Add("X-Cache-Status", "MISS")
@@ -183,6 +191,7 @@ func GalaxyProxyCollectionGet(key string) echo.HandlerFunc {
183191
status, err := misc.DownloadFile(url, dest, headers)
184192
if err != nil {
185193
logger.Named(loggerNS).Errorf("[Downloading] %s", err)
194+
c.Response().Header().Add("X-Cache-Status", "ERROR")
186195
return c.String(status, fmt.Sprintf("%v", err))
187196
}
188197
logger.Named(loggerNS).Debugf("Downloaded %s", url)

pkg/handlers/goproxy.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@ func downloadAndCacheFile(c echo.Context, key, loggerNS, url, dest string) error
2828
logger.Named(loggerNS).Errorf("[Downloading] %s", err)
2929
if _, err = os.Stat(dest); errors.Is(err, os.ErrNotExist) {
3030
logger.Named(loggerNS).Errorf("[FS]: %s", err)
31+
c.Response().Header().Add("X-Cache-Status", "ERROR")
3132
return c.String(status, "410 Gone\n")
3233
}
33-
c.Response().Header().Add("X-Cache-Status", "HIT")
34+
c.Response().Header().Add("X-Cache-Status", "STALE")
3435
logger.Named(loggerNS).Debugf("Remote %s served from local file %s", url, dest)
3536
} else {
3637
c.Response().Header().Add("X-Cache-Status", "MISS")
@@ -62,9 +63,10 @@ func GoProxyList(key string) echo.HandlerFunc {
6263
logger.Named(loggerNS).Errorf("[Downloading] %s", err)
6364
if _, err = os.Stat(dest); errors.Is(err, os.ErrNotExist) {
6465
logger.Named(loggerNS).Errorf("[FS]: %s", err)
66+
c.Response().Header().Add("X-Cache-Status", "ERROR")
6567
return c.String(status, "410 Gone\n")
6668
}
67-
c.Response().Header().Add("X-Cache-Status", "HIT")
69+
c.Response().Header().Add("X-Cache-Status", "STALE")
6870
logger.Named(loggerNS).Debugf("Remote %s served from local file %s", url, dest)
6971
} else {
7072
c.Response().Header().Add("X-Cache-Status", "MISS")
@@ -161,8 +163,10 @@ func GoProxyZip(key string) echo.HandlerFunc {
161163
logger.Named(loggerNS).Errorf("[Downloading] %s", err)
162164
if _, err = os.Stat(dest); errors.Is(err, os.ErrNotExist) {
163165
logger.Named(loggerNS).Errorf("[FS]: %s", err)
166+
c.Response().Header().Add("X-Cache-Status", "ERROR")
164167
return c.String(status, "410 Gone\n")
165168
}
169+
c.Response().Header().Add("X-Cache-Status", "STALE")
166170
logger.Named(loggerNS).Debugf("Remote %s served from local file %s", url, dest)
167171
} else {
168172
c.Response().Header().Add("X-Cache-Status", "MISS")
@@ -205,9 +209,10 @@ func GoProxyLatest(key string) echo.HandlerFunc {
205209
logger.Named(loggerNS).Errorf("[Downloading] %s", err)
206210
if _, err = os.Stat(dest); errors.Is(err, os.ErrNotExist) {
207211
logger.Named(loggerNS).Errorf("[FS]: %s", err)
212+
c.Response().Header().Add("X-Cache-Status", "ERROR")
208213
return c.String(status, "410 Gone\n")
209214
}
210-
c.Response().Header().Add("X-Cache-Status", "HIT")
215+
c.Response().Header().Add("X-Cache-Status", "STALE")
211216
logger.Named(loggerNS).Debugf("Remote %s served from local file %s", url, dest)
212217
} else {
213218
c.Response().Header().Add("X-Cache-Status", "MISS")

0 commit comments

Comments
 (0)