add tunnel plugin package

This commit is contained in:
Dany LE 2021-11-28 14:10:21 +01:00
parent 0df49e387c
commit 031f78c926
19 changed files with 1484 additions and 7 deletions

View File

@ -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

View File

@ -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<string>}
* @memberof BroadcastGroup
*/
users: Set<string>;
/**
* 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<string>();
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<BroadcastGroup>}
* @memberof BroadcastManager
*/
private pendings: GenericObject<BroadcastGroup>;
/**
* 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<any>) => {
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<any>}
* @memberof BroadcastManager
*/
private setup(): Promise<any> {
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);
}
}
}

View File

@ -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"
}
}
]
}
}
}

View File

@ -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

519
AntunnelPlugins/build/debug/main.d.ts vendored Normal file
View File

@ -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<string>}
* @memberof BroadcastGroup
*/
users: Set<string>;
/**
* 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<BroadcastGroup>}
* @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<any>}
* @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;
}
}

View File

@ -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={}));

View File

@ -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": {}
}

Binary file not shown.

272
AntunnelPlugins/main.ts Normal file
View File

@ -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;
}

View File

@ -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": {}
}

View File

@ -0,0 +1,3 @@
<afx-app-window apptitle="AntunnelPlugins" width="500" height="400" data-id="AntunnelPlugins">
<afx-hbox ></afx-hbox>
</afx-app-window>

View File

@ -2,6 +2,7 @@
AntOSDK: development API for AntOS based applications/projects AntOSDK: development API for AntOS based applications/projects
## Change logs ## 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.11: Update AntOS API v1.2.1
- 0.0.10: fix binary readfile bug - 0.0.10: fix binary readfile bug
- 0.0.9: Fix locale gen bug - 0.0.9: Fix locale gen bug

View File

@ -2,6 +2,7 @@
AntOSDK: development API for AntOS based applications/projects AntOSDK: development API for AntOS based applications/projects
## Change logs ## 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.11: Update AntOS API v1.2.1
- 0.0.10: fix binary readfile bug - 0.0.10: fix binary readfile bug
- 0.0.9: Fix locale gen bug - 0.0.9: Fix locale gen bug

View File

@ -89,11 +89,21 @@ class TSJob extends AntOSDKBaseJob {
useCaseSensitiveFileNames: () => true, useCaseSensitiveFileNames: () => true,
writeFile: (path, data) => js_code = `${js_code}\n${data}` writeFile: (path, data) => js_code = `${js_code}\n${data}`
}; };
const program = ts.createProgram(files, { const compile_options = {
"target": "es6", "target": "es6",
"skipLibCheck": true, "skipLibCheck": true,
"downlevelIteration": 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 result = program.emit();
const diagnostics = result.diagnostics.concat((ts.getPreEmitDiagnostics(program))); const diagnostics = result.diagnostics.concat((ts.getPreEmitDiagnostics(program)));
const errors = []; const errors = [];

View File

@ -7,7 +7,7 @@
"author": "Xuan Sang LE", "author": "Xuan Sang LE",
"email": "mrsang@iohub.dev" "email": "mrsang@iohub.dev"
}, },
"version": "0.0.11-a", "version": "0.0.12-a",
"category": "Development", "category": "Development",
"iconclass": "fa fa-cog", "iconclass": "fa fa-cog",
"mimes": [ "mimes": [

View File

@ -89,11 +89,21 @@ class TSJob extends AntOSDKBaseJob {
useCaseSensitiveFileNames: () => true, useCaseSensitiveFileNames: () => true,
writeFile: (path, data) => js_code = `${js_code}\n${data}` writeFile: (path, data) => js_code = `${js_code}\n${data}`
}; };
const program = ts.createProgram(files, { const compile_options = {
"target": "es6", "target": "es6",
"skipLibCheck": true, "skipLibCheck": true,
"downlevelIteration": 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 result = program.emit();
const diagnostics = result.diagnostics.concat((ts.getPreEmitDiagnostics(program))); const diagnostics = result.diagnostics.concat((ts.getPreEmitDiagnostics(program)));
const errors = []; const errors = [];

View File

@ -7,7 +7,7 @@
"author": "Xuan Sang LE", "author": "Xuan Sang LE",
"email": "mrsang@iohub.dev" "email": "mrsang@iohub.dev"
}, },
"version": "0.0.11-a", "version": "0.0.12-a",
"category": "Development", "category": "Development",
"iconclass": "fa fa-cog", "iconclass": "fa fa-cog",
"mimes": [ "mimes": [

View File

@ -59,6 +59,16 @@
"dependencies": [], "dependencies": [],
"download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/Antunnel/build/release/Antunnel.zip" "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", "pkgname": "Archive",
"name": "Archive", "name": "Archive",
@ -195,7 +205,7 @@
"description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libantosdk/README.md", "description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libantosdk/README.md",
"category": "Development", "category": "Development",
"author": "Xuan Sang LE", "author": "Xuan Sang LE",
"version": "0.0.11-a", "version": "0.0.12-a",
"dependencies": [], "dependencies": [],
"download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libantosdk/build/release/libantosdk.zip" "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libantosdk/build/release/libantosdk.zip"
}, },