diff --git a/AntunnelPlugins/README.md b/AntunnelPlugins/README.md new file mode 100644 index 0000000..41fe941 --- /dev/null +++ b/AntunnelPlugins/README.md @@ -0,0 +1,7 @@ +# Antunnel Plugins +Aditional Plugins for Antunnel library. +This package provides also the Typescript declaration file for +application Development. + +## Change logs +- v.0.1.0: Antunnel API declaration and broadcast plugin \ No newline at end of file diff --git a/AntunnelPlugins/broadcast.ts b/AntunnelPlugins/broadcast.ts new file mode 100644 index 0000000..76b5de6 --- /dev/null +++ b/AntunnelPlugins/broadcast.ts @@ -0,0 +1,526 @@ +/** + * Broadcast plugin for Antunnel to communication + * with the backend Antunnel broadcast publisher + */ +namespace Antunnel { + /** + * Broadcast control message type + * + * @export + * @enum {number} + */ + export enum BroadcastCTRLType { + SUBSCRIBE = 0x0A, + UNSUBSCRIBE = 0xB, + QUERY = 0xC + } + + /** + * Group state + * + * @export + * @enum {number} + */ + export enum BroadcastGroupState { + INIT, + SUBSCRIBED, + UNSUBSCRIBED + } + + + /** + * Broadcast control message + * + * @export + * @interface BroadcastCTRLMsg + */ + export interface BroadcastCTRLMsg { + + /** + * Message type + * + * @type {BroadcastCTRLType} + * @memberof BroadcastCTRLMsg + */ + type: BroadcastCTRLType; + + /** + * Group name + * + * @type {string} + * @memberof BroadcastCTRLMsg + */ + group?: string; + + /** + * User name + * + * @type {string} + * @memberof BroadcastCTRLMsg + */ + user: string; + + /** + * group id - allocated by backend + * + * @type {number} + * @memberof BroadcastCTRLMsg + */ + id: number; + } + + + /** + * Broadcast group handle + * + * @export + * @class BroadcastGroup + */ + export class BroadcastGroup { + + /** + * Group name + * + * @type {string} + * @memberof BroadcastGroup + */ + groupname: string; + + /** + * Group id allocated by backend + * + * @type {number} + * @memberof BroadcastGroup + */ + id: number; + + /** + * Active users of the group + * + * @type {Set} + * @memberof BroadcastGroup + */ + users: Set; + + /** + * Called when grouped is opened by backend + * + * @memberof BroadcastGroup + */ + onready: () => void; + + /** + * Called whe a message is sent to group + * + * @memberof BroadcastGroup + */ + onmessage: (data: Uint8Array) => void; + + /** + * Called when user added to the group + * + * @memberof BroadcastGroup + */ + onuseradd: (user: string) => void; + + /** + * Called when user is removed from the group + * + * @memberof BroadcastGroup + */ + onuserdel: (user: string) => void; + + /** + * Called when handle owner left the group + * + * @memberof BroadcastGroup + */ + onclose: () => void; + + /** + * Owner of this handle + * + * @type {string} + * @memberof BroadcastGroup + */ + user: string; + + /** + * reference to the attached Broadcast manage + * + * @type {BroadcastManager} + * @memberof BroadcastGroup + */ + mgr: BroadcastManager; + + /** + * Current state of the handle + * + * @type {BroadcastGroupState} + * @memberof BroadcastGroup + */ + state: BroadcastGroupState; + + + /** + * Creates an instance of BroadcastGroup. + * @param {string} name + * @memberof BroadcastGroup + */ + constructor(name: string) { + this.groupname = name; + this.users = new Set(); + this.onmessage = undefined; + this.onready = undefined; + this.onuseradd = undefined; + this.onuserdel = undefined; + this.onclose = undefined; + this.user = OS.setting.user.name; + this.mgr = undefined; + this.state = BroadcastGroupState.INIT; + } + + + /** + * Leave the group + * + * @return {*} {void} + * @memberof BroadcastGroup + */ + close(): void { + if (!this.mgr || !this.id) { + return; + } + this.mgr.unsubscribe(this.id); + } + + + /** + * Query all users in the group + * + * @return {*} {void} + * @memberof BroadcastGroup + */ + refresh(): void { + if (!this.mgr || !this.id) { + return; + } + this.mgr.query(this.id); + } + + /** + * Send a message to the group + * + * @param {Uint8Array} data + * @memberof BroadcastGroup + */ + send(data: Uint8Array): void { + this.mgr.send(this.id, data); + } + } + + + /** + * Broadcast Manager + * Managing all group handles created by the current + * user + * + * @export + * @class BroadcastManager + */ + export class BroadcastManager { + + /** + * Reference to Antunnel subscriber + * + * @private + * @type {SubscriberInterface} + * @memberof BroadcastManager + */ + private sub: SubscriberInterface; + + /** + * channel name + * + * @private + * @type {string} + * @memberof BroadcastManager + */ + private channel: string; + + /** + * Reference to the global tunnel handle + * + * @private + * @type {AntunnelAPI} + * @memberof BroadcastManager + */ + private tunnel: AntunnelAPI; + + /** + * list of all registered group handles + * + * @private + * @type {{[prop: number]: BroadcastGroup}} + * @memberof BroadcastManager + */ + private groups: { [prop: number]: BroadcastGroup }; + + /** + * temporary list of group handles that wait for + * an connection confirmation from the backend + * + * @private + * @type {GenericObject} + * @memberof BroadcastManager + */ + private pendings: GenericObject; + + /** + * Creates an instance of BroadcastManager. + * @param {string} channel + * @memberof BroadcastManager + */ + constructor(channel: string) { + this.sub = undefined; + this.channel = channel; + this.tunnel = undefined; + this.groups = {}; + this.pendings = {}; + } + + /** + * Connect to the broadcast channel + * + * @private + * @param {(d: any)=> void} resolve + * @memberof BroadcastManager + */ + private connect(resolve: (d: any) => void): void { + this.sub = new Subscriber(this.channel); + this.sub.onopen = () => { + OS.announcer.osinfo(__("Subscriber {0}: Connected to the {1} channel", this.sub.id, this.channel)); + resolve(true); + }; + + this.sub.onerror = (e:AntunnelMSG) => { + let err: any = e; + if(e.data) + { + err = new TextDecoder("utf-8").decode(e.data); + } + OS.announcer.oserror( + __("Subscriber {0}: Error from the {1} channel: {2}", + this.sub.id, this.channel, err), undefined); + } + + this.sub.onmessage = (e: GenericObject) => { + if (e.data) { + let gid = Antunnel.Msg.int_from(e.data.slice(0, 4), 0, 4); + let g_handle = this.groups[gid]; + if (!g_handle) + return; + if (g_handle.onmessage) { + g_handle.onmessage(e.data.slice(4)); + } + } + } + this.sub.onctrl = (d) => { + let msg: BroadcastCTRLMsg = { + user: undefined, + group: undefined, + type: d.data[0] as BroadcastCTRLType, + id: undefined + } + switch (msg.type) { + case BroadcastCTRLType.SUBSCRIBE: + case BroadcastCTRLType.UNSUBSCRIBE: + let offset = d.data[1] + 2; + msg.user = new TextDecoder("utf-8").decode(d.data.slice(2, offset)); + msg.id = Antunnel.Msg.int_from(d.data, offset, 4); + offset += 4; + msg.group = new TextDecoder("utf-8").decode(d.data.slice(offset)); + if (msg.type === BroadcastCTRLType.SUBSCRIBE) { + let g_handle = this.pendings[msg.group]; + if (g_handle && g_handle.user === msg.user) { + g_handle.id = msg.id; + g_handle.onready(); + this.pendings[msg.group] = undefined; + delete this.pendings[msg.group]; + this.groups[msg.id] = g_handle; + g_handle.state = BroadcastGroupState.SUBSCRIBED; + } + g_handle = this.groups[msg.id]; + if (!g_handle) { + return; + } + g_handle.users.add(msg.user); + if (g_handle.onuseradd) + g_handle.onuseradd(msg.user); + } + else { + let g_handle = this.groups[msg.id]; + if (!g_handle) { + return; + } + if (g_handle.user === msg.user) { + OS.announcer.osinfo(__("Subcriber {0}: leave group {1}", this.sub.id, msg.group)); + this.groups[msg.id] = undefined; + delete this.groups[msg.id]; + g_handle.state = BroadcastGroupState.UNSUBSCRIBED; + if (g_handle.onclose) + g_handle.onclose(); + } + else { + g_handle.users.delete(msg.user); + if (g_handle.onuserdel) + g_handle.onuserdel(msg.user); + } + } + break; + case BroadcastCTRLType.QUERY: + msg.id = Antunnel.Msg.int_from(d.data, 1, 4); + msg.user = new TextDecoder("utf-8").decode(d.data.slice(5)); + let g_handle = this.groups[msg.id]; + if (!g_handle) + return; + if (!g_handle.users.has(msg.user)) { + g_handle.users.add(msg.user); + if (g_handle.onuseradd) + g_handle.onuseradd(msg.user); + } + break; + default: + break; + } + } + this.sub.onclose = () => { + OS.announcer.osinfo(__("Subscriber {0}: Connection to {1} closed", this.sub.id, this.channel)); + this.sub = undefined; + } + this.tunnel.subscribe(this.sub); + } + + /** + * Perform setup of the manager: + * - Check if Antunnel API is available + * - Connect to the tunnel if the global tunnel does not exists + * - Subscribe to th e broadcast channel if not done + * + * @private + * @return {*} {Promise} + * @memberof BroadcastManager + */ + private setup(): Promise { + return new Promise(async (resolve, reject) => { + try { + if (!Antunnel) { + throw new Error(__("Library not fould: %s", "Antunnel").__()); + } + if (!Antunnel.tunnel) { + await OS.GUI.pushService("Antunnel/AntunnelService"); + let uri = (OS.setting.system as any).tunnel_uri as string; + if (!uri) { + throw new Error(__("Unable to connect to: %s", "Antunnel").__()); + } + await Antunnel.init(uri); + this.tunnel = Antunnel.tunnel; + } + else { + this.tunnel = Antunnel.tunnel; + } + if (!this.sub) { + this.connect(resolve); + } + else { + resolve(true); + } + } + catch (e) { + if (Antunnel.tunnel) + Antunnel.tunnel.close(); + reject(__e(e)); + } + }); + } + + + /** + * Remove a group handle from the manager + * + * @param {number} gid + * @memberof BroadcastManager + */ + unsubscribe(gid: number): void { + let arr = new Uint8Array(5); + arr[0] = BroadcastCTRLType.UNSUBSCRIBE; + arr.set(Antunnel.Msg.bytes_of(gid, 4), 1); + this.sub.send(Antunnel.Msg.CTRL, arr); + } + + + /** + * Query users in the specific group + * + * @param {number} gid group id + * @memberof BroadcastManager + */ + query(gid: number): void { + let arr = new Uint8Array(5); + arr[0] = BroadcastCTRLType.QUERY; + arr.set(Antunnel.Msg.bytes_of(gid, 4), 1); + this.sub.send(Antunnel.Msg.CTRL, arr); + } + + + /** + * Register a group to the manager + * + * @param {BroadcastGroup} group + * @memberof BroadcastManager + */ + subscribe(group: BroadcastGroup): void { + this.setup() + .then((_) => { + let arr = new Uint8Array(group.groupname.length + 1); + arr[0] = BroadcastCTRLType.SUBSCRIBE; + arr.set(new TextEncoder().encode(group.groupname), 1); + this.sub.send(Antunnel.Msg.CTRL, arr); + group.mgr = this; + this.pendings[group.groupname] = group; + }) + .catch((e) => { + OS.announcer.oserror(__("Unable to subscribe to group {0}: {1}", group.groupname, e.toString()), e); + }) + } + + + /** + *CLeanup the manager + * + * @memberof BroadcastManager + */ + teardown(): void { + if (this.sub) { + this.sub.close(); + } + this.groups = {}; + this.pendings = {}; + } + + + /** + * Send a message to a specific group + * + * @param {number} gid + * @param {Uint8Array} data + * @memberof BroadcastManager + */ + send(gid: number, data: Uint8Array): void { + let arr = new Uint8Array(data.length + 4); + arr.set(Antunnel.Msg.bytes_of(gid, 4), 0); + arr.set(data, 4); + this.sub.send(Antunnel.Msg.DATA, arr); + } + } +} \ No newline at end of file diff --git a/AntunnelPlugins/build.json b/AntunnelPlugins/build.json new file mode 100644 index 0000000..13cd03a --- /dev/null +++ b/AntunnelPlugins/build.json @@ -0,0 +1,80 @@ +{ + "name": "AntunnelPlugins", + "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": ["main.ts", "broadcast.ts"], + "dest": "build/debug/main.js" + } + }, + { + "name": "ts-compile", + "data": { + "src": ["main.ts", "broadcast.ts"], + "dest": "build/debug/main.d.ts", + "options": { + "declaration": true, + "emitDeclarationOnly": true + } + } + } + ] + }, + "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": { + "depend": ["clean","build","uglify", "copy"], + "require": ["zip"], + "jobs": [ + { + "name": "zip-mk", + "data": { + "src":"build/debug", + "dest":"build/release/AntunnelPlugins.zip" + } + } + ] + } + } +} \ No newline at end of file diff --git a/AntunnelPlugins/build/debug/README.md b/AntunnelPlugins/build/debug/README.md new file mode 100644 index 0000000..41fe941 --- /dev/null +++ b/AntunnelPlugins/build/debug/README.md @@ -0,0 +1,7 @@ +# Antunnel Plugins +Aditional Plugins for Antunnel library. +This package provides also the Typescript declaration file for +application Development. + +## Change logs +- v.0.1.0: Antunnel API declaration and broadcast plugin \ No newline at end of file diff --git a/AntunnelPlugins/build/debug/main.d.ts b/AntunnelPlugins/build/debug/main.d.ts new file mode 100644 index 0000000..f5e3b07 --- /dev/null +++ b/AntunnelPlugins/build/debug/main.d.ts @@ -0,0 +1,519 @@ + +/** + * This namespace describe the Antunnel API + * used by o ther application + */ +declare namespace Antunnel { + /** + * Tunnel message type + * + * @export + * @enum {number} + */ + enum AntunnelMSGType { + OK = 0, + SUBSCRIBE = 2, + UNSUBSCRIBE = 3, + ERROR = 1, + DATA = 6, + CTRL = 7, + CLOSE = 5, + PING = 8 + } + /** + * Main tunnel core handle API + * + * @export + * @interface AntunnelAPI + */ + interface AntunnelAPI { + /** + * Close the socket connection attached to the + * current handle + * + * @memberof AntunnelAPI + */ + close(): void; + /** + * register a subscriber to the handle + * + * @param {SubscriberInterface} sub + * @memberof AntunnelAPI + */ + subscribe(sub: SubscriberInterface): void; + /** + * Remove a subscriber from the handle + * + * @param {SubscriberInterface} sub + * @param {boolean} b notify the backend ? + * @memberof AntunnelAPI + */ + unsubscribe(sub: SubscriberInterface, b: boolean): void; + } + /** + * Singleton instance to the current core tunnel handle + */ + var tunnel: AntunnelAPI; + /** + * A tunnel frame header + * + * @export + * @interface AntunnelMSGHeader + */ + interface AntunnelMSGHeader { + /** + * Client ID allocated by the backend + * + * @type {number} + * @memberof AntunnelMSGHeader + */ + cid: number; + /** + * Subscriber ID allocated by Antunnel frontend + * + * @type {number} + * @memberof AntunnelMSGHeader + */ + sid: number; + /** + * Payload size + * + * @type {number} + * @memberof AntunnelMSGHeader + */ + size: number; + /** + * Message type + * + * @type {AntunnelMSGType} + * @memberof AntunnelMSGHeader + */ + type: AntunnelMSGType; + } + /** + * Tunnel frame format + * + * @export + * @interface AntunnelMSG + */ + interface AntunnelMSG { + /** + * frame header + * + * @type {AntunnelMSGHeader} + * @memberof AntunnelMSG + */ + header: AntunnelMSGHeader; + /** + * raw data + * + * @type {Uint8Array} + * @memberof AntunnelMSG + */ + data: Uint8Array; + /** + * helper function that convert the + * entire frame to byte array + * + * @memberof AntunnelMSG + */ + as_raw(): void; + } + /** + * Static members of Msg class + * + * @export + * @interface AntunnelMSGMeta + */ + interface AntunnelMSGMeta { + /** + * constructor + */ + new (): AntunnelMSG; + /** + * convert number to array (network byte order) + * + * @param {number} x + * @param {number} [s] + * @return {*} {Uint8Array} + * @memberof AntunnelMSGMeta + */ + bytes_of(x: number, s?: number): Uint8Array; + /** + * convert network byte order array to number + * + * @param {Uint8Array} data + * @param {number} offset + * @param {number} [s] + * @return {*} {number} + * @memberof AntunnelMSGMeta + */ + int_from(data: Uint8Array, offset: number, s?: number): number; + OK: AntunnelMSGType; + ERROR: AntunnelMSGType; + DATA: AntunnelMSGType; + CLOSE: AntunnelMSGType; + SUBSCRIBE: AntunnelMSGType; + UNSUBSCRIBE: AntunnelMSGType; + CTRL: AntunnelMSGType; + PING: AntunnelMSGType; + } + var Msg: AntunnelMSGMeta; + /** + * Interface of a Subscriber class + * + * @export + * @interface SubscriberInterface + */ + interface SubscriberInterface { + /** + * Subscriber ID allocated by Antunnel API + * + * @type {number} + * @memberof SubscriberInterface + */ + id: number; + /** + * Channel ID/ Client ID allocated by backend + * + * @type {number} + * @memberof SubscriberInterface + */ + channel_id: number; + /** + * Called when a channel is opened for + * this subscriber + * + * @memberof SubscriberInterface + */ + onopen: () => void; + /** + * Error handle callback + * + * @memberof SubscriberInterface + */ + onerror: (d: string | AntunnelMSG) => void; + /** + * Message callback + * + * @memberof SubscriberInterface + */ + onmessage: (m: AntunnelMSG) => void; + /** + * Control messqge callback + * + * @memberof SubscriberInterface + */ + onctrl: (m: AntunnelMSG) => void; + /** + * Subscriber close callback + * + * @memberof SubscriberInterface + */ + onclose: () => void; + /** + * Send a message to backend + * + * @memberof SubscriberInterface + */ + send: (t: AntunnelMSGType, arr: Uint8Array) => void; + close: () => void; + } + /** + * Static member of a subscriber + * + * @export + * @interface SubscriberInterfaceMeta + */ + interface SubscriberInterfaceMeta { + new (channel: string): SubscriberInterface; + } + var Subscriber: SubscriberInterfaceMeta; + /** + * Core handle initialization + */ + var init: (u: string) => void; +} + +/** + * Broadcast plugin for Antunnel to communication + * with the backend Antunnel broadcast publisher + */ +declare namespace Antunnel { + /** + * Broadcast control message type + * + * @export + * @enum {number} + */ + enum BroadcastCTRLType { + SUBSCRIBE = 10, + UNSUBSCRIBE = 11, + QUERY = 12 + } + /** + * Group state + * + * @export + * @enum {number} + */ + enum BroadcastGroupState { + INIT = 0, + SUBSCRIBED = 1, + UNSUBSCRIBED = 2 + } + /** + * Broadcast control message + * + * @export + * @interface BroadcastCTRLMsg + */ + interface BroadcastCTRLMsg { + /** + * Message type + * + * @type {BroadcastCTRLType} + * @memberof BroadcastCTRLMsg + */ + type: BroadcastCTRLType; + /** + * Group name + * + * @type {string} + * @memberof BroadcastCTRLMsg + */ + group?: string; + /** + * User name + * + * @type {string} + * @memberof BroadcastCTRLMsg + */ + user: string; + /** + * group id - allocated by backend + * + * @type {number} + * @memberof BroadcastCTRLMsg + */ + id: number; + } + /** + * Broadcast group handle + * + * @export + * @class BroadcastGroup + */ + class BroadcastGroup { + /** + * Group name + * + * @type {string} + * @memberof BroadcastGroup + */ + groupname: string; + /** + * Group id allocated by backend + * + * @type {number} + * @memberof BroadcastGroup + */ + id: number; + /** + * Active users of the group + * + * @type {Set} + * @memberof BroadcastGroup + */ + users: Set; + /** + * Called when grouped is opened by backend + * + * @memberof BroadcastGroup + */ + onready: () => void; + /** + * Called whe a message is sent to group + * + * @memberof BroadcastGroup + */ + onmessage: (data: Uint8Array) => void; + /** + * Called when user added to the group + * + * @memberof BroadcastGroup + */ + onuseradd: (user: string) => void; + /** + * Called when user is removed from the group + * + * @memberof BroadcastGroup + */ + onuserdel: (user: string) => void; + /** + * Called when handle owner left the group + * + * @memberof BroadcastGroup + */ + onclose: () => void; + /** + * Owner of this handle + * + * @type {string} + * @memberof BroadcastGroup + */ + user: string; + /** + * reference to the attached Broadcast manage + * + * @type {BroadcastManager} + * @memberof BroadcastGroup + */ + mgr: BroadcastManager; + /** + * Current state of the handle + * + * @type {BroadcastGroupState} + * @memberof BroadcastGroup + */ + state: BroadcastGroupState; + /** + * Creates an instance of BroadcastGroup. + * @param {string} name + * @memberof BroadcastGroup + */ + constructor(name: string); + /** + * Leave the group + * + * @return {*} {void} + * @memberof BroadcastGroup + */ + close(): void; + /** + * Query all users in the group + * + * @return {*} {void} + * @memberof BroadcastGroup + */ + refresh(): void; + /** + * Send a message to the group + * + * @param {Uint8Array} data + * @memberof BroadcastGroup + */ + send(data: Uint8Array): void; + } + /** + * Broadcast Manager + * Managing all group handles created by the current + * user + * + * @export + * @class BroadcastManager + */ + class BroadcastManager { + /** + * Reference to Antunnel subscriber + * + * @private + * @type {SubscriberInterface} + * @memberof BroadcastManager + */ + private sub; + /** + * channel name + * + * @private + * @type {string} + * @memberof BroadcastManager + */ + private channel; + /** + * Reference to the global tunnel handle + * + * @private + * @type {AntunnelAPI} + * @memberof BroadcastManager + */ + private tunnel; + /** + * list of all registered group handles + * + * @private + * @type {{[prop: number]: BroadcastGroup}} + * @memberof BroadcastManager + */ + private groups; + /** + * temporary list of group handles that wait for + * an connection confirmation from the backend + * + * @private + * @type {GenericObject} + * @memberof BroadcastManager + */ + private pendings; + /** + * Creates an instance of BroadcastManager. + * @param {string} channel + * @memberof BroadcastManager + */ + constructor(channel: string); + /** + * Connect to the broadcast channel + * + * @private + * @param {(d: any)=> void} resolve + * @memberof BroadcastManager + */ + private connect; + /** + * Perform setup of the manager: + * - Check if Antunnel API is available + * - Connect to the tunnel if the global tunnel does not exists + * - Subscribe to th e broadcast channel if not done + * + * @private + * @return {*} {Promise} + * @memberof BroadcastManager + */ + private setup; + /** + * Remove a group handle from the manager + * + * @param {number} gid + * @memberof BroadcastManager + */ + unsubscribe(gid: number): void; + /** + * Query users in the specific group + * + * @param {number} gid group id + * @memberof BroadcastManager + */ + query(gid: number): void; + /** + * Register a group to the manager + * + * @param {BroadcastGroup} group + * @memberof BroadcastManager + */ + subscribe(group: BroadcastGroup): void; + /** + *CLeanup the manager + * + * @memberof BroadcastManager + */ + teardown(): void; + /** + * Send a message to a specific group + * + * @param {number} gid + * @param {Uint8Array} data + * @memberof BroadcastManager + */ + send(gid: number, data: Uint8Array): void; + } +} diff --git a/AntunnelPlugins/build/debug/main.js b/AntunnelPlugins/build/debug/main.js new file mode 100644 index 0000000..06b9b54 --- /dev/null +++ b/AntunnelPlugins/build/debug/main.js @@ -0,0 +1 @@ +var Antunnel;!function(e){let s;!function(e){e[e.OK=0]="OK",e[e.SUBSCRIBE=2]="SUBSCRIBE",e[e.UNSUBSCRIBE=3]="UNSUBSCRIBE",e[e.ERROR=1]="ERROR",e[e.DATA=6]="DATA",e[e.CTRL=7]="CTRL",e[e.CLOSE=5]="CLOSE",e[e.PING=8]="PING"}(s=e.AntunnelMSGType||(e.AntunnelMSGType={}))}(Antunnel||(Antunnel={})),function(e){let s,t;!function(e){e[e.SUBSCRIBE=10]="SUBSCRIBE",e[e.UNSUBSCRIBE=11]="UNSUBSCRIBE",e[e.QUERY=12]="QUERY"}(s=e.BroadcastCTRLType||(e.BroadcastCTRLType={})),function(e){e[e.INIT=0]="INIT",e[e.SUBSCRIBED=1]="SUBSCRIBED",e[e.UNSUBSCRIBED=2]="UNSUBSCRIBED"}(t=e.BroadcastGroupState||(e.BroadcastGroupState={})),e.BroadcastGroup=class{constructor(e){this.groupname=e,this.users=new Set,this.onmessage=void 0,this.onready=void 0,this.onuseradd=void 0,this.onuserdel=void 0,this.onclose=void 0,this.user=OS.setting.user.name,this.mgr=void 0,this.state=t.INIT}close(){this.mgr&&this.id&&this.mgr.unsubscribe(this.id)}refresh(){this.mgr&&this.id&&this.mgr.query(this.id)}send(e){this.mgr.send(this.id,e)}},e.BroadcastManager=class{constructor(e){this.sub=void 0,this.channel=e,this.tunnel=void 0,this.groups={},this.pendings={}}connect(n){this.sub=new e.Subscriber(this.channel),this.sub.onopen=()=>{OS.announcer.osinfo(__("Subscriber {0}: Connected to the {1} channel",this.sub.id,this.channel)),n(!0)},this.sub.onerror=e=>{let s=e;e.data&&(s=new TextDecoder("utf-8").decode(e.data)),OS.announcer.oserror(__("Subscriber {0}: Error from the {1} channel: {2}",this.sub.id,this.channel,s),void 0)},this.sub.onmessage=s=>{if(s.data){let t=e.Msg.int_from(s.data.slice(0,4),0,4),n=this.groups[t];if(!n)return;n.onmessage&&n.onmessage(s.data.slice(4))}},this.sub.onctrl=n=>{let i={user:void 0,group:void 0,type:n.data[0],id:void 0};switch(i.type){case s.SUBSCRIBE:case s.UNSUBSCRIBE:let r=n.data[1]+2;if(i.user=new TextDecoder("utf-8").decode(n.data.slice(2,r)),i.id=e.Msg.int_from(n.data,r,4),r+=4,i.group=new TextDecoder("utf-8").decode(n.data.slice(r)),i.type===s.SUBSCRIBE){let e=this.pendings[i.group];if(e&&e.user===i.user&&(e.id=i.id,e.onready(),this.pendings[i.group]=void 0,delete this.pendings[i.group],this.groups[i.id]=e,e.state=t.SUBSCRIBED),e=this.groups[i.id],!e)return;e.users.add(i.user),e.onuseradd&&e.onuseradd(i.user)}else{let e=this.groups[i.id];if(!e)return;e.user===i.user?(OS.announcer.osinfo(__("Subcriber {0}: leave group {1}",this.sub.id,i.group)),this.groups[i.id]=void 0,delete this.groups[i.id],e.state=t.UNSUBSCRIBED,e.onclose&&e.onclose()):(e.users.delete(i.user),e.onuserdel&&e.onuserdel(i.user))}break;case s.QUERY:i.id=e.Msg.int_from(n.data,1,4),i.user=new TextDecoder("utf-8").decode(n.data.slice(5));let o=this.groups[i.id];if(!o)return;o.users.has(i.user)||(o.users.add(i.user),o.onuseradd&&o.onuseradd(i.user))}},this.sub.onclose=()=>{OS.announcer.osinfo(__("Subscriber {0}: Connection to {1} closed",this.sub.id,this.channel)),this.sub=void 0},this.tunnel.subscribe(this.sub)}setup(){return new Promise(async(s,t)=>{try{if(!e)throw new Error(__("Library not fould: %s","Antunnel").__());if(e.tunnel)this.tunnel=e.tunnel;else{await OS.GUI.pushService("Antunnel/AntunnelService");let s=OS.setting.system.tunnel_uri;if(!s)throw new Error(__("Unable to connect to: %s","Antunnel").__());await e.init(s),this.tunnel=e.tunnel}this.sub?s(!0):this.connect(s)}catch(s){e.tunnel&&e.tunnel.close(),t(__e(s))}})}unsubscribe(t){let n=new Uint8Array(5);n[0]=s.UNSUBSCRIBE,n.set(e.Msg.bytes_of(t,4),1),this.sub.send(e.Msg.CTRL,n)}query(t){let n=new Uint8Array(5);n[0]=s.QUERY,n.set(e.Msg.bytes_of(t,4),1),this.sub.send(e.Msg.CTRL,n)}subscribe(t){this.setup().then(n=>{let i=new Uint8Array(t.groupname.length+1);i[0]=s.SUBSCRIBE,i.set((new TextEncoder).encode(t.groupname),1),this.sub.send(e.Msg.CTRL,i),t.mgr=this,this.pendings[t.groupname]=t}).catch(e=>{OS.announcer.oserror(__("Unable to subscribe to group {0}: {1}",t.groupname,e.toString()),e)})}teardown(){this.sub&&this.sub.close(),this.groups={},this.pendings={}}send(s,t){let n=new Uint8Array(t.length+4);n.set(e.Msg.bytes_of(s,4),0),n.set(t,4),this.sub.send(e.Msg.DATA,n)}}}(Antunnel||(Antunnel={})); \ No newline at end of file diff --git a/AntunnelPlugins/build/debug/package.json b/AntunnelPlugins/build/debug/package.json new file mode 100644 index 0000000..26e6cde --- /dev/null +++ b/AntunnelPlugins/build/debug/package.json @@ -0,0 +1,15 @@ +{ + "pkgname": "AntunnelPlugins", + "name":"Antunnel Plugins", + "description":"Additional plugins for the Antunnel library", + "info":{ + "author": "Dany LE", + "email": "mrsang@iohub.dev" + }, + "version":"0.1.0-a", + "category":"Library", + "iconclass":"fa fa-cog", + "mimes":["none"], + "dependencies":["Antunnel@0.2.0-b"], + "locale": {} +} \ No newline at end of file diff --git a/AntunnelPlugins/build/release/AntunnelPlugins.zip b/AntunnelPlugins/build/release/AntunnelPlugins.zip new file mode 100644 index 0000000..611a61d Binary files /dev/null and b/AntunnelPlugins/build/release/AntunnelPlugins.zip differ diff --git a/AntunnelPlugins/main.ts b/AntunnelPlugins/main.ts new file mode 100644 index 0000000..655a0e7 --- /dev/null +++ b/AntunnelPlugins/main.ts @@ -0,0 +1,272 @@ +/** + * This namespace describe the Antunnel API + * used by o ther application + */ +namespace Antunnel { + + /** + * Tunnel message type + * + * @export + * @enum {number} + */ + export enum AntunnelMSGType { + OK = 0, + SUBSCRIBE = 2, + UNSUBSCRIBE = 3, + ERROR = 1, + DATA = 6, + CTRL = 7, + CLOSE = 5, + PING = 8 + } + + /** + * Main tunnel core handle API + * + * @export + * @interface AntunnelAPI + */ + export interface AntunnelAPI { + + /** + * Close the socket connection attached to the + * current handle + * + * @memberof AntunnelAPI + */ + close(): void; + + /** + * register a subscriber to the handle + * + * @param {SubscriberInterface} sub + * @memberof AntunnelAPI + */ + subscribe(sub: SubscriberInterface): void; + + /** + * Remove a subscriber from the handle + * + * @param {SubscriberInterface} sub + * @param {boolean} b notify the backend ? + * @memberof AntunnelAPI + */ + unsubscribe(sub: SubscriberInterface, b: boolean): void; + } + + /** + * Singleton instance to the current core tunnel handle + */ + export var tunnel: AntunnelAPI; + + + /** + * A tunnel frame header + * + * @export + * @interface AntunnelMSGHeader + */ + export interface AntunnelMSGHeader { + + /** + * Client ID allocated by the backend + * + * @type {number} + * @memberof AntunnelMSGHeader + */ + cid: number; + + /** + * Subscriber ID allocated by Antunnel frontend + * + * @type {number} + * @memberof AntunnelMSGHeader + */ + sid: number; + + /** + * Payload size + * + * @type {number} + * @memberof AntunnelMSGHeader + */ + size: number; + + /** + * Message type + * + * @type {AntunnelMSGType} + * @memberof AntunnelMSGHeader + */ + type: AntunnelMSGType; + } + + + /** + * Tunnel frame format + * + * @export + * @interface AntunnelMSG + */ + export interface AntunnelMSG { + + /** + * frame header + * + * @type {AntunnelMSGHeader} + * @memberof AntunnelMSG + */ + header: AntunnelMSGHeader; + + /** + * raw data + * + * @type {Uint8Array} + * @memberof AntunnelMSG + */ + data: Uint8Array; + + /** + * helper function that convert the + * entire frame to byte array + * + * @memberof AntunnelMSG + */ + as_raw(): void; + } + + + /** + * Static members of Msg class + * + * @export + * @interface AntunnelMSGMeta + */ + export interface AntunnelMSGMeta { + /** + * constructor + */ + new(): AntunnelMSG; + + /** + * convert number to array (network byte order) + * + * @param {number} x + * @param {number} [s] + * @return {*} {Uint8Array} + * @memberof AntunnelMSGMeta + */ + bytes_of(x: number, s?: number): Uint8Array; + + /** + * convert network byte order array to number + * + * @param {Uint8Array} data + * @param {number} offset + * @param {number} [s] + * @return {*} {number} + * @memberof AntunnelMSGMeta + */ + int_from(data: Uint8Array, offset: number, s?: number): number; + + OK: AntunnelMSGType; + ERROR: AntunnelMSGType; + DATA: AntunnelMSGType; + CLOSE: AntunnelMSGType; + SUBSCRIBE: AntunnelMSGType; + UNSUBSCRIBE: AntunnelMSGType; + CTRL: AntunnelMSGType; + PING: AntunnelMSGType; + } + + export var Msg: AntunnelMSGMeta; + + + /** + * Interface of a Subscriber class + * + * @export + * @interface SubscriberInterface + */ + export interface SubscriberInterface { + + /** + * Subscriber ID allocated by Antunnel API + * + * @type {number} + * @memberof SubscriberInterface + */ + id: number; + + /** + * Channel ID/ Client ID allocated by backend + * + * @type {number} + * @memberof SubscriberInterface + */ + channel_id: number; + + /** + * Called when a channel is opened for + * this subscriber + * + * @memberof SubscriberInterface + */ + onopen: () => void; + + /** + * Error handle callback + * + * @memberof SubscriberInterface + */ + onerror: (d: string| AntunnelMSG) => void; + + /** + * Message callback + * + * @memberof SubscriberInterface + */ + onmessage: (m: AntunnelMSG) => void; + + /** + * Control messqge callback + * + * @memberof SubscriberInterface + */ + onctrl: (m: AntunnelMSG) => void; + + /** + * Subscriber close callback + * + * @memberof SubscriberInterface + */ + onclose: () => void; + + /** + * Send a message to backend + * + * @memberof SubscriberInterface + */ + send: (t: AntunnelMSGType, arr: Uint8Array) => void; + close: () => void; + } + + + /** + * Static member of a subscriber + * + * @export + * @interface SubscriberInterfaceMeta + */ + export interface SubscriberInterfaceMeta { + new(channel: string): SubscriberInterface; + } + + export var Subscriber: SubscriberInterfaceMeta; + + /** + * Core handle initialization + */ + export var init: (u: string) => void; +} \ No newline at end of file diff --git a/AntunnelPlugins/package.json b/AntunnelPlugins/package.json new file mode 100644 index 0000000..26e6cde --- /dev/null +++ b/AntunnelPlugins/package.json @@ -0,0 +1,15 @@ +{ + "pkgname": "AntunnelPlugins", + "name":"Antunnel Plugins", + "description":"Additional plugins for the Antunnel library", + "info":{ + "author": "Dany LE", + "email": "mrsang@iohub.dev" + }, + "version":"0.1.0-a", + "category":"Library", + "iconclass":"fa fa-cog", + "mimes":["none"], + "dependencies":["Antunnel@0.2.0-b"], + "locale": {} +} \ No newline at end of file diff --git a/AntunnelPlugins/scheme.html b/AntunnelPlugins/scheme.html new file mode 100644 index 0000000..de7c3ca --- /dev/null +++ b/AntunnelPlugins/scheme.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/libantosdk/README.md b/libantosdk/README.md index eb86c94..43f92c0 100644 --- a/libantosdk/README.md +++ b/libantosdk/README.md @@ -2,6 +2,7 @@ AntOSDK: development API for AntOS based applications/projects ## Change logs +- 0.0.12: TS worker now allows user specific compile options (defined un build file) - 0.0.11: Update AntOS API v1.2.1 - 0.0.10: fix binary readfile bug - 0.0.9: Fix locale gen bug diff --git a/libantosdk/build/debug/README.md b/libantosdk/build/debug/README.md index eb86c94..43f92c0 100644 --- a/libantosdk/build/debug/README.md +++ b/libantosdk/build/debug/README.md @@ -2,6 +2,7 @@ AntOSDK: development API for AntOS based applications/projects ## Change logs +- 0.0.12: TS worker now allows user specific compile options (defined un build file) - 0.0.11: Update AntOS API v1.2.1 - 0.0.10: fix binary readfile bug - 0.0.9: Fix locale gen bug diff --git a/libantosdk/build/debug/core/ts.worker.js b/libantosdk/build/debug/core/ts.worker.js index 3b27bcb..192b77f 100644 --- a/libantosdk/build/debug/core/ts.worker.js +++ b/libantosdk/build/debug/core/ts.worker.js @@ -89,11 +89,21 @@ class TSJob extends AntOSDKBaseJob { useCaseSensitiveFileNames: () => true, writeFile: (path, data) => js_code = `${js_code}\n${data}` }; - const program = ts.createProgram(files, { + const compile_options = { "target": "es6", "skipLibCheck": true, "downlevelIteration": true - }, host); + }; + // Allow user override compile options + if(this.job.data.options) + { + for(let k in this.job.data.options) + { + compile_options[k] = this.job.data.options[k]; + } + } + console.log("TS compile options", compile_options); + const program = ts.createProgram(files,compile_options , host); const result = program.emit(); const diagnostics = result.diagnostics.concat((ts.getPreEmitDiagnostics(program))); const errors = []; diff --git a/libantosdk/build/debug/package.json b/libantosdk/build/debug/package.json index fd5d931..d4123e5 100644 --- a/libantosdk/build/debug/package.json +++ b/libantosdk/build/debug/package.json @@ -7,7 +7,7 @@ "author": "Xuan Sang LE", "email": "mrsang@iohub.dev" }, - "version": "0.0.11-a", + "version": "0.0.12-a", "category": "Development", "iconclass": "fa fa-cog", "mimes": [ diff --git a/libantosdk/build/release/libantosdk.zip b/libantosdk/build/release/libantosdk.zip index ea3ed73..aba6a6d 100644 Binary files a/libantosdk/build/release/libantosdk.zip and b/libantosdk/build/release/libantosdk.zip differ diff --git a/libantosdk/core/ts.worker.js b/libantosdk/core/ts.worker.js index 3b27bcb..192b77f 100644 --- a/libantosdk/core/ts.worker.js +++ b/libantosdk/core/ts.worker.js @@ -89,11 +89,21 @@ class TSJob extends AntOSDKBaseJob { useCaseSensitiveFileNames: () => true, writeFile: (path, data) => js_code = `${js_code}\n${data}` }; - const program = ts.createProgram(files, { + const compile_options = { "target": "es6", "skipLibCheck": true, "downlevelIteration": true - }, host); + }; + // Allow user override compile options + if(this.job.data.options) + { + for(let k in this.job.data.options) + { + compile_options[k] = this.job.data.options[k]; + } + } + console.log("TS compile options", compile_options); + const program = ts.createProgram(files,compile_options , host); const result = program.emit(); const diagnostics = result.diagnostics.concat((ts.getPreEmitDiagnostics(program))); const errors = []; diff --git a/libantosdk/package.json b/libantosdk/package.json index fd5d931..d4123e5 100644 --- a/libantosdk/package.json +++ b/libantosdk/package.json @@ -7,7 +7,7 @@ "author": "Xuan Sang LE", "email": "mrsang@iohub.dev" }, - "version": "0.0.11-a", + "version": "0.0.12-a", "category": "Development", "iconclass": "fa fa-cog", "mimes": [ diff --git a/packages.json b/packages.json index 223b6a7..f023d76 100644 --- a/packages.json +++ b/packages.json @@ -59,6 +59,16 @@ "dependencies": [], "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/Antunnel/build/release/Antunnel.zip" }, + { + "pkgname": "AntunnelPlugins", + "name": "Antunnel Plugins", + "description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/AntunnelPlugins/README.md", + "category": "Library", + "author": "Dany LE", + "version": "0.1.0-a", + "dependencies": ["Antunnel@0.2.0-b"], + "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/AntunnelPlugins/build/release/AntunnelPlugins.zip" + }, { "pkgname": "Archive", "name": "Archive", @@ -195,7 +205,7 @@ "description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libantosdk/README.md", "category": "Development", "author": "Xuan Sang LE", - "version": "0.0.11-a", + "version": "0.0.12-a", "dependencies": [], "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libantosdk/build/release/libantosdk.zip" },