@ -1,19 +1,62 @@
'use strict'
'use strict'
var async = require ( 'async' )
var EventManager = require ( 'remix-lib' ) . EventManager
var EventManager = require ( 'remix-lib' ) . EventManager
var pathtool = require ( 'path' )
function buildList ( self , path = '' , callback ) {
path = '' + ( path || '' )
self . remixd . dir ( path , ( error , filesList ) => {
if ( error ) console . error ( error )
var list = Object . keys ( filesList )
var counter = list . length
var fileTree = { }
if ( ! counter ) callback ( null , fileTree )
for ( var i = 0 , name , len = counter ; i < len ; i ++ ) {
name = list [ i ]
if ( filesList [ name ] . isDirectory ) {
setFolder ( self , path , name , fileTree , finish )
} else {
setFileContent ( self , path , name , fileTree , finish )
}
}
function finish ( error ) {
if ( error ) console . error ( error )
counter --
if ( ! counter ) callback ( null , fileTree )
}
} )
}
function setFolder ( self , path , name , fileTree , done ) {
buildList ( self , name , ( error , subFileTree ) => {
if ( error ) console . error ( error )
name = name . replace ( path , '' )
if ( name [ 0 ] === '/' ) name = name . substring ( 1 )
fileTree [ name ] = subFileTree
done ( null )
} )
}
function setFileContent ( self , path , name , fileTree , done ) {
self . remixd . read ( name , ( error , result ) => {
if ( error ) console . error ( error )
name = name . replace ( path , '' )
if ( name [ 0 ] === '/' ) name = name . substring ( 1 )
fileTree [ name ] = {
'/content' : result . content ,
'/readonly' : result . readonly
}
done ( null )
} )
}
class SharedFolder {
module . exports = class SharedFolder {
constructor ( remixd ) {
constructor ( remixd ) {
this . event = new EventManager ( )
this . event = new EventManager ( )
this . remixd = remixd
this . _remixd = remixd
this . files = null
this . remixd = remixapi ( remixd , this )
this . filesContent = { }
this . filesTree = null
this . type = 'localhost'
this . type = 'localhost'
this . error = {
this . error = { 'EEXIST' : 'File already exists' }
'EEXIST' : 'File already exists'
this . _isReady = true
}
this . remixd . event . register ( 'notified' , ( data ) => {
remixd . event . register ( 'notified' , ( data ) => {
if ( data . scope === 'sharedfolder' ) {
if ( data . scope === 'sharedfolder' ) {
if ( data . name === 'created' ) {
if ( data . name === 'created' ) {
this . init ( ( ) => {
this . init ( ( ) => {
@ -24,7 +67,7 @@ class SharedFolder {
this . event . trigger ( 'fileRemoved' , [ this . type + '/' + data . value . path ] )
this . event . trigger ( 'fileRemoved' , [ this . type + '/' + data . value . path ] )
} )
} )
} else if ( data . name === 'changed' ) {
} else if ( data . name === 'changed' ) {
this . remixd . call ( 'sharedfolder' , 'get' , { path : data . value } , ( error , content ) => {
this . _ remixd. call ( 'sharedfolder' , 'get' , { path : data . value } , ( error , content ) => {
if ( error ) {
if ( error ) {
console . log ( error )
console . log ( error )
} else {
} else {
@ -38,38 +81,43 @@ class SharedFolder {
} )
} )
}
}
isConnected ( ) {
return this . _isReady
}
close ( cb ) {
close ( cb ) {
this . remixd . close ( )
this . remixd . exit ( )
this . files = null
this . _isReady = false
this . filesTree = null
cb ( )
cb ( )
}
}
init ( cb ) {
init ( cb ) {
this . remixd . call ( 'sharedfolder' , 'list' , { } , ( error , filesList ) => {
this . _isReady = true
if ( error ) {
cb ( )
cb ( error )
} else {
this . files = { }
for ( var k in filesList ) {
this . files [ this . type + '/' + k ] = filesList [ k ]
}
listAsTree ( this , this . files , ( error , tree ) => {
this . filesTree = tree
cb ( error )
} )
}
} )
}
}
// @TODO: refactor all `this._remixd.call(....)` uses into `this.remixd[api](...)`
// where `api = ...`:
// this.remixd.read(path, (error, content) => {})
// this.remixd.write(path, content, (error, result) => {})
// this.remixd.rename(path1, path2, (error, result) => {})
// this.remixd.remove(path, (error, result) => {})
// this.remixd.dir(path, (error, filesList) => {})
//
// this.remixd.exists(path, (error, isValid) => {})
exists ( path ) {
exists ( path ) {
// @TODO: add new remixd.exists() method
// we remove the this.files = null at the beggining
// modify the exists() (cause it is using the this.files) to use remixd
// yes for the exists I think you might need another remixd function
if ( ! this . files ) return false
if ( ! this . files ) return false
return this . files [ path ] !== undefined
return this . files [ path ] !== undefined
}
}
get ( path , cb ) {
get ( path , cb ) {
var unprefixedpath = this . removePrefix ( path )
var unprefixedpath = this . removePrefix ( path )
this . remixd . call ( 'sharedfolder' , 'get' , { path : unprefixedpath } , ( error , content ) => {
this . _ remixd. call ( 'sharedfolder' , 'get' , { path : unprefixedpath } , ( error , content ) => {
if ( ! error ) {
if ( ! error ) {
this . filesContent [ path ] = content
this . filesContent [ path ] = content
cb ( error , content )
cb ( error , content )
@ -83,7 +131,7 @@ class SharedFolder {
set ( path , content , cb ) {
set ( path , content , cb ) {
var unprefixedpath = this . removePrefix ( path )
var unprefixedpath = this . removePrefix ( path )
this . remixd . call ( 'sharedfolder' , 'set' , { path : unprefixedpath , content : content } , ( error , result ) => {
this . _ remixd. call ( 'sharedfolder' , 'set' , { path : unprefixedpath , content : content } , ( error , result ) => {
if ( cb ) cb ( error , result )
if ( cb ) cb ( error , result )
var path = this . type + '/' + unprefixedpath
var path = this . type + '/' + unprefixedpath
this . filesContent [ path ]
this . filesContent [ path ]
@ -103,7 +151,7 @@ class SharedFolder {
remove ( path ) {
remove ( path ) {
var unprefixedpath = this . removePrefix ( path )
var unprefixedpath = this . removePrefix ( path )
this . remixd . call ( 'sharedfolder' , 'remove' , { path : unprefixedpath } , ( error , result ) => {
this . _ remixd. call ( 'sharedfolder' , 'remove' , { path : unprefixedpath } , ( error , result ) => {
if ( error ) console . log ( error )
if ( error ) console . log ( error )
var path = this . type + '/' + unprefixedpath
var path = this . type + '/' + unprefixedpath
delete this . filesContent [ path ]
delete this . filesContent [ path ]
@ -116,7 +164,7 @@ class SharedFolder {
rename ( oldPath , newPath , isFolder ) {
rename ( oldPath , newPath , isFolder ) {
var unprefixedoldPath = this . removePrefix ( oldPath )
var unprefixedoldPath = this . removePrefix ( oldPath )
var unprefixednewPath = this . removePrefix ( newPath )
var unprefixednewPath = this . removePrefix ( newPath )
this . remixd . call ( 'sharedfolder' , 'rename' , { oldPath : unprefixedoldPath , newPath : unprefixednewPath } , ( error , result ) => {
this . _ remixd. call ( 'sharedfolder' , 'rename' , { oldPath : unprefixedoldPath , newPath : unprefixednewPath } , ( error , result ) => {
if ( error ) {
if ( error ) {
console . log ( error )
console . log ( error )
if ( this . error [ error . code ] ) error = this . error [ error . code ]
if ( this . error [ error . code ] ) error = this . error [ error . code ]
@ -134,27 +182,26 @@ class SharedFolder {
return true
return true
}
}
list ( ) {
//
return this . files
// Tree model for files
}
// {
// 'a': { }, // empty directory 'a'
listAsTree ( path , level ) {
// 'b': {
var nodes = path ? path . split ( '/' ) : [ ]
// 'c': {}, // empty directory 'b/c'
var tree = this . filesTree
// 'd': { '/readonly': true, '/content': 'Hello World' } // files 'b/c/d'
try {
// 'e': { '/readonly': false, '/path': 'b/c/d' } // symlink to 'b/c/d'
while ( nodes . length ) {
// 'f': { '/readonly': false, '/content': '<executable>', '/mode': 0755 }
var key = nodes . shift ( )
// }
if ( key ) tree = tree [ key ]
// }
}
//
} catch ( e ) {
resolveDirectory ( path , callback ) {
tree = { }
var self = this
}
path = '' + ( path || '' )
if ( level ) {
path = pathtool . join ( './' , path )
var leveltree = { }
buildList ( self , path , ( error , fileTree ) => {
build ( tree , level , leveltree )
if ( error ) return callback ( error )
tree = leveltree
callback ( null , { [ self . type ] : fileTree } )
}
} )
return tree
}
}
removePrefix ( path ) {
removePrefix ( path ) {
@ -162,67 +209,33 @@ class SharedFolder {
}
}
}
}
//
function remixapi ( remixd , self ) {
// Tree model for files
const read = ( path , callback ) => {
// {
path = '' + ( path || '' )
// 'a': { }, // empty directory 'a'
path = pathtool . join ( './' , path )
// 'b': {
remixd . call ( 'sharedfolder' , 'get' , { path } , ( error , content ) => callback ( error , content ) )
// 'c': {}, // empty directory 'b/c'
// 'd': { '/readonly': true, '/content': 'Hello World' } // files 'b/c/d'
// 'e': { '/readonly': false, '/path': 'b/c/d' } // symlink to 'b/c/d'
// 'f': { '/readonly': false, '/content': '<executable>', '/mode': 0755 }
// }
// }
//
function build ( tree , level , leveltree ) {
if ( ! level ) return
Object . keys ( tree ) . forEach ( key => {
var value = tree [ key ]
var more = value === Object ( value )
if ( more ) {
leveltree [ key ] = { }
build ( value , level - 1 , leveltree [ key ] )
} else leveltree [ key ] = value
} )
}
function listAsTree ( self , filesList , callback ) {
function hashmapize ( obj , path , val ) {
var nodes = path . split ( '/' )
var i = 0
for ( ; i < nodes . length - 1 ; i ++ ) {
var node = nodes [ i ]
if ( obj [ node ] === undefined ) {
obj [ node ] = { }
}
obj = obj [ node ]
}
obj [ nodes [ i ] ] = val
}
}
const write = ( path , content , callback ) => {
var tree = { }
path = '' + ( path || '' )
path = pathtool . join ( './' , path )
// This does not include '.remix.config', because it is filtered
remixd . call ( 'sharedfolder' , 'set' , { path , content } , ( error , result ) => callback ( error , result ) )
// inside list().
}
async . eachSeries ( Object . keys ( filesList ) , function ( path , cb ) {
const rename = ( path , newpath , callback ) => {
self . get ( path , ( error , content ) => {
path = '' + ( path || '' )
if ( error ) {
path = pathtool . join ( './' , path )
console . log ( error )
remixd . call ( 'sharedfolder' , 'rename' , { oldPath : path , newPath : newpath } , ( error , result ) => callback ( error , result ) )
cb ( error )
}
} else {
const remove = ( path , callback ) => {
self . filesContent [ path ] = content
path = '' + ( path || '' )
hashmapize ( tree , path , {
path = pathtool . join ( './' , path )
'/readonly' : filesList [ path ] ,
remixd . call ( 'sharedfolder' , 'remove' , { path } , ( error , result ) => callback ( error , result ) )
'/content' : content
}
} )
const dir = ( path , callback ) => {
cb ( )
path = '' + ( path || '' )
}
path = pathtool . join ( './' , path )
} )
remixd . call ( 'sharedfolder' , 'resolveDirectory' , { path } , ( error , filesList ) => callback ( error , filesList ) )
} , ( error ) => {
}
callback ( error , tree )
const exit = ( ) => { remixd . close ( ) }
} )
const api = { read , write , rename , remove , dir , exit , event : remixd . event }
return api
}
}
module . exports = SharedFolder