11local cjson = require " cjson.safe"
2+ local http = require " resty.http"
23
34local _M = {}
45
@@ -11,6 +12,44 @@ function _M.init()
1112 npmConfig :set (' npm_upstream_pattern' , pattern )
1213end
1314
15+ function _M .prefetchRelatedPackages (premature , selfHost , pkg )
16+ local httpc = http .new ()
17+ httpc :connect (' 127.0.0.1' , 4873 )
18+ local distTags = pkg [' dist-tags' ] or {}
19+ local versions = pkg .versions or {}
20+ local latestVersion = distTags .latest
21+ local latest = versions [latestVersion ] or {}
22+ local deps = latest .dependencies or {}
23+ local reqs = {}
24+ -- find any deps that we haven't already seen and queue them for fetching
25+ for k , v in pairs (deps ) do
26+ if meta :get (' /' .. k ) == nil then
27+ table.insert (reqs , {
28+ path = ' /' .. k ,
29+ method = ' GET' ,
30+ headers = {
31+ [" Host" ] = selfHost ,
32+ },
33+ })
34+ end
35+ end
36+ -- extract all the tarball URLs and fetch them to force them to be cached
37+ for v ,p in pairs (versions ) do
38+ local scheme , host , port , path , query = unpack (httpc :parse_uri (p .dist .tarball ))
39+ table.insert (reqs , {
40+ path = path ,
41+ method = ' GET' ,
42+ })
43+ end
44+ local responses , err = httpc :request_pipeline (reqs )
45+ for i ,r in ipairs (responses ) do
46+ if r .status then
47+ r :read_body () -- to oblivion!
48+ end
49+ end
50+ httpc :close ()
51+ end
52+
1453function _M .getPackage ()
1554 local uri = ngx .var .uri
1655 local meta = ngx .shared .npmMeta
@@ -27,7 +66,8 @@ function _M.getPackage()
2766 -- next time
2867 return ngx .redirect (uri , ngx .HTTP_MOVED_TEMPORARILY )
2968 end
30- meta :set (uri , body )
69+ local succ , err , forcible = meta :set (uri , body )
70+ ngx .timer .at (0.1 , _M .prefetchRelatedPackages , ngx .var .http_host , pkgJSON )
3171 end
3272 ngx .header [" Content-Length" ] = # body
3373 ngx .print (body )
0 commit comments