UNPKG

globular-mvc

Version:

Generic template to create web-application that made use of globular as backend and materialize as css (wrap in web-component's)

467 lines (389 loc) 14.4 kB
import { generatePeerToken, getUrl, Model } from './Model'; import { readDir } from "globular-web-client/api"; import * as jwt from "jwt-decode"; import { Globular } from 'globular-web-client'; import { ApplicationView } from './ApplicationView'; import { FileInfo, GetFileInfoRequest, ReadFileRequest } from 'globular-web-client/file/file_pb'; import { Application } from './Application'; import { formatReal } from './components/utility'; import { mergeTypedArrays, uint8arrayToStringMethod } from "./Utility"; /** * Server side file accessor. That */ export class File extends Model { // Must be implemented by the application level. public static saveLocal: (f: File, b: Blob) => void // Test if a local copy exist for the file. public static hasLocal: (path: String, callback: (exists: boolean) => void) => void; // Remove the local file copy public static removeLocal: (path: String, callback: () => void) => void; // If the file does not really exist on the server It can be keep in that map. private static _local_files: any = {} private globule: Globular; // If the file is a .lnk file the lnk will contain a // reference to the linked file... private _lnk: File; public get lnk(): File { return this._lnk; } public set lnk(value: File) { this._lnk = value; } // return the file domain. public get domain(): string { return this.globule.domain; } private _metadata: any = {}; public get metadata(): any { return this._metadata; } public set metadata(value: any) { this._metadata = value; } /** A file image preview */ private _thumbnail: string public get thumbnail(): string { return this._thumbnail; } public set thumbnail(value: string) { this._thumbnail = value; } /** The file path */ private _path: string; public get path(): string { return this._path; } public set path(value: string) { this._path = value; } /** The name */ private _name: string; public get name(): string { return this._name; } public set name(value: string) { this._name = value; } /** The size */ private _size: number; public get size(): number { return this._size; } public set size(value: number) { this._size = value; } /** The Mode */ private _mode: number; public get mode(): number { return this._mode; } public set mode(value: number) { this._mode = value; } /** The mode time */ private _modeTime: Date; public get modeTime(): Date { return this._modeTime; } public set modeTime(value: Date) { this._modeTime = value; } /** The Mime type */ private _mime: string; public get mime(): string { return this._mime; } public set mime(value: string) { this._mime = value; } /** The file checksum */ private _checksum: string; public get checksum(): string { return this._checksum; } public set checksum(value: string) { this._checksum = value; } /** is dir */ private _isDir: boolean; public get isDir(): boolean { return this._isDir; } public set isDir(value: boolean) { this._isDir = value; } private _files: File[]; public get files(): File[] { return this._files; } public set files(value: File[]) { this._files = value; } /** The file */ constructor(name: string, path: string, local: boolean = false, globule = Model.globular) { super(); // keep track of the origine this.globule = globule; this._name = name; this._path = path.split("//").join("/"); /** Here I will initialyse the resource. */ this.files = new Array<File>(); if (local) { let id = globule.domain + "@" + this.path File._local_files[id] = this } } /** * Create instance of File class from JSON object. * @param obj The JSON object. */ static fromObject(obj: any, local?: boolean, globule?: Globular): any { if(obj.domain){ globule = Model.getGlobule(obj.domain) } const file = new File(obj.name, obj.path, local, globule) file.isDir = obj.isDir file.mime = obj.mime file.modeTime = new Date(obj.modeTime * 1000) file.mode = obj.mode file.size = obj.size file.thumbnail = obj.thumbnail file.checksum = obj.checksum file._metadata = obj.metadata // Now the sub-file. if (file.isDir && obj.filesList != null) { for (let o of obj.filesList) { let g = globule if(o.domain){ g = Model.getGlobule(o.domain) } let f = <File>File.fromObject(o, local, g) file.files.push(f) } } return file } /** * Create instance of File from string. * @param str */ static fromString(str: string): any { let file = File.fromObject(JSON.parse(str)) return file } /** * Set back the file to JSON object. */ toObject(): any { let obj = { isDir: this.isDir, mime: this.mime, modeTime: this.modeTime.toISOString(), mode: this.mode, name: this.name, path: this.path, size: this.size, domain: this.domain, checksum: this.checksum, thumbnail: this.thumbnail, metadata: this.metadata, files: new Array<any>() } for (let f of this.files) { obj.files.push(f.toObject()) } return obj } /** * Stringnify a file. */ toString(): string { let obj = this.toObject() return JSON.stringify(obj) } /** * Return the file path. */ get filePath(): string { if (this.name == "") { return "/" } return this.path + "/" + this.name } /** * Retrun the file from a given path. * @param globule * @param path * @param callback * @param errorCallback */ static getFile(globule: Globular, path: string, thumbnailWith: number, thumbnailHeight: number, callback: (f: File) => void, errorCallback: (err: string) => void) { generatePeerToken(globule, token => { let rqst = new GetFileInfoRequest() rqst.setPath(path) rqst.setThumnailheight(thumbnailHeight) rqst.setThumnailwidth(thumbnailWith) globule.fileService.getFileInfo(rqst, { application: Application.application, domain: globule.domain, token: token }) .then(rsp => { let f = File.fromObject(rsp.getInfo().toObject()) f.globule = globule; callback(f); }) .catch(e => { errorCallback(e) }) }, errorCallback) } /** * Static function's */ static readDir(path: string, recursive: boolean, callback: (dir: File) => void, errorCallback: (err: any) => void, globule?: Globular) { // So here I will get the dir of the current user... //let token = localStorage.getItem("user_token") generatePeerToken(globule, token => { let decoded = jwt(token); let address = (<any>decoded).address; if (!globule) { globule = Model.getGlobule(address) } path = path.replace(globule.config.DataPath + "/files/", "/") let id = globule.domain + "@" + path if (File._local_files[id] != undefined) { callback(File._local_files[id]) return } readDir(globule, path, recursive, (dir: FileInfo) => { callback(File.fromObject(dir.toObject(), false, globule)) }, errorCallback, 80, 80, token) }, errorCallback) } static readText(file: File, callback: (text: string) => void, errorCallback: (err: any) => void) { // Read the file... let url = getUrl(file.globule) file.path.split("/").forEach(item => { url += "/" + encodeURIComponent(item.trim()) }) // Generate peer token. generatePeerToken(file.globule, token => { let rqst = new ReadFileRequest rqst.setPath(file.path) let data: any = [] let stream = file.globule.fileService.readFile(rqst, { application: Application.application, domain: file.globule.domain, token: token }) // Here I will create a local event to be catch by the file uploader... stream.on("data", (rsp) => { data = mergeTypedArrays(data, rsp.getData()); }) stream.on("status", (status) => { if (status.code == 0) { uint8arrayToStringMethod(data, (str) => { callback(str); }); } else { // In case of error I will return an empty array errorCallback(status.details) } }); }, errorCallback) } /** * Save file local copy */ keepLocalyCopy(callback: () => void) { let globule = this.globule let toast = ApplicationView.displayMessage(` <style> </style> <div id="create-file-local-copy"> <div>Your about to create a local copy of file </div> <span style="font-style: italic;" id="file-path"></span> <div style="display: flex; flex-direction: column; justify-content: center;"> <img style="width: 185.31px; align-self: center; padding-top: 10px; padding-bottom: 15px;" id="thumbnail"> </img> </div> <div>Is that what you want to do? </div> <div style="display: flex; justify-content: flex-end;"> <paper-button id="ok-button">Ok</paper-button> <paper-button id="cancel-button">Cancel</paper-button> </div> </div> `, 60 * 1000) let cancelBtn = <any>(toast.el.querySelector("#cancel-button")) cancelBtn.onclick = () => { toast.dismiss(); } let thumbnailImg = <any>(toast.el.querySelector("#thumbnail")) thumbnailImg.src = this.thumbnail toast.el.querySelector("#file-path").innerHTML = this.name let okBtn = <any>(toast.el.querySelector("#ok-button")) okBtn.onclick = () => { // simply download the file. generatePeerToken(globule, (token: string) => { let path = this.path let url = getUrl(globule) path.split("/").forEach(item => { item = item.trim() if (item.length > 0) { url += "/" + encodeURIComponent(item) } }) const req = new XMLHttpRequest(); // Set the values also as parameters... url += "?domain=" + globule.domain url += "&application=" + Model.application url += "&token=" + token req.open("GET", url, true); // Set the token to manage downlaod access. req.setRequestHeader("token", token); req.setRequestHeader("application", globule.domain); req.setRequestHeader("domain", globule.domain); req.responseType = "blob"; req.onload = (event: any) => { const blob = req.response; if (File.saveLocal) { File.saveLocal(this, blob) callback() } }; req.send(); }, err => ApplicationView.displayMessage(err, 3000)) toast.dismiss(); } } /** * remove file local copy */ removeLocalCopy(callback: () => void) { let toast = ApplicationView.displayMessage(` <style> </style> <div id="create-file-local-copy"> <div>Your about to remove a local copy of file </div> <span style="font-style: italic;" id="file-path"></span> <div style="display: flex; flex-direction: column; justify-content: center;"> <img style="width: 185.31px; align-self: center; padding-top: 10px; padding-bottom: 15px;" id="thumbnail"> </img> </div> <div>Is that what you want to do? </div> <div style="display: flex; justify-content: flex-end;"> <paper-button id="ok-button">Ok</paper-button> <paper-button id="cancel-button">Cancel</paper-button> </div> </div> `, 60 * 1000) let cancelBtn = <any>(toast.el.querySelector("#cancel-button")) cancelBtn.onclick = () => { toast.dismiss(); } let thumbnailImg = <any>(toast.el.querySelector("#thumbnail")) thumbnailImg.src = this.thumbnail toast.el.querySelector("#file-path").innerHTML = this.name let okBtn = <any>(toast.el.querySelector("#ok-button")) okBtn.onclick = () => { if (File.removeLocal) { File.removeLocal(this.path, () => { ApplicationView.displayMessage(`local copy of ${this.path} was removed`, 3000) callback() }) } toast.dismiss(); } } }