From 6a282f712b2e7adb4699a0a8ead2e1a5122a995e Mon Sep 17 00:00:00 2001 From: simon3000 Date: Tue, 31 Mar 2020 13:01:55 +0200 Subject: [PATCH] local cache --- api/latest.js | 72 +++++++++++++++++++++++++++++++++++++++++++++++--- cache/.gitkeep | 0 2 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 cache/.gitkeep diff --git a/api/latest.js b/api/latest.js index 240a81b..4a29a7b 100644 --- a/api/latest.js +++ b/api/latest.js @@ -1,6 +1,9 @@ const Router = require('koa-router') const got = require('got') const yaml = require('js-yaml') +const { promises: { stat, writeFile, unlink }, createReadStream, createWriteStream } = require('fs') +const { join } = require('path') +const { createHash } = require('crypto') const { getLatestURL, relays } = require('./shared') @@ -14,6 +17,66 @@ const fileMap = { windows: 'latest.yml' } +const cachingMap = new Map() + +const calculateHash = path => new Promise(resolve => { + const hash = createHash('sha512') + const stream = createReadStream(path) + stream.on('readable', () => { + const data = stream.read() + if (data) { + hash.update(data) + } else { + resolve(hash.digest()) + } + }) +}) + +const checkCache = async (url, sha512) => { + console.log('check cache', url) + const fileName = url.split('/').reverse()[0] + const cachePath = join('./cache', fileName) + const hash = Buffer.from(sha512, 'base64') + const cacheHash = await calculateHash(cachePath) + if (!hash.equals(cacheHash)) { + console.log('remake cache', url) + await unlink(cachePath) + return makeCache(url, sha512) + } +} + +const makeCache = async (url, sha512) => { + console.log('make cache', url) + const fileName = url.split('/').reverse()[0] + const cachePath = join('./cache', fileName) + await writeFile(cachePath, '') + cachingMap.set(url, new Promise(resolve => { + const writeStream = createWriteStream(cachePath, { emitClose: true }) + got.stream(url).pipe(writeStream) + writeStream.on('close', async () => { + await checkCache(url, sha512) + resolve() + }) + })) + return cachingMap.get(url) +} + +const getCache = async (url, sha512) => { + const fileName = url.split('/').reverse()[0] + const cachePath = join('./cache', fileName) + const cacheExist = await stat(cachePath).catch(() => false) + if (!cacheExist) { + await makeCache(url, sha512) + } + if (cachingMap.has(url)) { + await cachingMap.get(url) + } else { + cachingMap.set(url, checkCache(url, sha512)) + await cachingMap.get(url) + } + return createReadStream(cachePath) +} + latest.get('/:name/:platform', async ctx => { const { name, platform } = ctx.params const match = relays[name] @@ -22,12 +85,13 @@ latest.get('/:name/:platform', async ctx => { const ymlUrl = await getLatestURL({ file: ymlFile, ...match }) const yml = await got(ymlUrl).text() const { files } = yaml.safeLoad(yml) - const file = files - .map(({ url }) => url) - .find(url => ['exe', 'dmg', 'AppImage'].find(ext => url.endsWith(ext))) + const { url: file, sha512 } = files + .find(({ url }) => ['exe', 'dmg', 'AppImage'].find(ext => url.endsWith(ext))) || {} if (file) { const url = await getLatestURL({ file, ...match }) - ctx.body = got.stream(url) + const fileName = url.split('/').reverse()[0] + ctx.response.attachment(fileName) + ctx.body = await getCache(url, sha512) } } }) diff --git a/cache/.gitkeep b/cache/.gitkeep new file mode 100644 index 0000000..e69de29