Skip to content

Commit

Permalink
Implemented package installation from URL (#28)
Browse files Browse the repository at this point in the history
This also adds in manifest generation
  • Loading branch information
andersevenrud committed Apr 11, 2020
1 parent d6b745e commit 8eb10b8
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 5 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"homepage": "https://github.com/os-js/osjs-server#readme",
"dependencies": {
"@osjs/common": "^3.0.8",
"bent": "^7.1.2",
"body-parser": "^1.19.0",
"chokidar": "^3.3.1",
"connect-loki": "^1.1.0",
Expand All @@ -53,6 +54,7 @@
"morgan": "^1.9.1",
"nocache": "^2.1.0",
"sanitize-filename": "^1.6.3",
"tar": "^6.0.1",
"uuid": "^3.4.0"
},
"devDependencies": {
Expand Down
44 changes: 41 additions & 3 deletions src/packages.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ const fs = require('fs-extra');
const fg = require('fast-glob');
const path = require('path');
const consola = require('consola');
const bent = require('bent');
const tar = require('tar');
const Package = require('./package.js');
const {getPrefix} = require('./utils/vfs.js');
const logger = consola.withTag('Packages');
Expand All @@ -42,10 +44,17 @@ const readOrDefault = filename => fs.existsSync(filename)
? fs.readJsonSync(filename)
: [];

const extract = (stream, target) => new Promise((resolve, reject) => {
stream.once('end', () => resolve());
stream.once('error', error => reject(error));
stream.pipe(tar.extract({C: target}));
});

/**
* @typedef InstallPackageOptions
* @param {string} root
* @param {boolean} system
* @param {object} [auth]
* @param {object} [headers]
*/

/**
Expand Down Expand Up @@ -144,9 +153,38 @@ class Packages {
* Installs a package from given url
* @param {string} url
* @param {InstallPackageOptions} options
* @param {object} user
*/
async installPackage(url, options) {
throw new Error('Not implemented yet');
async installPackage(url, options, user) {
const {realpath} = this.core.make('osjs/vfs');

const name = path.basename(url.split('?')[0])
.replace(/\.[^/.]+$/, '');

const stream = await bent()(url, null, {
headers: options.headers || {}
});

const userRoot = options.root || 'home:/.packages'; // FIXME: Client-side
const target = await realpath(`${userRoot}/${name}`, user);
const root = await realpath(userRoot, user);
const manifest = await realpath(`${userRoot}/metadata.json`, user);

if (await fs.exists(target)) {
throw new Error('Target already exists');
}

if (options.system) {
throw new Error('System packages not yet implemented');
}

await fs.mkdir(target);
await extract(stream, target);

const filenames = await fg(root + '/*/metadata.json');
const metadatas = await Promise.all(filenames.map(f => fs.readJson(f)));

await fs.writeJson(manifest, metadatas);
}

/**
Expand Down
7 changes: 5 additions & 2 deletions src/providers/packages.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,12 @@ class PackageServiceProvider extends ServiceProvider {
});

routeAuthenticated('POST', '/api/packages/install', (req, res) => {
this.packages.installPackage(req.body.url, req.body.options)
this.packages.installPackage(req.body.url, req.body.options, req.session.user)
.then(() => res.json({success: true}))
.catch(error => res.status(400).json({error}));
.catch((error) => {
console.error(error);
res.status(400).json({error: 'Package installation failed'});
});
});

return this.packages.init();
Expand Down

0 comments on commit 8eb10b8

Please sign in to comment.