|
|
@ -3,66 +3,77 @@ const NodeCache = require('node-cache'); |
|
|
|
const querystring = require('querystring'); |
|
|
|
const pkg = require('../package.json'); |
|
|
|
|
|
|
|
const cache = new NodeCache(); |
|
|
|
class Onionoo { |
|
|
|
|
|
|
|
const baseUrl = 'https://onionoo.torproject.org'; |
|
|
|
const endpoints = [ |
|
|
|
'summary', |
|
|
|
'details', |
|
|
|
'bandwidth', |
|
|
|
'weights', |
|
|
|
'clients', |
|
|
|
'uptime' |
|
|
|
]; |
|
|
|
// Constructor returns a new object so instance properties are private
|
|
|
|
constructor(options = {}) { |
|
|
|
|
|
|
|
// Returns cache max age from response headers
|
|
|
|
function checkResponseMaxAge(response) { |
|
|
|
const cacheControl = response.headers['cache-control']; |
|
|
|
const maxAgeRegex = /max-age=(\d+)/; |
|
|
|
const maxAge = cacheControl && cacheControl.match(maxAgeRegex); |
|
|
|
return maxAge && maxAge[1]; |
|
|
|
} |
|
|
|
// Set default options
|
|
|
|
this.options = Object.assign({}, { |
|
|
|
cache: new NodeCache(), |
|
|
|
baseUrl: 'https://onionoo.torproject.org', |
|
|
|
endpoints: [ |
|
|
|
'summary', |
|
|
|
'details', |
|
|
|
'bandwidth', |
|
|
|
'weights', |
|
|
|
'clients', |
|
|
|
'uptime' |
|
|
|
] |
|
|
|
}, options); |
|
|
|
|
|
|
|
// Returns a function to make requests to a given endpoint
|
|
|
|
function createEndpointMethod(endpoint) { |
|
|
|
return args => new Promise((resolve, reject) => { |
|
|
|
// Return object containing endpoint methods
|
|
|
|
return this.options.endpoints.reduce((onionoo, endpoint) => { |
|
|
|
onionoo[endpoint] = this.createEndpointMethod(endpoint); |
|
|
|
|
|
|
|
// Build query string (don't encode ':' for search filters)
|
|
|
|
const qs = querystring.encode(args).replace(/%3A/g, ':'); |
|
|
|
return onionoo; |
|
|
|
}, {}); |
|
|
|
} |
|
|
|
|
|
|
|
// Build url
|
|
|
|
const url = `${baseUrl}/${endpoint}?${qs}`; |
|
|
|
// Returns cache max age from response headers
|
|
|
|
checkResponseMaxAge(response) { |
|
|
|
const cacheControl = response.headers['cache-control']; |
|
|
|
const maxAgeRegex = /max-age=(\d+)/; |
|
|
|
const maxAge = cacheControl && cacheControl.match(maxAgeRegex); |
|
|
|
return maxAge && maxAge[1]; |
|
|
|
} |
|
|
|
|
|
|
|
// Check for url in cache
|
|
|
|
const cachedResult = cache.get(url); |
|
|
|
if(cachedResult) { |
|
|
|
resolve(cachedResult); |
|
|
|
} else { |
|
|
|
// Returns a function to make requests to a given endpoint
|
|
|
|
createEndpointMethod(endpoint) { |
|
|
|
return args => new Promise((resolve, reject) => { |
|
|
|
|
|
|
|
// Make request
|
|
|
|
const options = { |
|
|
|
json: true, |
|
|
|
'user-agent': `onionoo-node-client v${pkg.version} (${pkg.homepage})` |
|
|
|
}; |
|
|
|
resolve(got(url, options) |
|
|
|
.then(response => { |
|
|
|
// Build query string (don't encode ':' for search filters)
|
|
|
|
const qs = querystring.encode(args).replace(/%3A/g, ':'); |
|
|
|
|
|
|
|
// Cache response
|
|
|
|
const ttl = checkResponseMaxAge(response); |
|
|
|
if(ttl) { |
|
|
|
cache.set(url, response.body, ttl); |
|
|
|
} |
|
|
|
// Build url
|
|
|
|
const url = `${this.options.baseUrl}/${endpoint}?${qs}`; |
|
|
|
|
|
|
|
// Resolve response
|
|
|
|
return response.body; |
|
|
|
})); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
// Check for url in cache
|
|
|
|
const cachedResult = this.options.cache.get(url); |
|
|
|
if(cachedResult) { |
|
|
|
resolve(cachedResult); |
|
|
|
} else { |
|
|
|
|
|
|
|
// Make request
|
|
|
|
const options = { |
|
|
|
json: true, |
|
|
|
'user-agent': `onionoo-node-client v${pkg.version} (${pkg.homepage})` |
|
|
|
}; |
|
|
|
resolve(got(url, options) |
|
|
|
.then(response => { |
|
|
|
|
|
|
|
// Return object containing endpoint methods
|
|
|
|
module.exports = endpoints.reduce((onionoo, endpoint) => { |
|
|
|
onionoo[endpoint] = createEndpointMethod(endpoint); |
|
|
|
// Cache response
|
|
|
|
const ttl = this.checkResponseMaxAge(response); |
|
|
|
if(ttl) { |
|
|
|
this.options.cache.set(url, response.body, ttl); |
|
|
|
} |
|
|
|
|
|
|
|
// Resolve response
|
|
|
|
return response.body; |
|
|
|
})); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return onionoo; |
|
|
|
}, {}); |
|
|
|
module.exports = Onionoo; |
|
|
|