1
1
local cjson = require " cjson.safe"
2
+ local http = require " resty.http"
2
3
3
4
local _M = {}
4
5
@@ -18,6 +19,44 @@ function _M.init()
18
19
npmConfig :set (' MAXAGE' , _M .MAXAGE )
19
20
end
20
21
22
+ function _M .prefetchRelatedPackages (premature , selfHost , pkg )
23
+ local httpc = http .new ()
24
+ httpc :connect (' 127.0.0.1' , 4873 )
25
+ local distTags = pkg [' dist-tags' ] or {}
26
+ local versions = pkg .versions or {}
27
+ local latestVersion = distTags .latest
28
+ local latest = versions [latestVersion ] or {}
29
+ local deps = latest .dependencies or {}
30
+ local reqs = {}
31
+ -- find any deps that we haven't already seen and queue them for fetching
32
+ for k , v in pairs (deps ) do
33
+ if meta :get (' /' .. k ) == nil then
34
+ table.insert (reqs , {
35
+ path = ' /' .. k ,
36
+ method = ' GET' ,
37
+ headers = {
38
+ [" Host" ] = selfHost ,
39
+ },
40
+ })
41
+ end
42
+ end
43
+ -- extract all the tarball URLs and fetch them to force them to be cached
44
+ for v ,p in pairs (versions ) do
45
+ local scheme , host , port , path , query = unpack (httpc :parse_uri (p .dist .tarball ))
46
+ table.insert (reqs , {
47
+ path = path ,
48
+ method = ' GET' ,
49
+ })
50
+ end
51
+ local responses , err = httpc :request_pipeline (reqs )
52
+ for i ,r in ipairs (responses ) do
53
+ if r .status then
54
+ r :read_body () -- to oblivion!
55
+ end
56
+ end
57
+ httpc :close ()
58
+ end
59
+
21
60
function _M .getPackage ()
22
61
local uri = ngx .var .uri
23
62
local meta = ngx .shared .npmMeta
@@ -37,10 +76,14 @@ function _M.getPackage()
37
76
return ngx .redirect (uri , ngx .HTTP_MOVED_TEMPORARILY )
38
77
end
39
78
meta :set (uri , body , _M .MAXAGE )
79
+ -- We rewrite the URLs AFTER caching so that we can be accessed by
80
+ -- any hostname that is pointed at us.
81
+ body = string.gsub (body , _M .hostPattern , base )
82
+ ngx .timer .at (0.1 , _M .prefetchRelatedPackages , ngx .var .http_host , pkgJSON )
40
83
else
84
+ body = string.gsub (body , _M .hostPattern , base )
41
85
ngx .var .ephemeralCacheStatus = ' HIT'
42
86
end
43
- body = string.gsub (body , _M .hostPattern , base )
44
87
ngx .header [" Content-Length" ] = # body
45
88
ngx .print (body )
46
89
end
0 commit comments