@@ -36,6 +36,22 @@ const createUrl = (basePath, folder, metadata, filename) =>
36
36
? filename
37
37
: `${ basePath } ${ folder } /${ metadata . name } /${ filename } ` ;
38
38
39
+ const mapPreloads = ( core , metadata , preloads ) => {
40
+ const { url} = core . make ( 'osjs/vfs' ) ;
41
+
42
+ if ( metadata . _vfsRoot ) {
43
+ // FIXME: We might wanna do this on actual metadata creation instead
44
+ const promises = preloads . map ( iter => {
45
+ return url ( `${ metadata . _vfsRoot } /${ iter } ` ) ;
46
+ } ) ;
47
+
48
+ return Promise . all ( promises )
49
+ . then ( results => [ ] . concat ( ...results ) ) ;
50
+ }
51
+
52
+ return Promise . resolve ( preloads ) ;
53
+ } ;
54
+
39
55
/**
40
56
* A registered package reference
41
57
* @property {Object } metadata Package metadata
@@ -59,13 +75,6 @@ const createUrl = (basePath, folder, metadata, filename) =>
59
75
* @typedef PackageMetadata
60
76
*/
61
77
62
- /*
63
- * Fetch package manifest
64
- */
65
- const fetchManifest = core =>
66
- fetch ( core . url ( '/metadata.json' ) )
67
- . then ( response => response . json ( ) ) ;
68
-
69
78
/**
70
79
* Package Manager
71
80
*
@@ -109,6 +118,9 @@ export default class Packages {
109
118
* @type {String[] }
110
119
*/
111
120
this . running = [ ] ;
121
+
122
+ this . _systemMetadata = [ ] ;
123
+ this . _userMetadata = [ ] ;
112
124
}
113
125
114
126
/**
@@ -117,6 +129,8 @@ export default class Packages {
117
129
destroy ( ) {
118
130
this . packages = [ ] ;
119
131
this . metadata = [ ] ;
132
+ this . _systemMetadata = [ ] ;
133
+ this . _userMetadata = [ ] ;
120
134
}
121
135
122
136
/**
@@ -131,10 +145,75 @@ export default class Packages {
131
145
. forEach ( pkg => this . launch ( pkg . name ) ) ;
132
146
} ) ;
133
147
134
- return fetchManifest ( this . core )
135
- . then ( metadata => {
136
- this . metadata = metadata . map ( iter => Object . assign ( { type : 'application' } , iter ) ) ;
137
- } ) ;
148
+ return Promise . resolve ( true ) ;
149
+ }
150
+
151
+ /**
152
+ * Loads user and system packages
153
+ * @return {Promise<undefined, Error> }
154
+ */
155
+ loadPackages ( ) {
156
+ const err = e => console . warn ( e ) ;
157
+
158
+ return Promise . all ( [
159
+ this . loadSystemPackages ( ) . catch ( err ) ,
160
+ this . loadUserPackages ( ) . catch ( err )
161
+ ] ) ;
162
+ }
163
+
164
+ /**
165
+ * Loads system installed packages
166
+ * @return {Promise<undefined, Error> }
167
+ */
168
+ loadSystemPackages ( ) {
169
+ const fetchSystemManifest = ( ) =>
170
+ fetch ( this . core . url ( '/metadata.json' ) )
171
+ . then ( response => response . json ( ) ) ;
172
+
173
+ return fetchSystemManifest ( )
174
+ . then ( json => this . _setPackages ( json , 'system' ) ) ;
175
+ }
176
+
177
+ /**
178
+ * Loads user installed packages
179
+ * @return {Promise<undefined, Error> }
180
+ */
181
+ loadUserPackages ( ) {
182
+ const { readfile} = this . core . make ( 'osjs/vfs' ) ;
183
+ const { root} = this . core . config ( 'packages.local' ) ;
184
+ const localManifest = `${ root } /metadata.json` ;
185
+
186
+ const parseLocal = str => typeof str === 'string' && str
187
+ ? JSON . parse ( str )
188
+ : [ ] ;
189
+
190
+ const fetchLocalManifest = ( ) =>
191
+ readfile ( { path : localManifest } )
192
+ . then ( parseLocal ) ;
193
+
194
+ const compability = json => json . map ( iter => Object . assign ( {
195
+ _vfsRoot : `${ root } /${ iter . name } `
196
+ } , iter ) ) ;
197
+
198
+ return fetchLocalManifest ( )
199
+ . then ( compability )
200
+ . then ( json => this . _setPackages ( json , 'user' ) ) ;
201
+ }
202
+
203
+ /**
204
+ * Internal method for populating the installed packages metadata list
205
+ * @param {Object[] } list List of metadatas
206
+ * @param {string } scope Package scope
207
+ */
208
+ _setPackages ( list , scope ) {
209
+ this [ `_${ scope } Metadata` ] = list ;
210
+
211
+ const map = iter => Object . assign ( { type : 'application' } , iter ) ;
212
+
213
+ this . metadata = [
214
+ ...this . _systemMetadata ,
215
+ ...this . _userMetadata
216
+ ] . map ( map ) ;
138
217
}
139
218
140
219
/**
@@ -202,7 +281,7 @@ export default class Packages {
202
281
}
203
282
204
283
if ( [ 'theme' , 'icons' , 'sounds' ] . indexOf ( metadata . type ) !== - 1 ) {
205
- return this . _launchTheme ( name , metadata . type ) ;
284
+ return this . _launchTheme ( name , metadata . type , options ) ;
206
285
}
207
286
208
287
if ( metadata . singleton ) {
@@ -246,10 +325,12 @@ export default class Packages {
246
325
*
247
326
* @param {String } name Package name
248
327
* @param {String } type Package type
328
+ * @param {Object } [options] Launch options
329
+ * @param {Boolean } [options.forcePreload=false] Force preload reloading
249
330
* @throws {Error }
250
331
* @return {Promise<Object, Error> }
251
332
*/
252
- _launchTheme ( name , type ) {
333
+ _launchTheme ( name , type , options = { } ) {
253
334
const _ = this . core . make ( 'osjs/locale' ) . translate ;
254
335
const folder = type === 'icons' ? 'icons' : 'themes' ;
255
336
const basePath = this . core . config ( 'public' ) ;
@@ -265,13 +346,16 @@ export default class Packages {
265
346
const preloads = ( metadata . files || [ ] )
266
347
. map ( f => this . core . url ( createUrl ( basePath , folder , metadata , f ) ) ) ;
267
348
268
- return this . preload ( preloads )
269
- . then ( result => {
270
- return Object . assign (
271
- { elements : { } } ,
272
- result ,
273
- this . packages . find ( pkg => pkg . metadata . name === name ) || { }
274
- ) ;
349
+ return mapPreloads ( this . core , metadata , preloads )
350
+ . then ( preloads => {
351
+ return this . preload ( preloads , options . forcePreload === true )
352
+ . then ( result => {
353
+ return Object . assign (
354
+ { elements : { } } ,
355
+ result ,
356
+ this . packages . find ( pkg => pkg . metadata . name === name ) || { }
357
+ ) ;
358
+ } ) ;
275
359
} ) ;
276
360
}
277
361
@@ -340,18 +424,21 @@ export default class Packages {
340
424
return app ;
341
425
} ;
342
426
343
- return this . preload ( preloads , options . forcePreload === true )
344
- . then ( ( { errors} ) => {
345
- if ( errors . length ) {
346
- fail ( _ ( 'ERR_PACKAGE_LOAD' , name , errors . join ( ', ' ) ) ) ;
347
- }
427
+ return mapPreloads ( this . core , metadata , preloads )
428
+ . then ( preloads => {
429
+ return this . preload ( preloads , options . forcePreload === true )
430
+ . then ( ( { errors} ) => {
431
+ if ( errors . length ) {
432
+ fail ( _ ( 'ERR_PACKAGE_LOAD' , name , errors . join ( ', ' ) ) ) ;
433
+ }
348
434
349
- const found = this . packages . find ( pkg => pkg . metadata . name === name ) ;
350
- if ( ! found ) {
351
- fail ( _ ( 'ERR_PACKAGE_NO_RUNTIME' , name ) ) ;
352
- }
435
+ const found = this . packages . find ( pkg => pkg . metadata . name === name ) ;
436
+ if ( ! found ) {
437
+ fail ( _ ( 'ERR_PACKAGE_NO_RUNTIME' , name ) ) ;
438
+ }
353
439
354
- return create ( found ) ;
440
+ return create ( found ) ;
441
+ } ) ;
355
442
} ) ;
356
443
}
357
444
@@ -382,6 +469,66 @@ export default class Packages {
382
469
} ) ;
383
470
}
384
471
472
+ /**
473
+ * Installs a package
474
+ * @param {Object } options
475
+ * @param {File|Blob|ArrayBuffer } [options.file]
476
+ * @param {boolean } [options.local=true]
477
+ */
478
+ install ( options ) {
479
+ // TODO: Progress Dialog
480
+ // TODO: Locales
481
+ // TODO: Better error handling
482
+
483
+ options = Object . assign ( {
484
+ file : null ,
485
+ local : true
486
+ } , options ) ;
487
+
488
+ const { mountpoints} = this . core . make ( 'osjs/fs' ) ;
489
+
490
+ const checkSupported = ( path ) => {
491
+ const [ name ] = path . split ( ':' ) ;
492
+ const found = mountpoints ( )
493
+ . find ( mount => mount . name === name ) ;
494
+
495
+ // FIXME: Should check for 'local' instead probably
496
+ return found && found . adapter === 'system' ;
497
+ } ;
498
+
499
+ const enabled = this . core . config ( 'packages.installation' ) ;
500
+ if ( ! enabled ) {
501
+ return Promise . reject ( new Error ( 'Package installation not enabled.' ) ) ;
502
+ }
503
+
504
+ if ( options . local ) {
505
+ const { root} = this . core . config ( 'packages.local' ) ;
506
+ if ( ! checkSupported ( root ) ) {
507
+ return Promise . reject ( new Error ( 'Cannot install local packages on a non-system VFS adapter' ) ) ;
508
+ }
509
+ }
510
+
511
+ const reloader = options . local
512
+ ? ( ) => this . loadUserPackages ( )
513
+ : ( ) => this . loadSystemPackages ( ) ;
514
+
515
+ return this . core
516
+ . request ( '/packages/install' , {
517
+ method : 'post' ,
518
+ body : options
519
+ } , 'json' )
520
+ . then ( result => {
521
+ if ( result . success ) {
522
+ return reloader ( )
523
+ . catch ( err => console . warn ( err ) ) ;
524
+ }
525
+
526
+ console . error ( result . errors ) ;
527
+
528
+ return Promise . reject ( new Error ( 'Package installaction was unsuccessful' ) ) ;
529
+ } ) ;
530
+ }
531
+
385
532
/**
386
533
* Gets a list of packages (metadata)
387
534
* @param {Function } [filter] A filter function
0 commit comments