]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/lib/cache/caching-client.js
Adding integrated tile server
[simantics/district.git] / org.simantics.maps.server / node / node-v4.8.0-win-x64 / node_modules / npm / lib / cache / caching-client.js
1 module.exports = CachingRegistryClient
2
3 var path = require("path")
4   , fs = require("graceful-fs")
5   , url = require("url")
6   , assert = require("assert")
7   , inherits = require("util").inherits
8
9 var RegistryClient = require("npm-registry-client")
10   , npm = require("../npm.js")
11   , log = require("npmlog")
12   , getCacheStat = require("./get-stat.js")
13   , cacheFile = require("npm-cache-filename")
14   , mkdirp = require("mkdirp")
15   , rimraf = require("rimraf")
16   , chownr = require("chownr")
17   , writeFile = require("write-file-atomic")
18
19 function CachingRegistryClient (config) {
20   RegistryClient.call(this, adaptConfig(config))
21
22   this._mapToCache = cacheFile(config.get("cache"))
23
24   // swizzle in our custom cache invalidation logic
25   this._request = this.request
26   this.request  = this._invalidatingRequest
27   this.get      = get
28 }
29 inherits(CachingRegistryClient, RegistryClient)
30
31 CachingRegistryClient.prototype._invalidatingRequest = function (uri, params, cb) {
32   var client = this
33   this._request.call(this, uri, params, function () {
34     var args = arguments
35
36     var method = params.method
37     if (method !== "HEAD" && method !== "GET") {
38       var invalidated = client._mapToCache(uri)
39       // invalidate cache
40       //
41       // This is irrelevant for commands that do etag / last-modified caching,
42       // but ls and view also have a timed cache, so this keeps the user from
43       // thinking that it didn't work when it did.
44       // Note that failure is an acceptable option here, since the only
45       // result will be a stale cache for some helper commands.
46       log.verbose("request", "invalidating", invalidated, "on", method)
47       return rimraf(invalidated, function () {
48         cb.apply(undefined, args)
49       })
50     }
51
52     cb.apply(undefined, args)
53   })
54 }
55
56 function get (uri, params, cb) {
57   assert(typeof uri === "string", "must pass registry URI to get")
58   assert(params && typeof params === "object", "must pass params to get")
59   assert(typeof cb === "function", "must pass callback to get")
60
61   var parsed = url.parse(uri)
62   assert(
63     parsed.protocol === "http:" || parsed.protocol === "https:",
64     "must have a URL that starts with http: or https:"
65   )
66
67   var cacheBase = cacheFile(npm.config.get("cache"))(uri)
68   var cachePath = path.join(cacheBase, ".cache.json")
69
70   // If the GET is part of a write operation (PUT or DELETE), then
71   // skip past the cache entirely, but still save the results.
72   if (uri.match(/\?write=true$/)) {
73     log.verbose("get", "GET as part of write; not caching result")
74     return get_.call(this, uri, cachePath, params, cb)
75   }
76
77   var client = this
78   fs.stat(cachePath, function (er, stat) {
79     if (!er) {
80       fs.readFile(cachePath, function (er, data) {
81         try {
82           data = JSON.parse(data)
83         }
84         catch (ex) {
85           data = null
86         }
87
88         params.stat = stat
89         params.data = data
90
91         get_.call(client, uri, cachePath, params, cb)
92       })
93     }
94     else {
95       get_.call(client, uri, cachePath, params, cb)
96     }
97   })
98 }
99
100 function get_ (uri, cachePath, params, cb) {
101   var staleOk = params.staleOk === undefined ? false : params.staleOk
102     , timeout = params.timeout === undefined ? -1 : params.timeout
103     , data    = params.data
104     , stat    = params.stat
105     , etag
106     , lastModified
107
108   timeout = Math.min(timeout, npm.config.get("cache-max") || 0)
109   timeout = Math.max(timeout, npm.config.get("cache-min") || -Infinity)
110   if (process.env.COMP_CWORD !== undefined &&
111       process.env.COMP_LINE  !== undefined &&
112       process.env.COMP_POINT !== undefined) {
113     timeout = Math.max(timeout, 60000)
114   }
115
116   if (data) {
117     if (data._etag) etag = data._etag
118     if (data._lastModified) lastModified = data._lastModified
119
120     if (stat && timeout && timeout > 0) {
121       if ((Date.now() - stat.mtime.getTime())/1000 < timeout) {
122         log.verbose("get", uri, "not expired, no request")
123         delete data._etag
124         delete data._lastModified
125         return cb(null, data, JSON.stringify(data), { statusCode : 304 })
126       }
127
128       if (staleOk) {
129         log.verbose("get", uri, "staleOk, background update")
130         delete data._etag
131         delete data._lastModified
132         process.nextTick(
133           cb.bind(null, null, data, JSON.stringify(data), { statusCode : 304 } )
134         )
135         cb = function () {}
136       }
137     }
138   }
139
140   var options = {
141     etag         : etag,
142     lastModified : lastModified,
143     follow       : params.follow,
144     auth         : params.auth
145   }
146   this.request(uri, options, function (er, remoteData, raw, response) {
147     // if we get an error talking to the registry, but we have it
148     // from the cache, then just pretend we got it.
149     if (er && cachePath && data && !data.error) {
150       er = null
151       response = { statusCode: 304 }
152     }
153
154     if (response) {
155       log.silly("get", "cb", [response.statusCode, response.headers])
156       if (response.statusCode === 304 && (etag || lastModified)) {
157         remoteData = data
158         log.verbose(etag ? "etag" : "lastModified", uri+" from cache")
159       }
160     }
161
162     data = remoteData
163     if (!data) er = er || new Error("failed to fetch from registry: " + uri)
164
165     if (er) return cb(er, data, raw, response)
166
167     saveToCache(cachePath, data, saved)
168
169     // just give the write the old college try.  if it fails, whatever.
170     function saved () {
171       delete data._etag
172       delete data._lastModified
173       cb(er, data, raw, response)
174     }
175
176     function saveToCache (cachePath, data, saved) {
177       log.verbose("get", "saving", data.name, "to", cachePath)
178       getCacheStat(function (er, st) {
179         mkdirp(path.dirname(cachePath), function (er, made) {
180           if (er) return saved()
181
182           writeFile(cachePath, JSON.stringify(data), function (er) {
183             if (er) return saved()
184
185             chownr(made || cachePath, st.uid, st.gid, saved)
186           })
187         })
188       })
189     }
190   })
191 }
192
193 function adaptConfig (config) {
194   return {
195     proxy : {
196       http         : config.get("proxy"),
197       https        : config.get("https-proxy"),
198       localAddress : config.get("local-address")
199     },
200     ssl : {
201       certificate : config.get("cert"),
202       key         : config.get("key"),
203       ca          : config.get("ca"),
204       strict      : config.get("strict-ssl")
205     },
206     retry : {
207       retries    : config.get("fetch-retries"),
208       factor     : config.get("fetch-retry-factor"),
209       minTimeout : config.get("fetch-retry-mintimeout"),
210       maxTimeout : config.get("fetch-retry-maxtimeout")
211     },
212     userAgent  : config.get("user-agent"),
213     log        : log,
214     defaultTag : config.get("tag"),
215     couchToken : config.get("_token"),
216     maxSockets : config.get('maxsockets')
217   }
218 }