diff --git a/packages/hydrooj/src/commands/install.ts b/packages/hydrooj/src/commands/install.ts index 39afa984..7f0a7618 100644 --- a/packages/hydrooj/src/commands/install.ts +++ b/packages/hydrooj/src/commands/install.ts @@ -1,11 +1,12 @@ import child from 'child_process'; import os from 'os'; import path from 'path'; +import AdmZip from 'adm-zip'; import { CAC } from 'cac'; import fs from 'fs-extra'; import superagent from 'superagent'; import tar from 'tar'; -import { Logger } from '@hydrooj/utils'; +import { Logger, streamToBuffer } from '@hydrooj/utils'; const logger = new Logger('install'); let yarnVersion = 0; @@ -19,6 +20,27 @@ try { const hydroPath = path.resolve(os.homedir(), '.hydro'); const addonDir = path.join(hydroPath, 'addons'); +function downloadAndExtractTgz(url: string, dest: string) { + return new Promise((resolve, reject) => { + superagent.get(url) + .pipe(tar.x({ + C: dest, + strip: 1, + })) + .on('finish', resolve) + .on('error', reject); + }); +} +async function downloadAndExtractZip(url: string, dest: string) { + const res = await streamToBuffer(await superagent.get(url).responseType('blob')); + new AdmZip(res).extractAllTo(dest, true); +} +const types = { + '.tgz': downloadAndExtractTgz, + '.tar.gz': downloadAndExtractTgz, + '.zip': downloadAndExtractZip, +}; + export function register(cli: CAC) { cli.command('install [package]').action(async (_src) => { if (!_src) { @@ -44,20 +66,13 @@ export function register(cli: CAC) { if (src.startsWith('http')) { const url = new URL(src); const filename = url.pathname.split('/').pop()!; - if (['.tar.gz', '.tgz', '.zip'].find((i) => filename.endsWith(i))) { + if (Object.keys(types).find((i) => filename.endsWith(i))) { const name = filename.replace(/(-?(\d+\.\d+\.\d+|latest))?(\.tar\.gz|\.zip|\.tgz)$/g, ''); newAddonPath = path.join(addonDir, name); logger.info(`Downloading ${src} to ${newAddonPath}`); fs.ensureDirSync(newAddonPath); - await new Promise((resolve, reject) => { - superagent.get(src) - .pipe(tar.x({ - C: newAddonPath, - strip: 1, - })) - .on('finish', resolve) - .on('error', reject); - }); + const func = types[Object.keys(types).find((i) => filename.endsWith(i))]!; + await func(src, newAddonPath); } else throw new Error('Unsupported file type'); } else throw new Error(`Unsupported install source: ${src}`); if (!newAddonPath) throw new Error('Addon download failed');