Skip to content

Commit 8eb10b8

Browse files
committed
Implemented package installation from URL (#28)
This also adds in manifest generation
1 parent d6b745e commit 8eb10b8

File tree

3 files changed

+48
-5
lines changed

3 files changed

+48
-5
lines changed

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"homepage": "https://github.com/os-js/osjs-server#readme",
3636
"dependencies": {
3737
"@osjs/common": "^3.0.8",
38+
"bent": "^7.1.2",
3839
"body-parser": "^1.19.0",
3940
"chokidar": "^3.3.1",
4041
"connect-loki": "^1.1.0",
@@ -53,6 +54,7 @@
5354
"morgan": "^1.9.1",
5455
"nocache": "^2.1.0",
5556
"sanitize-filename": "^1.6.3",
57+
"tar": "^6.0.1",
5658
"uuid": "^3.4.0"
5759
},
5860
"devDependencies": {

src/packages.js

+41-3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ const fs = require('fs-extra');
3232
const fg = require('fast-glob');
3333
const path = require('path');
3434
const consola = require('consola');
35+
const bent = require('bent');
36+
const tar = require('tar');
3537
const Package = require('./package.js');
3638
const {getPrefix} = require('./utils/vfs.js');
3739
const logger = consola.withTag('Packages');
@@ -42,10 +44,17 @@ const readOrDefault = filename => fs.existsSync(filename)
4244
? fs.readJsonSync(filename)
4345
: [];
4446

47+
const extract = (stream, target) => new Promise((resolve, reject) => {
48+
stream.once('end', () => resolve());
49+
stream.once('error', error => reject(error));
50+
stream.pipe(tar.extract({C: target}));
51+
});
52+
4553
/**
4654
* @typedef InstallPackageOptions
55+
* @param {string} root
4756
* @param {boolean} system
48-
* @param {object} [auth]
57+
* @param {object} [headers]
4958
*/
5059

5160
/**
@@ -144,9 +153,38 @@ class Packages {
144153
* Installs a package from given url
145154
* @param {string} url
146155
* @param {InstallPackageOptions} options
156+
* @param {object} user
147157
*/
148-
async installPackage(url, options) {
149-
throw new Error('Not implemented yet');
158+
async installPackage(url, options, user) {
159+
const {realpath} = this.core.make('osjs/vfs');
160+
161+
const name = path.basename(url.split('?')[0])
162+
.replace(/\.[^/.]+$/, '');
163+
164+
const stream = await bent()(url, null, {
165+
headers: options.headers || {}
166+
});
167+
168+
const userRoot = options.root || 'home:/.packages'; // FIXME: Client-side
169+
const target = await realpath(`${userRoot}/${name}`, user);
170+
const root = await realpath(userRoot, user);
171+
const manifest = await realpath(`${userRoot}/metadata.json`, user);
172+
173+
if (await fs.exists(target)) {
174+
throw new Error('Target already exists');
175+
}
176+
177+
if (options.system) {
178+
throw new Error('System packages not yet implemented');
179+
}
180+
181+
await fs.mkdir(target);
182+
await extract(stream, target);
183+
184+
const filenames = await fg(root + '/*/metadata.json');
185+
const metadatas = await Promise.all(filenames.map(f => fs.readJson(f)));
186+
187+
await fs.writeJson(manifest, metadatas);
150188
}
151189

152190
/**

src/providers/packages.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,12 @@ class PackageServiceProvider extends ServiceProvider {
7979
});
8080

8181
routeAuthenticated('POST', '/api/packages/install', (req, res) => {
82-
this.packages.installPackage(req.body.url, req.body.options)
82+
this.packages.installPackage(req.body.url, req.body.options, req.session.user)
8383
.then(() => res.json({success: true}))
84-
.catch(error => res.status(400).json({error}));
84+
.catch((error) => {
85+
console.error(error);
86+
res.status(400).json({error: 'Package installation failed'});
87+
});
8588
});
8689

8790
return this.packages.init();

0 commit comments

Comments
 (0)