diff options
Diffstat (limited to 'src/modules/requests.js')
-rw-r--r-- | src/modules/requests.js | 371 |
1 files changed, 196 insertions, 175 deletions
diff --git a/src/modules/requests.js b/src/modules/requests.js index a67bc26..bc113bb 100644 --- a/src/modules/requests.js +++ b/src/modules/requests.js @@ -1,196 +1,217 @@ -const { app } = require("electron"); -const path = require("path"); const fs = require("fs"); -const { https, http } = require("follow-redirects"); -const lang = require("../lang"); +const path = require("path"); +const app = require("electron").app; +const https = require("follow-redirects").https; const json = require("./json"); +const version = require("./version"); + +var cache_dir = app.getPath("userData"); +var cache_file = path.join(cache_dir, "cached-requests.json"); -// all requests results are stored in this file -const cachePath = path.join(app.getPath("cache"), "viper-requests.json"); -const NORTHSTAR_LATEST_RELEASE_KEY = "nsLatestRelease"; -const NORTHSTAR_RELEASE_NOTES_KEY = "nsReleaseNotes"; -const VIPER_RELEASE_NOTES_KEY = "vpReleaseNotes"; +// updates `cache_dir` and `cache_file` +function set_paths() { + cache_dir = app.getPath("userData"); + cache_file = path.join(cache_dir, "cached-requests.json"); +} + +let requests = { + cache: {} +} -const user_agent = "viper/" + json(path.join(__dirname, "../../package.json")).version; +// verifies and ensures `cache_dir` exists +function ensure_dir() { + set_paths(); -function _saveCache(data) { - fs.writeFileSync(cachePath, JSON.stringify(data)); + // does the folder exist? + let exists = fs.existsSync(cache_dir); + + // shorthand for creating folder + let mkdir = () => {fs.mkdirSync(cache_dir)}; + + // if folder doesn't exist at all, create it + if (! exists) { + mkdir(); + return; + } + + // if it does exist, but somehow is a file, remove it, then recreate + // it as an actual folder, wait how did this even happen? + if (exists && fs.statSync(cache_dir).isFile()) { + fs.rmSync(cache_dir); + mkdir(); + } } -function _getRequestsCache() { - if (fs.existsSync(cachePath)) { - return JSON.parse(fs.readFileSync(cachePath, "utf8")); - } else { - fs.writeFileSync(cachePath, "{}"); - return {}; - } +// check `cache_file` and optionally check for the existence of +// `cache_key`, and if it exists, return it as is +let check_file = (cache_key) => { + // if `cache_file` doesn't exist, or isn't even a file, somehow, + // simply return `false`, and if it wasn't a file, we'll also remove + // the non-file item. + if (! fs.existsSync(cache_file) + || ! fs.statSync(cache_file).isFile()) { + + if (fs.existsSync(cache_file)) { + fs.rmSync(cache_file, {recursive: true}); + } + + return false; + } + + // attempt to read and parse `cache_file` as JSON + let file = json(cache_file); + + // if parsing failed, remove file, and return `false` + if (! file) { + fs.rmSync(cache_file); + return false; + } + + if (! cache_key) { + return file; + } + + // if `cache_key` isn't found, return `false` + if (! file[cache_key]) { + return false; + } + + return file[cache_key]; } -function delete_cache() { - if (fs.existsSync(cachePath)) { - return fs.rmSync(cachePath); +// attempts to get a `cache_key`'s value, unless it's been set more than +// `max_time_min` ago, set it to a falsy value to disable +requests.cache.get = (cache_key, max_time_min = 5) => { + ensure_dir(); + + let key = check_file(cache_key); + + // something went wrong with the config file or the key doesn't + // exist, return `false` + if (! key) { + return false; } + + // if the key is missing `.data` or `.time`, return `false` + if (! key.data || ! key.time) { + return false; + } + + // convert from minutes to milliseconds + max_time_min = max_time_min * 1000 * 60; + + let now = new Date().getTime(); + + // check if `key.time` is more than `max_time_min` since it got set + if (now - key.time > max_time_min && max_time_min) { + return false; + } + + return key.data; } -// Returns latest Northstar version available from GitHub releases. If -// there's no cache result for this request, or if cache exists but is -// old, refreshes cache with new data. -async function getLatestNsVersion() { - return new Promise((resolve, reject) => { - let cache = _getRequestsCache(); - - if (cache[NORTHSTAR_LATEST_RELEASE_KEY] && (Date.now() - cache[NORTHSTAR_LATEST_RELEASE_KEY]["time"]) < 5 * 60 * 1000) { - resolve( cache[NORTHSTAR_LATEST_RELEASE_KEY]["body"]["tag_name"] ); - } else { - https.get({ - host: "api.github.com", - port: 443, - path: "/repos/R2Northstar/Northstar/releases/latest", - method: "GET", - headers: { "User-Agent": user_agent } - }, - - response => { - response.setEncoding("utf8"); - let responseData = ""; - - response.on("data", data => { - responseData += data; - }); - - response.on("end", _ => { - cache[NORTHSTAR_LATEST_RELEASE_KEY] = { - "time": Date.now(), - "body": JSON.parse(responseData) - }; - _saveCache(cache); - resolve( cache[NORTHSTAR_LATEST_RELEASE_KEY]["body"]["tag_name"] ); - }); - }) - - .on('error', () => { - console.error('Failed to get latest Northstar version.'); - resolve( false ); - }); - } - }); +// attempt to delete `cache_key` from `cache_file` +requests.cache.delete = (cache_key) => { + ensure_dir(); + let file = check_file(); + + // if something went wrong when checking the `cache_file`, simply + // set the file to an empty Object + if (! file) { + file = {}; + } + + delete file[cache_key]; + fs.writeFileSync(cache_file, JSON.stringify(file)); } -// Returns the download link to latest Northstar version. Should always -// be called after getLatestNsVersion, as it refreshes cache data (if -// needed). -function getLatestNsVersionLink() { - const cache = _getRequestsCache(); - return cache[NORTHSTAR_LATEST_RELEASE_KEY]["body"].assets[0].browser_download_url; +// deletes all cached keys +requests.cache.delete.all = () => { + // if the file already exists, and actually is a file, we will + // simply empty it by writing an empty Object to it + if (fs.existsSync(cache_file) + && fs.statSync(cache_file).isFile()) { + + fs.writeFileSync(cache_file, "{}"); + } else if (fs.existsSync(cache_file)) { + // if `cache_file` does exist, but its not a file, we'll delete + // it completely + fs.rmSync(cache_file, {recursive: true}); + } } -// Returns and caches the Northstar release notes -async function getNsReleaseNotes() { - return new Promise(resolve => { - let cache = _getRequestsCache(); - - if (cache[NORTHSTAR_RELEASE_NOTES_KEY] && (Date.now() - cache[NORTHSTAR_RELEASE_NOTES_KEY]["time"]) < 5 * 60 * 1000) { - resolve( cache[NORTHSTAR_RELEASE_NOTES_KEY]["body"] ); - } else { - https.get({ - host: "api.github.com", - port: 443, - path: "/repos/R2Northstar/Northstar/releases", - method: "GET", - headers: { "User-Agent": user_agent } - }, - - response => { - response.setEncoding("utf8"); - let responseData = ""; - - response.on("data", data => { - responseData += data; - }); - - response.on("end", _ => { - cache[NORTHSTAR_RELEASE_NOTES_KEY] = { - "time": Date.now(), - "body": JSON.parse(responseData) - }; - _saveCache(cache); - resolve( cache[NORTHSTAR_RELEASE_NOTES_KEY]["body"] ); - }); - }) - - // When GitHub cannot be reached (when user doesn't have Internet - // access for instance), we return latest cache content even if - // it's not up-to-date, or display an error message if cache - // is empty. - .on('error', () => { - if ( cache[NORTHSTAR_RELEASE_NOTES_KEY] ) { - console.warn("Couldn't fetch Northstar release notes, returning data from cache."); - resolve( cache[NORTHSTAR_RELEASE_NOTES_KEY]["body"] ); - } else { - console.error("Couldn't fetch Northstar release notes, cache is empty."); - resolve( [lang("request.no_ns_release_notes")] ); - } - }); - } - }); +// sets `cache_key` to `data` and updates its timestamp +requests.cache.set = (cache_key, data) => { + ensure_dir(); + let file = check_file(); + + // if something went wrong when checking the `cache_file`, simply + // set the file to an empty Object + if (! file) { + file = {}; + } + + file[cache_key] = { + data: data, + time: new Date().getTime() + } + + fs.writeFileSync(cache_file, JSON.stringify(file)); } -// Returns and caches the Viper release notes -async function getVpReleaseNotes() { - return new Promise(resolve => { - let cache = _getRequestsCache(); - - if (cache[VIPER_RELEASE_NOTES_KEY] && (Date.now() - cache[VIPER_RELEASE_NOTES_KEY]["time"]) < 5 * 60 * 1000) { - resolve( cache[VIPER_RELEASE_NOTES_KEY]["body"] ); - } else { - https.get({ - host: "api.github.com", - port: 443, - path: "/repos/0negal/viper/releases", - method: "GET", - headers: { "User-Agent": user_agent } - }, - - response => { - response.setEncoding("utf8"); - let responseData = ""; - - response.on("data", data => { - responseData += data; - }); - - response.on("end", _ => { - cache[VIPER_RELEASE_NOTES_KEY] = { - "time": Date.now(), - "body": JSON.parse(responseData) - }; - _saveCache(cache); - resolve( cache[VIPER_RELEASE_NOTES_KEY]["body"] ); - }); - }) - - // When GitHub cannot be reached (when user doesn't have Internet - // access for instance), we return latest cache content even if - // it's not up-to-date, or display an error message if cache - // is empty. - .on('error', () => { - if ( cache[VIPER_RELEASE_NOTES_KEY] ) { - console.warn("Couldn't fetch Viper release notes, returning data from cache."); - resolve( cache[VIPER_RELEASE_NOTES_KEY]["body"] ); - } else { - console.error("Couldn't fetch Viper release notes, cache is empty."); - resolve( [lang("request.no_vp_release_notes")] ); - } - }); - } - }); +// attempts to `GET` `https://<host>/<path>`, and then returns the +// result or if it fails it'll reject with `false` +// +// if `cache_key` is set, we'll first attempt to check if any valid +// cache with that key exists, and then return it directly if its still +// valid cache. +requests.get = (host, path, cache_key, max_time_min) => { + let cached = requests.cache.get(cache_key, max_time_min); + if (cached) { + return cached; + } + + // we'll use this as the `User-Agent` header for the request + let user_agent = "viper/" + version.viper(); + + return new Promise((resolve, reject) => { + // start `GET` request + https.get({ + host: host, + port: 443, + path: path, + method: "GET", + headers: { "User-Agent": user_agent } + }, + + // on data response + response => { + // set correct encoding + response.setEncoding("utf8"); + + // this'll be filled with incoming data + let res_data = ""; + + // data has arrived, add it on `res_data` + response.on("data", data => { + res_data += data; + }) + + // request is done, return result + response.on("end", _ => { + resolve(res_data); + if (cache_key) { + requests.cache.set(cache_key, res_data); + } + }) + }) + + // an error occured, simply `reject()` + .on("error", () => { + reject(false); + }) + }) } -module.exports = { - delete_cache, - getLatestNsVersion, - getLatestNsVersionLink, - getNsReleaseNotes, - getVpReleaseNotes -}; +module.exports = requests; |