/**
- * @file File System Interface
- * @desc Provides basic file commands for interacting with Strapp
- * file system as well as storage (and backups) of file system
- * @author Jordan Lavatai and Ken Grimes
- * @version 0.0.1
- * @license AGPL-3.0
- * @copyright Strapp.io
- */
-
-import localforage from "localforage"
-import StrappPeerConnection from "strappPeerConnection"
-
-/* File constructor */
-class File extends Object {
- constructor(...props) {
- super()
- return Object.assign(this, new.target.defaults, ...props)
- }
- get() {
- return this.data
- }
- post(postedData) {
- this.data += postedData
- this.lastModified = new Date()
- }
- put(putData) {
- this.data = putData
- this.lastModified = new Date()
- }
- delete() {
- this.data = ''
- this.lastModified = new Date()
+* @file Strapp File System
+* @author Jordan Lavatai, Ken Grimes
+* @version 0.0.1
+* @license AGPL-3.0
+* @copyright August 2017 - Ken Grimes, Jordan Lavatai
+* @summmary File system implementation for a strapp node
+*/
+import LocalForage from "localforage"
+
+const StrappFile = (() => {
+ const localforage = LocalForage.createInstance({
+ driver: [LocalForage.LOCALSTORAGE,
+ LocalForage.INDEXEDDB,
+ LocalForage.WEBSQL],
+ name: 'strapp',
+ version: 0.1,
+ storeName: 'strapp'
+ })
+ const authorize = (pubKey, mode, stat) => {
+ let allowed
+ if (pubKey === stat.owner)
+ allowed = (stat.perms >>> 16) & 0xF
+ else {
+ let gAccess = false
+ let uGroups = StrappFile.get(`acct/${pubKey}/groups`).split(' ')
+ for (let i = 0; i < uGroups.length; i++) {
+ if (uGroups[i] === stat.group) {
+ gAccess = true
+ break
+ }
+ }
+ if (gAccess)
+ allowed = (stat.perms >>> 8) & 0xF
+ else
+ allowed = stat.perms & 0xF
+ }
+ switch(mode){
+ case 'r+':
+ case 'rw':
+ case 'wr':
+ return (allowed & 0x6) === 0x6
+ case 'w':
+ return (allowed & 0x2) === 0x2
+ case 'r':
+ return (allowed & 0x4) === 0x4
+ case 'x':
+ return (allowed & 0x1) === 0x1
+ default:
+ console.log(`Unknown access mode: ${mode}`)
+ return false
+ }
}
- connect() {
-
+ class StrappFile extends Object {
+ constructor(...props) {
+ super()
+ return Object.assign(this, new.target.defaults, ...props)
+ }
+ static PermissionDenied() {
+ return new Promise((resolve, reject) => reject('Permission denied'))
+ }
+ static get(path) {
+ return localforage.getItem(path)
+ }
+ static set(path, data) {
+ return localforage.setItem(path, data)
+ }
+ static delete(path) {
+ return localforage.removeItem(path)
+ }
+ static routeMessage(lmkid) {
+ //split lmkid by spaces
+ //regex sanitize. if '/', MSG. else if ' ', resolve method
+ }
+ HEAD(opt) {
+ if (authorize(opt.pubKey, 'r', this.stat))
+ return new Promise((resolve, reject) => resolve(''))
+ else
+ return StrappFile.PermissionDenied()
+ }
+ GET(opt) {
+ if (authorize(opt.pubKey, 'r', this.stat))
+ return StrappFile.get(this.path)
+ else return StrappFile.PermissionDenied()
+ }
+ PUT(opt) {
+ if (authorize(opt.pubKey, 'w', this.stat))
+ return StrappFile.set(this.path, opt.data)
+ else return StrappFile.PermissionDenied()
+ }
+ POST(opt) {
+ return this.PUT(Object.assign(opt, { data: this.GET(opt) + opt.data }))
+ }
+ DELETE(opt) {
+ if (authorize(opt.pubKey, 'w', this.stat))
+ return StrappFile.delete(this.path)
+ else return StrappFile.PermissionDenied()
+ }
+ OPTIONS(opt) {
+ return this.stat
+ }
+ CONNECT(opt) { //make channel
+ return this.GET(opt)
+ }
+ TRACE(opt) {
+ }
+ PATCH(opt) {
+ }
}
- options(publicKey) {
- return this.availPermissions(publicKey)
+ StrappFile.defaults = {
+ stat: {
+ type: 'mime/type',
+ perm: 0,
+ owner: 'thisOwnerPubKey',
+ group: 'groupname',
+ changed: 'time',
+ created: 'time',
+ accessed: 'time - not saved'
+ }
}
-}
-/* TODO: Continue to flesh this out */
-File.defaults = {
- name: '',
- data: '',
- mode: {},
- size: 0
- //lastModified: new Date()?
- //lastAccessed: new Date()?
-
-}
-
-
-/* Filesystem maintains the current session memory for the strapp instance. Files can be
- created and killed from the filesystem without leveraging localForage. Files that are
- in the filesystem can be stored to localForage while files that are in localForage can be loaded
- to the filesystem. When a Filesystem is first intialized, it attempts to get its strappID it populates itself from localForage and
- overwrites any files in its current memory. Files that have restore() as a property (which will be some method needed to
- make the file functions e.g. strappPeerConnections will restore() themselves lazily, i.e. when they are needed.*/
-
- /* TODO: Should it be possible to create/preserve/destroy a file to both localForage and fileSystem? (same time) */
- /* TODO: Should initFileSystem not overwrite files? */
-
-/* These are the default files on all file systems */
-let defaultFiles = [ "..", ".", "accounts", "ice", "log", "run" ]
-
-
-/* TODO: Protect data via closures? */
-const fs = {
- /* TODO: What if files are added to file system before init is is called? */
- initFileSystem(){
- this.db = localforage.createInstance({ name: "database" })
- /* Iterate through all files on localforage, adding them to FileSystem
- and calling their restore methods */
- this.db.iterate( (value, key, n) => {
- /* just btw, return !undefined to exit early */
- this.loadFile(key, true)
-
- }).catch( (err) => {
- console.log(`error: ${err} when iterating through localForage during initFileSystem`)
- })
- /* Add the hardcoded default files if they dont already exist */
- /* Restore these files --> need the private/public key*/
- initialFiles.map( (val, idx, array) => {
- if (this.fileExists(val)) {
- let file = this.getFile(val)
- let restoreProp = file['restore']
- if (restoreProp === undefined && typeof restoreFx === 'function') {
- //restore file
- }
- /* Else don't do anything, file exists in FS and doesnt need to be restored */
- }
- else {
- /* TODO: Remove checking for every file --> although its only for the default files which
- will probably be a low number. Still, unnecessary. Could make initialFiles a
- Map object with fileType in it and switch(val.fileType) */
- if (val === '..') {
- let file = new StrappPeerConnection()
- /* Connect with host */
- }
- else {
- /* Each default file is going to have specific permissions, */
- let filedata = new File()
- filedata.name = val
- filedata.mode =
- this.createFile(val,)
- }
- }
-
- })
-
- },
-
- fileExists(filename) {
- return this.files[filename] === undefined ? false : true
- },
-
- /* Create a file in the file system, if specified overwrites any file that is already there
- else does nothing */
- createFile(filename, filedata, overwrite = false){
- filedata.name = filename
- if (this.files[filename] === undefined) {
- this.files[filename] = filedata
+ return StrappFile
+})()
+
+const StrappPeerConnection = (() => {
+ class StrappPeerConnection extends StrappFile {
+ GET(opts) {
+ //get metadata (held in filesystem), with owner, usage info, etc
+ //if unauthed, send message down socket
}
- else {
- if (overwrite) {
- console.log(`Overwriting ${filename}`)
- this.files[filename] = filedata
- }
- else {
- console.log(`Didn't overwrite file so nothing happened`)
- }
+ PUT(opts) {
+ //create w/ sdp, register callback (or pipe), set owner
}
- },
-
- /* Get a file from browser session memory */
- /* TODO: Option to get from localForage? */
- getFile(filename) {
- return this.files[filename]
- },
-
- /* Save a file to file system*/
- saveFile(filename, filedata) {
- /* TODO: Determine if file to be saved is of saveable nature e.g. SPC's cant really be saved */
- this.db.setItem(filename, filedata)
- },
-
- /* Delete file from localForage */
- removeFile(filename) {
- this.db.removeItem(filename)
- },
-
- /* Delete a file from file system */
- killFile(filename) {
- delete this.files[filename]
-
- },
-
- /* Store file in file system to localForage */
- storeFile(filename) {
- this.db.setItem(filename, this.files[filename].filedata)
- },
-
- /* Load file from localForage to file system */
- loadFile(filename, overwrite = false) {
- let filedata = this.db.getItem(filename)
- filedata = filedata.restore === undefined ? filedata : filedata.restore()
- this.createFile(filename, filedata, overwrite)
- },
-
- saveFileSystem() {
- /* TODO: save all files in filesystem to localforage */
- },
- db: {},
- files: {}
-
-}
-
-/* File System API */
-
-
-/* Load file system from localStorage/indexedDB if strapp.js is running on a host */
-function loadFileSystem(){
-
-}
-
-/* Store file system before shutting down if strapp.js is running on a host- */
-function storeFileSystem(){}
-
-
-
-/* addFile - adds a created file to a file */
-//@arg fileType - what to set the type property
-//@arg fileData - what to set the data property
-//@arg filePos - where to create the file
-
-/* Determine if a publicKey has permissions to execute methods
-
-/* rm - Delete file */
-
-/* ls - display file contents */
- //open file
-//return all of file files
-
-/* cat - display file data */
-//return file data
-
-/* open - Open file */
- //traverse to file path
-/* perm - display file permissions (if you have permissions) */
-/* find - find a file */
-//@arg fileToFind
-/* stat - info about a file */
-//@arg path - path to the file
-/* exists - determine if a file contains a file */
-//@arg {String} searchedFile - file to be searched
-//@arg {String} fileName
-//@arg {Number} Depth to look
-//@return {Boolean} true if exists, false if doesn't
-
+ POST(opts) {
+ //send msg
+ }
+ MSG(opts) {
+ //send routing message down socket
+ //POST(opts.routemessage)
+ }
+ }
+ return StrappPeerConnection
+})()
+const StrappDirectory = (() => {
+ class StrappDirectory extends StrappFile {
+ CONNECT(opts) {
+ //send routing message to the directory (handle the next part here)
+ }
+ }
+ return StrappDirectory
+})()
+export default StrappFile
+export { StrappPeerConnection, StrappDirectory }