antos-frontend/src/core/vfs.coffee
2018-03-18 14:16:06 +01:00

352 lines
11 KiB
CoffeeScript

# Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
# AnTOS Web desktop is is licensed under the GNU General Public
# License v3.0, see the LICENCE file for more information
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
# You should have received a copy of the GNU General Public License
#along with this program. If not, see https://www.gnu.org/licenses/.
String.prototype.asFileHandler = () ->
list = @split "://"
handlers = _API.VFS.findHandlers list[0]
if not handlers or handlers.length is 0
_courrier.osfail __("VFS unknown handler: {0}", @), (_API.throwe "OS.VFS"), @
return null
return new handlers[0](@)
this.OS.API.VFS =
handlers: { }
register: ( protos, cls ) ->
return self.OS.API.VFS.handlers[protos] = cls # if typeof protos is "string"
#_API.VFS.handlers[v] = cls for v in protos
findHandlers: (proto) ->
l = (v for k, v of _API.VFS.handlers when proto.trim().match (new RegExp k , "g"))
return l
class BaseFileHandler
constructor: (path) ->
@dirty = false
@cache = undefined
@setPath path
setPath: (p) ->
@ready = false
return unless p
@path = p.toString()
list = @path.split "://"
@protocol = list[0]
return unless list.length > 1
re = list[1].replace(/^\/+|\/+$/g, '')
return if re is ""
@genealogy = re.split("/")
@basename = @genealogy[@genealogy.length - 1] unless @isRoot()
@ext = @basename.split( "." ).pop() unless @basename.lastIndexOf(".") is 0 or @basename.indexOf( "." ) is -1
asFileHandler: () ->
@
isRoot: () -> (not @genealogy) or (@genealogy.size is 0)
child: (name) ->
if @isRoot()
return @path + name
else
return @path + "/" + name
isHidden: () ->
return false if not @basename
@basename[0] is "."
hash: () ->
return -1 unless @path
return @path.hash()
sendB64: (m, f) ->
me = @
return f "" unless @cache
if typeof @cache is "string"
b64 = @cache.asBase64()
b64 = "data:#{m};base64,#{b64}"
f(b64)
else
reader = new FileReader()
reader.readAsDataURL(@cache)
reader.onload = () ->
f reader.result
reader.onerror = (e) ->
return _courrier.osfail __("VFS Cannot encode file: {0}", me.path), (_API.throwe "OS.VFS"), e
parent: () ->
return @ if @isRoot()
return (@protocol + "://" + (@genealogy.slice 0 , @genealogy.length - 1).join "/")
onready: (f, err) ->
# read meta data
return f() if @ready
me = @
me.meta (d) ->
if d.error
return if err then err d else _courrier.osfail "#{me.path}: #{d.error}", (_API.throwe "OS.VFS"), d.error
me.info = d.result
me.ready = true
f()
read: (f, t) ->
me = @
@onready (() -> me.action "read", t, f)
write: (d, f) ->
me = @
@action "write", d, (r) ->
_courrier.ostrigger "VFS", { m: "write", file: me } if r.result
f r
mk: (d, f) ->
me = @
@onready (() -> me.action "mk", d, (r) ->
_courrier.ostrigger "VFS", { m: "mk", file: me } if r.result
f r)
remove: (f) ->
me = @
@onready (() -> me.action "remove", null, (r) ->
_courrier.ostrigger "VFS", { m: "remove", file: me } if r.result
f r)
upload: (f) ->
me = @
@onready (() -> me.action "upload", null, (r) ->
_courrier.ostrigger "VFS", { m: "upload", file: me } if r.result
f r)
publish: (f) ->
me = @
@onready (() -> me.action "publish", null, (r) ->
_courrier.ostrigger "VFS", { m: "publish", file: me } if r.result
f r)
download: (f) ->
me = @
@onready (() -> me.action "download", null, f)
move: (d, f) ->
me = @
@onready (() -> me.action "move", d, (r) ->
_courrier.ostrigger "VFS", { m: "move", file: d.asFileHandler() } if r.result
f r)
execute: (f) ->
me = @
@onready (() -> me.action "execute", null, f)
#mk: (f) ->
meta: (f) ->
# for main action read, write, remove, execute
# must be implemented by subclasses
action: (n, p, f) ->
return _courrier.osfail __("VFS unknown action: {0}", n), (_API.throwe "OS.VFS"), n
# now export the class
self.OS.API.VFS.BaseFileHandler = BaseFileHandler
# Remote file handle
class RemoteFileHandler extends self.OS.API.VFS.BaseFileHandler
constructor: (path) ->
super path
meta: (f) ->
_API.handler.fileinfo @path, f
action: (n, p, f) ->
me = @
switch n
when "read"
return _API.handler.scandir @path, f if @info.type is "dir"
#read the file
return _API.handler.fileblob @path, f if p is "binary"
_API.handler.readfile @path, f, if p then p else "text"
when "mk"
return f { error: __("{0} is not a directory", @path) } if @info.type is "file"
_API.handler.mkdir "#{@path}/#{p}", f
when "write"
return _API.handler.write me.path, me.cache, f if p is "base64"
@sendB64 p, (data) ->
_API.handler.write me.path, data, f
when "upload"
return if @info.type is "file"
_API.handler.upload @path, f
when "remove"
_API.handler.delete @path, f
when "publish"
_API.handler.sharefile @path, true , f
when "download"
return if @info.type is "dir"
_API.handler.fileblob @path, (d) ->
blob = new Blob [d], { type: "octet/stream" }
_API.saveblob me.basename, blob
when "move"
_API.handler.move @path, p, f
else
return _courrier.osfail __("VFS unknown action: {0}", n), (_API.throwe "OS.VFS"), n
self.OS.API.VFS.register "^(home|desktop|os|Untitled)$", RemoteFileHandler
# Application Handler
class ApplicationHandler extends self.OS.API.VFS.BaseFileHandler
constructor: (path) ->
super path
@info = _OS.setting.system.packages[@basename] if @basename
@ready = true
meta: (f) ->
f()
action: (n, p, f) ->
me = @
switch n
when "read"
return f { result: @info } if @info
return unless @isRoot()
f { result: ( v for k, v of _OS.setting.system.packages ) }
when "mk"
return
when "write"
return
when "upload"
# install
return
when "remove"
#uninstall
return
when "publish"
return
when "download"
return
when "move"
return
else
return _courrier.osfail __("VFS unknown action: {0}", n), (_API.throwe "OS.VFS"), n
self.OS.API.VFS.register "^app$", ApplicationHandler
class BufferFileHandler extends self.OS.API.VFS.BaseFileHandler
constructor: (path, mime, data) ->
super path
@cache = data if data
@info =
mime: mime
path: path
size: if data then data.length else 0
name: @basename
type: "file"
meta: (f) ->
f()
onchange: (f) ->
@onchange = f
action: (n, p, f) ->
me = @
switch n
when "read"
return f { result: @cache }
when "mk"
return
when "write"
@cache = p
@onchange @ if @onchange
f { result: true }
when "upload"
# install
return
when "remove"
#uninstall
return
when "publish"
return
when "download"
blob = new Blob [@cache], { type: "octet/stream" }
_API.saveblob me.basename, blob
when "move"
return
else
return _courrier.osfail __("VFS unknown action: {0}", n), (_API.throwe "OS.VFS"), n
self.OS.API.VFS.register "^mem$", BufferFileHandler
class URLFileHandler extends self.OS.API.VFS.BaseFileHandler
constructor: (path) ->
super path
@ready = true
meta: (f) ->
f { result: true }
action: (n, p, f) ->
me = @
switch n
when "read"
_API.get @path, (d) ->
f(d)
, (e, s) ->
_courrier.oserror __("VFS cannot read : {0}", me.path), e, s
, if p then p else "text"
else
return _courrier.oserror __("VFS unknown action: {0}", n), (_API.throwe "OS.VFS"), n
self.OS.API.VFS.register "^(http|https)$", URLFileHandler
class SharedFileHandler extends self.OS.API.VFS.BaseFileHandler
constructor: (path) ->
super path
@ready = true if @isRoot()
meta: (f) ->
_API.handler.fileinfo @path, f
action: (n, p, f) ->
me = @
switch n
when "read"
return _API.get "#{_API.handler.shared}/all", f, ((e, s)->) if @isRoot()
#read the file
return _API.handler.fileblob @path, f if p is "binary"
_API.handler.readfile @path, f, if p then p else "text"
when "mk"
return
when "write"
_API.handler.write @path, p, f
when "remove"
_API.handler.sharefile @basename, false, f
when "upload"
return
when "publish"
return f { result: @basename }
when "download"
return if @info.type is "dir"
_API.handler.fileblob @path, (d) ->
blob = new Blob [d], { type: "octet/stream" }
_API.saveblob me.basename, blob
when "move"
return
else
return _courrier.osfail __("VFS unknown action: {0}", n), (_API.throwe "OS.VFS"), n
self.OS.API.VFS.register "^shared$", SharedFileHandler