mirror of
https://github.com/antos-rde/antosdk-apps.git
synced 2024-12-25 11:48:21 +01:00
add vfsx protocol
This commit is contained in:
parent
44d877ca6e
commit
9cd133194e
81
Antunnel/build.json
Normal file
81
Antunnel/build.json
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
{
|
||||||
|
"name": "Antunnel",
|
||||||
|
"targets": {
|
||||||
|
"init": {
|
||||||
|
"jobs": [
|
||||||
|
{
|
||||||
|
"name": "vfs-mkdir",
|
||||||
|
"data": [
|
||||||
|
"build",
|
||||||
|
"build/debug",
|
||||||
|
"build/release"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"coffee": {
|
||||||
|
"require": [
|
||||||
|
"coffee"
|
||||||
|
],
|
||||||
|
"jobs": [
|
||||||
|
{
|
||||||
|
"name": "coffee-compile",
|
||||||
|
"data": {
|
||||||
|
"src": [
|
||||||
|
"coffees/Antunnel.coffee",
|
||||||
|
"coffees/AntunnelService.coffee"
|
||||||
|
],
|
||||||
|
"dest": "build/debug/main.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"uglify": {
|
||||||
|
"require": [
|
||||||
|
"terser"
|
||||||
|
],
|
||||||
|
"jobs": [
|
||||||
|
{
|
||||||
|
"name": "terser-uglify",
|
||||||
|
"data": [
|
||||||
|
"build/debug/main.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"copy": {
|
||||||
|
"jobs": [
|
||||||
|
{
|
||||||
|
"name": "vfs-cp",
|
||||||
|
"data": {
|
||||||
|
"src": [
|
||||||
|
"package.json",
|
||||||
|
"README.md"
|
||||||
|
],
|
||||||
|
"dest": "build/debug"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"release": {
|
||||||
|
"require": [
|
||||||
|
"zip"
|
||||||
|
],
|
||||||
|
"depend": [
|
||||||
|
"init",
|
||||||
|
"coffee",
|
||||||
|
"copy",
|
||||||
|
"uglify"
|
||||||
|
],
|
||||||
|
"jobs": [
|
||||||
|
{
|
||||||
|
"name": "zip-mk",
|
||||||
|
"data": {
|
||||||
|
"src": "build/debug",
|
||||||
|
"dest": "build/release/Antunnel.zip"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -24,8 +24,10 @@ class AntunnelService extends OS.application.BaseService
|
|||||||
@iconclass = "fa fa-close" unless @is_connect
|
@iconclass = "fa fa-close" unless @is_connect
|
||||||
@update()
|
@update()
|
||||||
OS.onexit "cleanupAntunnel", () =>
|
OS.onexit "cleanupAntunnel", () =>
|
||||||
|
return new Promise (resolve, reject) =>
|
||||||
Antunnel.tunnel.close() if Antunnel.tunnel
|
Antunnel.tunnel.close() if Antunnel.tunnel
|
||||||
@quit()
|
@quit()
|
||||||
|
resolve(true)
|
||||||
|
|
||||||
|
|
||||||
action: (e) ->
|
action: (e) ->
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Antunnel",
|
|
||||||
"css": [],
|
|
||||||
"javascripts": [],
|
|
||||||
"coffees": ["coffees/Antunnel.coffee", "coffees/AntunnelService.coffee"],
|
|
||||||
"copies": ["package.json", "README.md"]
|
|
||||||
}
|
|
@ -389,6 +389,16 @@
|
|||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/TinyEditor/build/release/TinyEditor.zip"
|
"download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/TinyEditor/build/release/TinyEditor.zip"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"pkgname": "vfsx",
|
||||||
|
"name": "AntOS VFS handles",
|
||||||
|
"description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/vfsx/README.md",
|
||||||
|
"category": "Library",
|
||||||
|
"author": "Dany LE",
|
||||||
|
"version": "0.1.0-b",
|
||||||
|
"dependencies": [],
|
||||||
|
"download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/vfsx/build/release/vfsx.zip"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"pkgname": "VizApp",
|
"pkgname": "VizApp",
|
||||||
"name": "Viz editor",
|
"name": "Viz editor",
|
||||||
|
10
vfsx/README.md
Normal file
10
vfsx/README.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# vfsx
|
||||||
|
AntOS VFS handles for various file protocols which are not included by default
|
||||||
|
int core release, such as:
|
||||||
|
- GoogleDrive
|
||||||
|
- Dropbox (TODO)
|
||||||
|
|
||||||
|
This package is used mainly by the File application to communicate with different
|
||||||
|
file hosting protocols
|
||||||
|
|
||||||
|
## Change logs
|
83
vfsx/build.json
Normal file
83
vfsx/build.json
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
{
|
||||||
|
"name": "vfsx",
|
||||||
|
"targets":{
|
||||||
|
"clean": {
|
||||||
|
"jobs": [
|
||||||
|
{
|
||||||
|
"name": "vfs-rm",
|
||||||
|
"data": ["build/debug","build/release"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"require": ["ts"],
|
||||||
|
"jobs":[
|
||||||
|
{
|
||||||
|
"name": "vfs-mkdir",
|
||||||
|
"data": ["build","build/debug","build/release"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ts-import",
|
||||||
|
"data": ["sdk://core/ts/core.d.ts", "sdk://core/ts/jquery.d.ts","sdk://core/ts/antos.d.ts"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ts-compile",
|
||||||
|
"data": {
|
||||||
|
"src": ["gdv.ts"],
|
||||||
|
"dest": "build/debug/vfsx.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"uglify": {
|
||||||
|
"require": ["terser"],
|
||||||
|
"jobs": [
|
||||||
|
{
|
||||||
|
"name":"terser-uglify",
|
||||||
|
"data": ["build/debug/vfsx.js"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"copy": {
|
||||||
|
"jobs": [
|
||||||
|
{
|
||||||
|
"name": "vfs-cp",
|
||||||
|
"data": {
|
||||||
|
"src": [
|
||||||
|
"package.json",
|
||||||
|
"README.md"
|
||||||
|
],
|
||||||
|
"dest":"build/debug"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locale": {
|
||||||
|
"require": ["locale"],
|
||||||
|
"jobs": [
|
||||||
|
{
|
||||||
|
"name":"locale-gen",
|
||||||
|
"data": {
|
||||||
|
"src": "",
|
||||||
|
"exclude": ["build/"],
|
||||||
|
"locale": "en_GB",
|
||||||
|
"dest": "package.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"release": {
|
||||||
|
"depend": ["clean","build","uglify", "copy"],
|
||||||
|
"require": ["zip"],
|
||||||
|
"jobs": [
|
||||||
|
{
|
||||||
|
"name": "zip-mk",
|
||||||
|
"data": {
|
||||||
|
"src":"build/debug",
|
||||||
|
"dest":"build/release/vfsx.zip"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
vfsx/build/debug/README.md
Normal file
10
vfsx/build/debug/README.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# vfsx
|
||||||
|
AntOS VFS handles for various file protocols which are not included by default
|
||||||
|
int core release, such as:
|
||||||
|
- GoogleDrive
|
||||||
|
- Dropbox (TODO)
|
||||||
|
|
||||||
|
This package is used mainly by the File application to communicate with different
|
||||||
|
file hosting protocols
|
||||||
|
|
||||||
|
## Change logs
|
39
vfsx/build/debug/package.json
Normal file
39
vfsx/build/debug/package.json
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"pkgname": "vfsx",
|
||||||
|
"name": "AntOS VFS handles",
|
||||||
|
"description": "AntOS VFS handles for various file protocols which are not included by default int core release",
|
||||||
|
"info": {
|
||||||
|
"author": "Dany LE",
|
||||||
|
"email": "mrsang@iohub.dev"
|
||||||
|
},
|
||||||
|
"version": "0.1.0-b",
|
||||||
|
"category": "Library",
|
||||||
|
"iconclass": "fa fa-cog",
|
||||||
|
"mimes": [
|
||||||
|
"none"
|
||||||
|
],
|
||||||
|
"dependencies": [],
|
||||||
|
"locale": {},
|
||||||
|
"locales": {
|
||||||
|
"en_GB": {
|
||||||
|
"Unknown API setting for GAPI": "Unknown API setting for GAPI",
|
||||||
|
"VFS cannot download file : {0}": "VFS cannot download file : {0}",
|
||||||
|
"VFS cannot get meta data for {0}": "VFS cannot get meta data for {0}",
|
||||||
|
"No GAPI meta found": "No GAPI meta found",
|
||||||
|
"Authentication": "Authentication",
|
||||||
|
"Would you like to login to GoogleDrive?": "Would you like to login to GoogleDrive?",
|
||||||
|
"User abort the authentication": "User abort the authentication",
|
||||||
|
"File ID is not valid": "File ID is not valid",
|
||||||
|
"File {0} not found": "File {0} not found",
|
||||||
|
"Cannot find local copy of file; {0}": "Cannot find local copy of file; {0}",
|
||||||
|
"VFS cannot save : {0}": "VFS cannot save : {0}",
|
||||||
|
"VFS cannot write : {0}": "VFS cannot write : {0}",
|
||||||
|
"{0} is not a directory": "{0} is not a directory",
|
||||||
|
"VFS cannot create : {0}": "VFS cannot create : {0}",
|
||||||
|
"Cannot identify file id of {0}": "Cannot identify file id of {0}",
|
||||||
|
"VFS cannot delete : {0}": "VFS cannot delete : {0}",
|
||||||
|
"VFS cannot move : {0}": "VFS cannot move : {0}",
|
||||||
|
"Target file should be a folder": "Target file should be a folder"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
vfsx/build/debug/vfsx.js
Normal file
1
vfsx/build/debug/vfsx.js
Normal file
File diff suppressed because one or more lines are too long
BIN
vfsx/build/release/vfsx.zip
Normal file
BIN
vfsx/build/release/vfsx.zip
Normal file
Binary file not shown.
619
vfsx/gdv.ts
Normal file
619
vfsx/gdv.ts
Normal file
@ -0,0 +1,619 @@
|
|||||||
|
namespace OS {
|
||||||
|
export namespace API {
|
||||||
|
export namespace VFS {
|
||||||
|
declare var gapi: any;
|
||||||
|
|
||||||
|
interface GAPITYPE {
|
||||||
|
CLIENT_ID: string;
|
||||||
|
API_KEY: string;
|
||||||
|
apilink: string;
|
||||||
|
DISCOVERY_DOCS: string[];
|
||||||
|
SCOPES: string;
|
||||||
|
uploadlink: string; //
|
||||||
|
logout: string;
|
||||||
|
};
|
||||||
|
let G_CACHE = {"gdv://":{ id: "root", mime: 'dir' } };
|
||||||
|
|
||||||
|
export class GoogleDriveHandle extends BaseFileHandle {
|
||||||
|
private gid: string;
|
||||||
|
static API_META: GAPITYPE;
|
||||||
|
private local_copy: BaseFileHandle;
|
||||||
|
constructor(path: string) {
|
||||||
|
super(path);
|
||||||
|
if (!GoogleDriveHandle.API_META) {
|
||||||
|
OS.announcer.oserror( __("Unknown API setting for GAPI"),
|
||||||
|
OS.API.throwe("OS.VFS"));
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (this.isRoot()) {
|
||||||
|
this.gid = 'root';
|
||||||
|
}
|
||||||
|
this.cache = "";
|
||||||
|
this.local_copy = undefined;
|
||||||
|
}
|
||||||
|
private fields(): string {
|
||||||
|
return "webContentLink, id, name,mimeType,description, kind, parents, properties, iconLink, createdTime, modifiedTime, owners, permissions, fullFileExtension, fileExtension, size, version";
|
||||||
|
}
|
||||||
|
private isFolder(): boolean {
|
||||||
|
return this.info.mimeType === "application/vnd.google-apps.folder";
|
||||||
|
}
|
||||||
|
private load(promise: Promise<any>): Promise<any> {
|
||||||
|
const q = API.mid();
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
API.loading(q, "GAPI");
|
||||||
|
try {
|
||||||
|
let ret = await promise;
|
||||||
|
API.loaded(q, "GAPI", "OK");
|
||||||
|
return resolve(ret);
|
||||||
|
} catch (e) {
|
||||||
|
API.loaded(q, "GAPI", "FAIL");
|
||||||
|
return reject(__e(e));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private sync(meta_data?: GenericObject<any>): Promise<any>
|
||||||
|
{
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try{
|
||||||
|
if((!this.info || this.info.version != meta_data.version) && meta_data.mimeType !== "application/vnd.google-apps.folder")
|
||||||
|
{
|
||||||
|
await VFS.mkdirAll([
|
||||||
|
"home://.gdv_cache",
|
||||||
|
`home://.gdv_cache/${meta_data.id}`
|
||||||
|
], true);
|
||||||
|
let copy = `home://.gdv_cache/${meta_data.id}/${meta_data.version}.${meta_data.fullFileExtension}`.asFileHandle();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
let r = await copy.onready();
|
||||||
|
}
|
||||||
|
catch(e1)
|
||||||
|
{
|
||||||
|
await `home://.gdv_cache/${meta_data.id}`.asFileHandle().remove();
|
||||||
|
await VFS.mkdirAll([`home://.gdv_cache/${meta_data.id}`]);
|
||||||
|
let r = await this.load(gapi.client.drive.files.get({
|
||||||
|
fileId: meta_data.id,
|
||||||
|
alt: 'media'
|
||||||
|
}));
|
||||||
|
if (!r.body) {
|
||||||
|
throw new Error(__("VFS cannot download file : {0}", this.path).__());
|
||||||
|
}
|
||||||
|
|
||||||
|
copy.cache = new Blob([r.body.asUint8Array()], { type: "octet/stream" });
|
||||||
|
await copy.write(meta_data.mimeType);
|
||||||
|
}
|
||||||
|
this.local_copy = copy;
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(e)
|
||||||
|
{
|
||||||
|
OS.announcer.oserror(e.toString(), e);
|
||||||
|
reject(__e(e));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
meta(): Promise<RequestResult> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try{
|
||||||
|
await this.oninit();
|
||||||
|
if (G_CACHE[this.path]) { this.gid = G_CACHE[this.path].id; };
|
||||||
|
if(this.gid)
|
||||||
|
{
|
||||||
|
let ret = await this.load(gapi.client.drive.files.get({
|
||||||
|
fileId: this.gid,
|
||||||
|
fields: this.fields()
|
||||||
|
}));
|
||||||
|
if (ret.result) {
|
||||||
|
ret.result.mime = ret.result.mimeType;
|
||||||
|
await this.load(this.sync(ret.result));
|
||||||
|
resolve(ret);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Error(__("VFS cannot get meta data for {0}", this.gid).__());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const fp = this.parent().asFileHandle();
|
||||||
|
let d = await fp.meta();
|
||||||
|
const file: any = d.result;
|
||||||
|
G_CACHE[fp.path] = { id: file.id, mime: file.mimeType };
|
||||||
|
let r = await this.load(gapi.client.drive.files.list({
|
||||||
|
q: `name = '${this.basename}' and '${file.id}' in parents and trashed = false`,
|
||||||
|
fields: `files(${this.fields()})`
|
||||||
|
}));
|
||||||
|
if (!r.result.files || !(r.result.files.length > 0)) {
|
||||||
|
throw new Error(__("VFS cannot get meta data for {0}", this.path).__());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
G_CACHE[this.path] = { id: r.result.files[0].id, mime: r.result.files[0].mimeType };
|
||||||
|
r.result.files[0].mime = r.result.files[0].mimeType;
|
||||||
|
this.gid = G_CACHE[this.path].id;
|
||||||
|
await this.load(this.sync(r.result.files[0]));
|
||||||
|
resolve({ result: r.result.files[0], error: false});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(e)
|
||||||
|
{
|
||||||
|
OS.announcer.oserror(e.toString(), e);
|
||||||
|
reject(__e(e));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private oninit(): Promise<any> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
const fn = async function(r: boolean) {
|
||||||
|
if (r) { return resolve(true); }
|
||||||
|
// perform the login
|
||||||
|
G_CACHE = {"gdv://":{ id: "root", mime: 'dir' } };
|
||||||
|
try {
|
||||||
|
let ret = await gapi.auth2.getAuthInstance().signIn();
|
||||||
|
resolve(ret);
|
||||||
|
}
|
||||||
|
catch(e)
|
||||||
|
{
|
||||||
|
reject(__e(e));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
if(!GoogleDriveHandle.API_META)
|
||||||
|
{
|
||||||
|
throw new Error(__("No GAPI meta found").__());
|
||||||
|
}
|
||||||
|
if(!API.libready(GoogleDriveHandle.API_META.apilink))
|
||||||
|
{
|
||||||
|
await this.load(API.requires(GoogleDriveHandle.API_META.apilink, false));
|
||||||
|
// load the api
|
||||||
|
await this.load(new Promise((res,rej) => {
|
||||||
|
gapi.load('client:auth2', res);
|
||||||
|
}));
|
||||||
|
await this.load(gapi.client.init({
|
||||||
|
apiKey: GoogleDriveHandle.API_META.API_KEY,
|
||||||
|
clientId: GoogleDriveHandle.API_META.CLIENT_ID,
|
||||||
|
discoveryDocs: GoogleDriveHandle.API_META.DISCOVERY_DOCS,
|
||||||
|
scope: GoogleDriveHandle.API_META.SCOPES
|
||||||
|
}));
|
||||||
|
gapi.auth2.getAuthInstance().isSignedIn.listen(r => fn(r));
|
||||||
|
let ret = await GUI.openDialog("YesNoDialog", {
|
||||||
|
title: __("Authentication"),
|
||||||
|
text: __("Would you like to login to GoogleDrive?")
|
||||||
|
});
|
||||||
|
if(!ret)
|
||||||
|
{
|
||||||
|
throw new Error(__("User abort the authentication").__());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fn(gapi.auth2.getAuthInstance().isSignedIn.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gapi.auth2.getAuthInstance().isSignedIn.listen(r => fn(r));
|
||||||
|
fn(gapi.auth2.getAuthInstance().isSignedIn.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
OS.announcer.oserror(e.toString(), e);
|
||||||
|
reject(__e(e));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getlink() {
|
||||||
|
if (this.local_copy) { return this.local_copy.getlink(); }
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private child(name: string): string
|
||||||
|
{
|
||||||
|
if(this.isFolder())
|
||||||
|
return `${this.path}/${name}`
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Low level protocol-specific read operation
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @param {string} t data type, see [[read]]
|
||||||
|
* @returns {Promise<RequestResult>}
|
||||||
|
* @memberof BaseFileHandle
|
||||||
|
*/
|
||||||
|
protected _rd(t: string): Promise<RequestResult> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try{
|
||||||
|
if(!this.info.id)
|
||||||
|
{
|
||||||
|
throw new Error(__("File ID is not valid").__());
|
||||||
|
}
|
||||||
|
if(this.isFolder())
|
||||||
|
{
|
||||||
|
let r = await this.load(gapi.client.drive.files.list({
|
||||||
|
q: `'${this.info.id}' in parents and trashed = false`,
|
||||||
|
fields: `files(${this.fields()})`
|
||||||
|
}));
|
||||||
|
if(!r.result.files)
|
||||||
|
{
|
||||||
|
throw new Error(__("File {0} not found", this.info.id).__());
|
||||||
|
}
|
||||||
|
for (let file of r.result.files) {
|
||||||
|
file.path = this.child(file.name);
|
||||||
|
file.mime = file.mimeType;
|
||||||
|
file.filename = file.name;
|
||||||
|
file.type = "file";
|
||||||
|
file.gid = file.id;
|
||||||
|
if (file.mimeType === "application/vnd.google-apps.folder") {
|
||||||
|
file.mime = "dir";
|
||||||
|
file.type = "dir";
|
||||||
|
file.size = 0;
|
||||||
|
}
|
||||||
|
G_CACHE[file.path] = { id: file.gid, mime: file.mime };
|
||||||
|
}
|
||||||
|
resolve({ result: r.result.files, error: false});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!this.local_copy)
|
||||||
|
{
|
||||||
|
throw new Error(__("Cannot find local copy of file; {0}", this.path).__());
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
let r = await this.load(gapi.client.drive.files.get({
|
||||||
|
fileId: this.info.id,
|
||||||
|
alt: 'media'
|
||||||
|
}));
|
||||||
|
if (t !== "binary") {
|
||||||
|
resolve(r.body);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resolve(r.body.asUint8Array());
|
||||||
|
}*/
|
||||||
|
let r = await this.local_copy.read(t);
|
||||||
|
resolve(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(e)
|
||||||
|
{
|
||||||
|
OS.announcer.oserror(e.toString(), e);
|
||||||
|
reject(__e(e));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private save(gid: string, t: string): Promise<any>
|
||||||
|
{
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const user = gapi.auth2.getAuthInstance().currentUser.get();
|
||||||
|
const oauthToken = user.getAuthResponse().access_token;
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
const url = __(GoogleDriveHandle.API_META.uploadlink,gid).__();
|
||||||
|
xhr.open('PATCH', url);
|
||||||
|
xhr.setRequestHeader('Authorization', 'Bearer ' + oauthToken);
|
||||||
|
xhr.setRequestHeader('Content-Type', t);
|
||||||
|
xhr.setRequestHeader('Content-Encoding', 'base64');
|
||||||
|
xhr.setRequestHeader('Content-Transfer-Encoding', 'base64');
|
||||||
|
let error = (e:Error) => {
|
||||||
|
OS.announcer.oserror(__("VFS cannot save : {0}", this.path), e);
|
||||||
|
return reject(e);
|
||||||
|
};
|
||||||
|
xhr.onreadystatechange = () => {
|
||||||
|
if ( xhr.readyState === 4 ) {
|
||||||
|
if ( xhr.status === 200 ) {
|
||||||
|
return resolve({ result: JSON.parse(xhr.responseText), error: false});
|
||||||
|
} else {
|
||||||
|
error(OS.API.throwe("OS.VFS"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr.onerror = () => error(OS.API.throwe("OS.VFS"));
|
||||||
|
let data = this.cache;
|
||||||
|
if (t !== "base64") {
|
||||||
|
data = await this.b64(t);
|
||||||
|
}
|
||||||
|
xhr.send(data.replace(/^data:[^;]+;base64,/g, ""));
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
catch(e)
|
||||||
|
{
|
||||||
|
reject(__e(e));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Low level protocol-specific write operation
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @param {string} t data type, see [[write]]
|
||||||
|
* @param {*} [d]
|
||||||
|
* @returns {Promise<RequestResult>}
|
||||||
|
* @memberof BaseFileHandle
|
||||||
|
*/
|
||||||
|
protected _wr(t: string, d?: any): Promise<RequestResult> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try{
|
||||||
|
var gid = undefined;
|
||||||
|
if (G_CACHE[this.path]) {
|
||||||
|
gid = G_CACHE[this.path].id;
|
||||||
|
}
|
||||||
|
if (gid) {
|
||||||
|
resolve(await this.load(this.save(gid, t)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const dir = this.parent().asFileHandle();
|
||||||
|
await dir.onready();
|
||||||
|
const meta = {
|
||||||
|
name: this.basename,
|
||||||
|
mimeType: t,
|
||||||
|
parents: [dir.info.id]
|
||||||
|
};
|
||||||
|
|
||||||
|
let r = await this.load(gapi.client.drive.files.create({
|
||||||
|
resource: meta,
|
||||||
|
fields: 'id'
|
||||||
|
}));
|
||||||
|
if (!r || !r.result) {
|
||||||
|
throw new Error(__("VFS cannot write : {0}", this.path).__());
|
||||||
|
}
|
||||||
|
G_CACHE[this.path] = { id: r.result.id, mime: t };
|
||||||
|
resolve(this.load(this.save(r.result.id, t)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(e)
|
||||||
|
{
|
||||||
|
OS.announcer.oserror(e.toString(), e);
|
||||||
|
reject(__e(e));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Low level protocol-specific sub-directory creation
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @param {string} d sub directory name
|
||||||
|
* @returns {Promise<RequestResult>}
|
||||||
|
* @memberof BaseFileHandle
|
||||||
|
*/
|
||||||
|
protected _mk(d: string): Promise<RequestResult> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!this.isFolder()) {
|
||||||
|
throw new Error(__("{0} is not a directory", this.path).__());
|
||||||
|
}
|
||||||
|
var meta = {
|
||||||
|
name: d,
|
||||||
|
parents: [this.info.id],
|
||||||
|
mimeType: 'application/vnd.google-apps.folder'
|
||||||
|
};
|
||||||
|
let r = await this.load(gapi.client.drive.files.create({
|
||||||
|
resource: meta,
|
||||||
|
fields: 'id'
|
||||||
|
}));
|
||||||
|
if (!r || !r.result) {
|
||||||
|
throw new Error(__("VFS cannot create : {0}", d).__());
|
||||||
|
}
|
||||||
|
G_CACHE[this.child(d)] = { id: r.result.id, mime: "dir" };
|
||||||
|
resolve(r);
|
||||||
|
}
|
||||||
|
catch(e)
|
||||||
|
{
|
||||||
|
OS.announcer.oserror(e.toString(), e);
|
||||||
|
reject(__e(e));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Low level protocol-specific delete operation
|
||||||
|
*
|
||||||
|
* @returns {Promise<RequestResult>}
|
||||||
|
* @memberof BaseFileHandle
|
||||||
|
*/
|
||||||
|
protected _rm(): Promise<RequestResult> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try{
|
||||||
|
if (!this.info.id) {
|
||||||
|
throw new Error(__("Cannot identify file id of {0}", this.path).__());
|
||||||
|
}
|
||||||
|
let r = await this.load(gapi.client.drive.files.delete({
|
||||||
|
fileId: this.info.id
|
||||||
|
}));
|
||||||
|
if (!r) {
|
||||||
|
throw new Error(__("VFS cannot delete : {0}", this.path).__());
|
||||||
|
}
|
||||||
|
G_CACHE[this.path] = null;
|
||||||
|
delete G_CACHE[this.path];
|
||||||
|
resolve({ result: true, error: false});
|
||||||
|
}
|
||||||
|
catch(e)
|
||||||
|
{
|
||||||
|
OS.announcer.oserror(e.toString(), e);
|
||||||
|
reject(__e(e));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Low level protocol-specific move operation
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @param {string} d
|
||||||
|
* @returns {Promise<RequestResult>}
|
||||||
|
* @memberof BaseFileHandle
|
||||||
|
*/
|
||||||
|
protected _mv(d: string): Promise<RequestResult> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
var dest = d.asFileHandle().parent().asFileHandle();
|
||||||
|
await dest.onready();
|
||||||
|
const previousParents = this.info.parents.join(',');
|
||||||
|
let r = await this.load(gapi.client.drive.files.update({
|
||||||
|
fileId: this.info.id,
|
||||||
|
addParents: dest.info.id,
|
||||||
|
removeParents: previousParents,
|
||||||
|
fields: "id"
|
||||||
|
}));
|
||||||
|
if (!r) {
|
||||||
|
throw new Error(__("VFS cannot move : {0}", this.path).__());
|
||||||
|
}
|
||||||
|
resolve(r);
|
||||||
|
}
|
||||||
|
catch(e)
|
||||||
|
{
|
||||||
|
OS.announcer.oserror(e.toString(), e);
|
||||||
|
reject(__e(e));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Low level protocol-specific upload operation
|
||||||
|
*
|
||||||
|
* @returns {Promise<RequestResult>}
|
||||||
|
* @memberof BaseFileHandle
|
||||||
|
*/
|
||||||
|
protected _up(): Promise<RequestResult> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try{
|
||||||
|
if (!this.isFolder()) {
|
||||||
|
throw new Error(__("Target file should be a folder").__());
|
||||||
|
}
|
||||||
|
var o = ($('<input>')).attr('type', 'file').css("display", "none");
|
||||||
|
o.on("change", async () => {
|
||||||
|
//Ant.OS.API.loading q, p
|
||||||
|
const fo = (o[0] as HTMLInputElement).files[0];
|
||||||
|
const file = (this.child(fo.name)).asFileHandle();
|
||||||
|
file.cache = fo;
|
||||||
|
let ret = await this.load(file.write(fo.type));
|
||||||
|
return o.remove();
|
||||||
|
resolve(ret);
|
||||||
|
});
|
||||||
|
o.trigger("click");
|
||||||
|
}
|
||||||
|
catch(e)
|
||||||
|
{
|
||||||
|
OS.announcer.oserror(e.toString(), e);
|
||||||
|
reject(__e(e));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Low level protocol-specific download operation
|
||||||
|
*
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @memberof BaseFileHandle
|
||||||
|
*/
|
||||||
|
protected _down(): Promise<any> {
|
||||||
|
return new Promise(async (resolve,reject) => {
|
||||||
|
try {
|
||||||
|
let r = await this.load(gapi.client.drive.files.get({
|
||||||
|
fileId: this.info.id,
|
||||||
|
alt: 'media'
|
||||||
|
}));
|
||||||
|
if (!r.body) {
|
||||||
|
throw new Error(__("VFS cannot download file : {0}", this.path).__());
|
||||||
|
}
|
||||||
|
let bs = [];
|
||||||
|
for (let i = 0, end = r.body.length - 1, asc = 0 <= end; asc ? i <= end : i >= end; asc ? i++ : i--) {
|
||||||
|
bs.push(r.body.charCodeAt(i));
|
||||||
|
}
|
||||||
|
let bytes = new Uint8Array(bs);
|
||||||
|
const blob = new Blob([bytes], { type: "octet/stream" });
|
||||||
|
OS.API.saveblob(this.basename, blob);
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
catch(e)
|
||||||
|
{
|
||||||
|
OS.announcer.oserror(e.toString(), e);
|
||||||
|
reject(__e(e));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GoogleDriveHandle.API_META = {
|
||||||
|
CLIENT_ID: "1006507170703-l322pfkrhf9cgta4l4jh2p8ughtc14id.apps.googleusercontent.com",
|
||||||
|
API_KEY: "AIzaSyBZhM5KbARvT10acWC8JQKlRn2WbSsmfLc",
|
||||||
|
apilink: "https://apis.google.com/js/api.js",
|
||||||
|
DISCOVERY_DOCS: [
|
||||||
|
"https://www.googleapis.com/discovery/v1/apis/drive/v3/rest",
|
||||||
|
],
|
||||||
|
SCOPES: "https://www.googleapis.com/auth/drive",
|
||||||
|
uploadlink: "https://www.googleapis.com/upload/drive/v3/files/{0}?uploadType=media",
|
||||||
|
logout: "https://www.google.com/accounts/Logout"
|
||||||
|
};
|
||||||
|
|
||||||
|
register("^gdv$", GoogleDriveHandle);
|
||||||
|
|
||||||
|
API.onsearch("Google Drive", function(t) {
|
||||||
|
const arr = [];
|
||||||
|
const term = new RegExp(t, "i");
|
||||||
|
for (let k in G_CACHE) {
|
||||||
|
const v = G_CACHE[k];
|
||||||
|
if ((k.match(term)) || (v && v.mime.match(term))) {
|
||||||
|
const file = k.asFileHandle() as any;
|
||||||
|
file.text = file.basename;
|
||||||
|
file.mime = v.mime;
|
||||||
|
file.iconclass = "fa fa-file";
|
||||||
|
if (file.mime === "dir") { file.iconclass = "fa fa-folder"; }
|
||||||
|
file.complex = true;
|
||||||
|
file.detail = [{ text: file.path }];
|
||||||
|
arr.push(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FIXME: proper way to logout
|
||||||
|
*/
|
||||||
|
OS.onexit("cleanUpGoogleDrive", function() {
|
||||||
|
return new Promise(async (resolve, reject) =>{
|
||||||
|
try{
|
||||||
|
await "home://.gdv_cache".asFileHandle().remove();
|
||||||
|
G_CACHE = { "gdv://": { id: "root", mime: 'dir' } };
|
||||||
|
if (!Ant.OS.API.libready(Ant.OS.setting.VFS.gdrive.apilink))
|
||||||
|
{
|
||||||
|
return resolve(true);
|
||||||
|
}
|
||||||
|
const auth2 = gapi.auth2.getAuthInstance();
|
||||||
|
if (!auth2) {
|
||||||
|
throw new Error(__("Unable to get OATH instance").__());
|
||||||
|
}
|
||||||
|
if (auth2.isSignedIn.get()) {
|
||||||
|
$('<iframe/>', {
|
||||||
|
src: GoogleDriveHandle.API_META.logout,
|
||||||
|
frameborder: 0,
|
||||||
|
onload() {
|
||||||
|
//console.log("disconnect")
|
||||||
|
return auth2.disconnect();
|
||||||
|
}
|
||||||
|
//$(this).remove()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
catch(e){
|
||||||
|
console.log(e);
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
vfsx/package.json
Normal file
39
vfsx/package.json
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"pkgname": "vfsx",
|
||||||
|
"name": "AntOS VFS handles",
|
||||||
|
"description": "AntOS VFS handles for various file protocols which are not included by default int core release",
|
||||||
|
"info": {
|
||||||
|
"author": "Dany LE",
|
||||||
|
"email": "mrsang@iohub.dev"
|
||||||
|
},
|
||||||
|
"version": "0.1.0-b",
|
||||||
|
"category": "Library",
|
||||||
|
"iconclass": "fa fa-cog",
|
||||||
|
"mimes": [
|
||||||
|
"none"
|
||||||
|
],
|
||||||
|
"dependencies": [],
|
||||||
|
"locale": {},
|
||||||
|
"locales": {
|
||||||
|
"en_GB": {
|
||||||
|
"Unknown API setting for GAPI": "Unknown API setting for GAPI",
|
||||||
|
"VFS cannot download file : {0}": "VFS cannot download file : {0}",
|
||||||
|
"VFS cannot get meta data for {0}": "VFS cannot get meta data for {0}",
|
||||||
|
"No GAPI meta found": "No GAPI meta found",
|
||||||
|
"Authentication": "Authentication",
|
||||||
|
"Would you like to login to GoogleDrive?": "Would you like to login to GoogleDrive?",
|
||||||
|
"User abort the authentication": "User abort the authentication",
|
||||||
|
"File ID is not valid": "File ID is not valid",
|
||||||
|
"File {0} not found": "File {0} not found",
|
||||||
|
"Cannot find local copy of file; {0}": "Cannot find local copy of file; {0}",
|
||||||
|
"VFS cannot save : {0}": "VFS cannot save : {0}",
|
||||||
|
"VFS cannot write : {0}": "VFS cannot write : {0}",
|
||||||
|
"{0} is not a directory": "{0} is not a directory",
|
||||||
|
"VFS cannot create : {0}": "VFS cannot create : {0}",
|
||||||
|
"Cannot identify file id of {0}": "Cannot identify file id of {0}",
|
||||||
|
"VFS cannot delete : {0}": "VFS cannot delete : {0}",
|
||||||
|
"VFS cannot move : {0}": "VFS cannot move : {0}",
|
||||||
|
"Target file should be a folder": "Target file should be a folder"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user