diff --git a/bower.json b/bower.json index e5ebac81..a105e493 100644 --- a/bower.json +++ b/bower.json @@ -24,7 +24,8 @@ "jquery-ui": "~1.11.4", "jquery-fullscreen": "~1.1.4", "cjs": "*", - "ace": "~1.2.2" + "ace": "~1.2.2", + "browserfs": "0.5.8" }, "devDependencies": {}, "resolutions": { diff --git a/src/app/require.config.js b/src/app/require.config.js index dc3d0136..67d15f29 100644 --- a/src/app/require.config.js +++ b/src/app/require.config.js @@ -28,7 +28,8 @@ require.config({ "bloodhound": "bower_modules/typeahead.js/dist/bloodhound.min", // exports window global "Bloodhound" "FileSaver": "bower_modules/FileSaver/FileSaver.min", // exports window global "saveAs" "Blob": "bower_modules/Blob/Blob", // exports window global "Blob" - + "browserfs": "bower_modules/browserfs/dist/browserfs.min", + // Application-specific modules "app/config": "app/config/config.dev" // overridden to 'config.dist' in build config }, diff --git a/src/app/sys-filesystem.js b/src/app/sys-filesystem.js new file mode 100644 index 00000000..189055cd --- /dev/null +++ b/src/app/sys-filesystem.js @@ -0,0 +1,321 @@ +/* global require, Buffer */ +import BrowserFS from 'browserfs'; + +class SysFileSystem { + + constructor() { + this.initialized = false; + return this; + } + + initialize(jor1kFS) + { + this.initialized = true; + BrowserFS.install(window); + BrowserFS.initialize(new BrowserFS.FileSystem.LocalStorage()); + + this.localFS = require('fs'); + this.jor1kFS = jor1kFS; + this.listeners = []; + + this.syncVM(); + + this.jor1kFS.WatchDirectory('home/user', this.Jor1kNotifyCallBack.bind(this), this); + + } +/*------------------------------------------------------------------------------------------------*/ + /** + * API for interating with the joined file system + **/ + + writeFile(path, buf){ + if(path.charAt(0)!='/') + path = '/' + path; + + if (typeof buf == 'string') buf = new Buffer(buf); + + this.jor1kFS.MergeBinaryFile('home/user'+path, new Uint8Array(buf.toArrayBuffer())); + this.localFS.writeFileSync(path, buf); + } + + readFile(path, cb){ + if(this.localFS.statSync(path).isDirectory()) + return; + + this.localFS.readFile(path, cb); + } + + /* + * This is a blocking call, user readFile for asyc. + */ + readFileSync(path){ + if(this.localFS.statSync(path).isDirectory()) + return; + + return this.localFS.readFileSync(path); + } + + deleteFile(path){ + if(this.localFS.statSync(path).isDirectory()) + return; + + if(path.charAt(0)!='/') + path = '/' + path; + + if(this.localFS.statSync(path).isFile()) + this.jor1kFS.DeleteNode('home/user'+path); + } + + /* + * Creates a directory. + * Does not overwrite existing directories. + */ + makeDirectory(path){ + if(path.charAt(0)!='/') + path = '/' + path; + + this.jor1kFS.CreateDirectory('home/user'+path); + } + + /* + * Recursively removes a directory. + */ + removeDirectory(path){ + if(this.localFS.statSync(path).isFile()) + return; + + if(path.charAt(0)!='/') + path = '/' + path; + + if(this.localFS.statSync(path).isDirectory()) + this.jor1kFS.DeleteNode('home/user'+path); + } + + /* + * Renames a file or directory from oldpath to newpath. + * Same functionality as mv. + */ + rename(oldpath, newpath){ + if(oldpath==newpath) + return; + + if(oldpath.charAt(0)!='/') + oldpath = '/' + oldpath; + + if(newpath.charAt(0)!='/') + newpath = '/' + newpath; + + if(this.localFS.existsSync(oldpath)) + this.jor1kFS.Rename('home/user'+oldpath, 'home/user'+newpath); + } + + /* + * Copies a single file from srcpath to dstpath. + * Copying of directories is not yet implemented. + */ + copyTo(srcpath, dstpath){ + if(srcpath == dstpath) + return; + + var stat = this.localFS.statSync(srcpath); + if(stat.isDirectory()) + return; + + this.localFS.readFile(srcpath, function(err, buf){ + if(dstpath.charAt(0)!='/') + dstpath = '/' + dstpath; + + this.jor1kFS.MergeBinaryFile('home/user'+dstpath, new Uint8Array(buf.toArrayBuffer()), stat.mode); + + }.bind(this)); + } + + /* + * Returns an array of { isDirectory: boolean, name: string } objects + * of all nodes with in the directory specified in path. + */ + getDirectoryChildren(path){ + if(path == '') + path = '/'; + + if((!this.localFS.existsSync(path)) || this.localFS.statSync(path).isFile()) + return []; + + var children = this.localFS.readdirSync(path); + var ret = []; + + if(path.charAt(path.length-1)!='/') + path = path + '/'; + + for(var i=0; i leafs + */ + getDirectoryTree(){ + return this.getDirectoryTreeHelper('/'); + } + + /* + * Helper for getDirectoryTree + */ + getDirectoryTreeHelper(path){ + var children = this.localFS.readdirSync(path); + + if(path=='/') + path = ''; + + var ret = []; + var dirs = []; + for(var i=0; i { if (this.tty0ready && this.tty1ready) { + + //Attach persistent filesystem + SysFileSystem.initialize(this.jor1kgui.fs); + // LiveEdit uses the bootFinished value when sent the ready event, // so bootFinished must be updated before broadcasting the event this.bootFinished = true;