mirror of
https://github.com/antos-rde/antosdk-apps.git
synced 2025-07-13 06:04:26 +02:00
add new package
This commit is contained in:
5
Antunnel/README.md
Normal file
5
Antunnel/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Antunnel
|
||||
|
||||
`Antunnel` is a client side API that allows AntOS applications to
|
||||
talk to server side applications via the [`antd-tunnel-pligin`](https://github.com/lxsang/antd-tunnel-plugin) plugin
|
||||
using a single websocket API.
|
5
Antunnel/build/debug/README.md
Normal file
5
Antunnel/build/debug/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Antunnel
|
||||
|
||||
`Antunnel` is a client side API that allows AntOS applications to
|
||||
talk to server side applications via the [`antd-tunnel-pligin`](https://github.com/lxsang/antd-tunnel-plugin) plugin
|
||||
using a single websocket API.
|
1
Antunnel/build/debug/main.js
Normal file
1
Antunnel/build/debug/main.js
Normal file
File diff suppressed because one or more lines are too long
17
Antunnel/build/debug/package.json
Normal file
17
Antunnel/build/debug/package.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"pkgname": "Antunnel",
|
||||
"name":"Antunnel",
|
||||
"services": [
|
||||
"AntunnelService"
|
||||
],
|
||||
"description":"Antunnel API library",
|
||||
"info":{
|
||||
"author": "Xuan Sang LE",
|
||||
"email": "xsang.le@lxsang.me"
|
||||
},
|
||||
"version":"0.1.1-a",
|
||||
"category":"Library",
|
||||
"iconclass":"fa fa-adn",
|
||||
"mimes":["none"],
|
||||
"locale": {}
|
||||
}
|
5
Antunnel/build/debug/scheme.html
Normal file
5
Antunnel/build/debug/scheme.html
Normal file
@ -0,0 +1,5 @@
|
||||
<afx-app-window apptitle="Antunnel" width="500" height="400" data-id="Antunnel">
|
||||
<afx-hbox >
|
||||
<afx-button text="Sub" data-id="btsub"></afx-button>
|
||||
</afx-hbox>
|
||||
</afx-app-window>
|
BIN
Antunnel/build/release/Antunnel.zip
Normal file
BIN
Antunnel/build/release/Antunnel.zip
Normal file
Binary file not shown.
232
Antunnel/coffees/Antunnel.coffee
Normal file
232
Antunnel/coffees/Antunnel.coffee
Normal file
@ -0,0 +1,232 @@
|
||||
|
||||
|
||||
class Msg
|
||||
constructor: () ->
|
||||
@header = {
|
||||
sid: 0,
|
||||
cid: 0,
|
||||
type: 0,
|
||||
size: 0
|
||||
}
|
||||
@data = undefined
|
||||
|
||||
|
||||
as_raw:() ->
|
||||
length = 21 + @header.size
|
||||
arr = new Uint8Array(length)
|
||||
arr.set(Msg.MAGIC_START, 0)
|
||||
arr[4] = @header.type
|
||||
bytes = Msg.bytes_of @header.cid
|
||||
arr.set(bytes,5)
|
||||
bytes = Msg.bytes_of @header.sid
|
||||
arr.set(bytes,9)
|
||||
bytes = Msg.bytes_of @header.size
|
||||
arr.set(bytes,13)
|
||||
if @data
|
||||
arr.set(@data, 17)
|
||||
arr.set(Msg.MAGIC_END, @header.size + 17)
|
||||
arr.buffer
|
||||
|
||||
Msg.decode = (raw) ->
|
||||
new Promise (resolve, reject) ->
|
||||
msg = new Msg()
|
||||
if(Msg.int_from(Msg.MAGIC_START, 0) != Msg.int_from(raw, 0))
|
||||
return reject("Unmatch message begin magic number")
|
||||
msg.header.type = raw[4]
|
||||
msg.header.cid = Msg.int_from(raw, 5)
|
||||
msg.header.sid = Msg.int_from(raw,9)
|
||||
msg.header.size = Msg.int_from(raw, 13)
|
||||
msg.data = raw.slice(17, 17+msg.header.size)
|
||||
if(Msg.int_from(Msg.MAGIC_END, 0) != Msg.int_from(raw, 17+msg.header.size))
|
||||
return reject("Unmatch message end magic number")
|
||||
resolve msg
|
||||
|
||||
|
||||
Msg.bytes_of = (x) ->
|
||||
bytes=new Uint8Array(4)
|
||||
bytes[0]=x & (255)
|
||||
x=x>>8
|
||||
bytes[1]=x & (255)
|
||||
x=x>>8
|
||||
bytes[2]=x & (255)
|
||||
x=x>>8
|
||||
bytes[3]=x & (255)
|
||||
bytes
|
||||
|
||||
Msg.int_from = (bytes, offset) ->
|
||||
(bytes[offset] | (bytes[offset+1]<<8) | (bytes[offset+2]<<16) | (bytes[offset+3] << 24))
|
||||
|
||||
Msg.OK = 0
|
||||
Msg.ERROR = 1
|
||||
Msg.DATA = 6
|
||||
Msg.CLOSE = 5
|
||||
Msg.SUBSCRIBE = 2
|
||||
Msg.UNSUBSCRIBE = 3
|
||||
Msg.CTRL = 7
|
||||
Msg.MAGIC_END = [ 0x41, 0x4e, 0x54, 0x44]
|
||||
Msg.MAGIC_START = [0x44, 0x54, 0x4e, 0x41 ]
|
||||
|
||||
class Subscriber
|
||||
constructor: (@channel) ->
|
||||
@id = undefined
|
||||
@channel_id = undefined
|
||||
@onmessage = undefined
|
||||
@onerror = undefined
|
||||
@onopen = undefined
|
||||
@onclose = undefined
|
||||
@tunnel = undefined
|
||||
@is_opened = false
|
||||
|
||||
send: (type, arr) ->
|
||||
if not @tunnel
|
||||
@onerror "Tunnel is not opened" if @onerror
|
||||
return
|
||||
if not @is_opened
|
||||
@onerror "Channel is not opened yet" if @onerror
|
||||
return
|
||||
|
||||
@tunnel.send @genmsg type, arr
|
||||
|
||||
genmsg: (type, data) ->
|
||||
msg = new Msg()
|
||||
msg.header.sid = @id
|
||||
msg.header.cid = @channel_id
|
||||
msg.header.type = type
|
||||
msg.header.size = if data then data.length else 0
|
||||
msg.data = data
|
||||
msg
|
||||
|
||||
close: (b) ->
|
||||
@is_opened = false
|
||||
return unless @tunnel
|
||||
@tunnel.unsubscribe @, b
|
||||
|
||||
|
||||
class AntunnelApi
|
||||
constructor: (@uri) ->
|
||||
@socket = undefined
|
||||
@pending = {}
|
||||
@subscribers = {}
|
||||
@onclose = undefined
|
||||
|
||||
ready: () ->
|
||||
return new Promise (resolve, reject) =>
|
||||
return reject() if not @uri
|
||||
return resolve() if @socket isnt undefined
|
||||
# connect to the socket
|
||||
console.log "Connect to #{@uri}"
|
||||
@socket = new WebSocket(@uri)
|
||||
@socket.binaryType = 'arraybuffer'
|
||||
@socket.onmessage = (evt) => @process evt
|
||||
@socket.onclose = (evt) =>
|
||||
@socket = undefined
|
||||
for k,v of @pending
|
||||
v.tunnel = undefined
|
||||
v.onclose() if v.onclose
|
||||
|
||||
for k,v of @subscribers
|
||||
v.tunnel = undefined
|
||||
v.is_opened = false
|
||||
v.onclose() if v.onclose
|
||||
|
||||
@pending = {}
|
||||
@subscribe = {}
|
||||
@onclose() if @onclose()
|
||||
@socket.onerror = (evt) =>
|
||||
v.onerror(evt.toString()) for k,v of @pending when v.onerror
|
||||
v.onerror(evt.toString()) for k,v of @subscribers when v.onerror
|
||||
@socket.onopen = (e) => resolve()
|
||||
|
||||
process: (evt) ->
|
||||
Msg.decode(new Uint8Array(evt.data)).then (msg) =>
|
||||
# find the correct subscriber of the data
|
||||
relay_msg = (m, a) =>
|
||||
sub = @pending[m.header.sid]
|
||||
if sub
|
||||
sub[a] m if sub[a]
|
||||
return
|
||||
sub = @subscribers[m.header.sid]
|
||||
if sub
|
||||
sub[a] m if sub[a]
|
||||
switch msg.header.type
|
||||
when Msg.OK
|
||||
# first look for the pending
|
||||
sub = @pending[msg.header.sid]
|
||||
if sub
|
||||
delete @pending[msg.header.sid]
|
||||
sub.id = Msg.int_from(msg.data,0)
|
||||
sub.channel_id = msg.header.cid
|
||||
@subscribers[sub.id] = sub
|
||||
sub.is_opened = true
|
||||
sub.onopen() if sub.onopen
|
||||
else
|
||||
relay_msg msg, "onmessage"
|
||||
|
||||
when Msg.DATA
|
||||
relay_msg msg, "onmessage"
|
||||
|
||||
when Msg.ERROR
|
||||
relay_msg msg, "onerror"
|
||||
|
||||
when Msg.UNSUBSCRIBE
|
||||
sub = @subscribers[msg.header.sid]
|
||||
return unless sub
|
||||
sub.close(true)
|
||||
else
|
||||
console.error "Message of type #{msg.header.type} is unsupported", msg
|
||||
|
||||
.catch (e) =>
|
||||
v.onerror(e) for k,v of @pending when v.onerror
|
||||
v.onerror(e) for k,v of @subscribers when v.onerror
|
||||
|
||||
|
||||
subscribe: (sub) ->
|
||||
@ready().then ()=>
|
||||
# insert it to pending list
|
||||
sub.tunnel = @
|
||||
sub.id = Math.floor(Math.random()*100000) + 1
|
||||
while @subscribers[sub.id] or @pending[sub.id]
|
||||
sub.id = Math.floor(Math.random()*100000) + 1
|
||||
@pending[sub.id] = sub
|
||||
# send request to connect to a channel
|
||||
@send sub.genmsg Msg.SUBSCRIBE, (new TextEncoder()).encode(sub.channel)
|
||||
.catch (e) ->
|
||||
sub.onerror e.toString() if sub.onerror
|
||||
|
||||
unsubscribe: (sub, b) ->
|
||||
@ready().then ()=>
|
||||
return unless @subscribers[sub.id]
|
||||
# insert it to pending list
|
||||
# send request to connect to a channel
|
||||
@send sub.genmsg Msg.UNSUBSCRIBE, undefined if not b
|
||||
sub.onclose() if sub.onclose
|
||||
delete @subscribers[sub.id]
|
||||
sub.tunnel = undefined
|
||||
sub.is_opened = false
|
||||
|
||||
.catch (e) ->
|
||||
sub.onerror e.toString() if sub.onerror
|
||||
|
||||
send: (msg) ->
|
||||
# return unless @subscribers[msg.header.sid]
|
||||
@socket.send msg.as_raw()
|
||||
|
||||
close: () ->
|
||||
console.log "Close connection to #{@uri}"
|
||||
@socket.close() if @socket
|
||||
@onclose() if @onclose()
|
||||
|
||||
W = this
|
||||
W.Antunnel = {
|
||||
tunnel: undefined
|
||||
init: ((url) ->
|
||||
return new Promise (resolve, reject) ->
|
||||
return resolve(W.Antunnel.tunnel) if W.Antunnel.tunnel
|
||||
W.Antunnel.tunnel = new AntunnelApi(url)
|
||||
W.Antunnel.tunnel.onclose = () -> W.Antunnel.tunnel = undefined
|
||||
W.Antunnel.tunnel.ready().then () ->
|
||||
resolve(W.Antunnel.tunnel)
|
||||
.catch (e) -> reject(e)),
|
||||
Subscriber: Subscriber,
|
||||
Msg: Msg
|
||||
}
|
68
Antunnel/coffees/AntunnelService.coffee
Normal file
68
Antunnel/coffees/AntunnelService.coffee
Normal file
@ -0,0 +1,68 @@
|
||||
class AntunnelService extends OS.application.BaseService
|
||||
constructor: (args) ->
|
||||
super "AntunnelService", args
|
||||
@text = __("Tunnel")
|
||||
@iconclass = "fa fa-close"
|
||||
@is_connect = false
|
||||
@nodes = [
|
||||
{text: __("Connect"), id: 1},
|
||||
{text: __("Disconnect"), id: 2},
|
||||
{text: __("Enter uri"), id: 3},
|
||||
{text: __("Exit"), id: 4}
|
||||
]
|
||||
@onchildselect = (e) => @action e
|
||||
|
||||
init: () ->
|
||||
@start() if @systemsetting.system.tunnel_uri
|
||||
@watch 1500, () =>
|
||||
new_status = false
|
||||
new_status = true if Antunnel.tunnel isnt undefined
|
||||
|
||||
return unless new_status isnt @is_connect
|
||||
@is_connect = new_status
|
||||
@iconclass = "fa fa-circle"
|
||||
@iconclass = "fa fa-close" unless @is_connect
|
||||
@update()
|
||||
|
||||
|
||||
action: (e) ->
|
||||
ask = () =>
|
||||
@_gui.openDialog("PromptDialog", {
|
||||
title: __("Tunnel uri"),
|
||||
label: __("Please enter tunnel uri"),
|
||||
value: "wss://localhost/tunnel"
|
||||
})
|
||||
.then (uri) =>
|
||||
return unless uri and uri isnt ""
|
||||
@systemsetting.system.tunnel_uri = uri
|
||||
@start()
|
||||
|
||||
switch e.data.item.data.id
|
||||
when 1
|
||||
return if @is_connect
|
||||
if @systemsetting.system.tunnel_uri
|
||||
@start()
|
||||
else
|
||||
ask()
|
||||
when 2
|
||||
Antunnel.tunnel.close() if Antunnel.tunnel
|
||||
when 3
|
||||
Antunnel.tunnel.close() if Antunnel.tunnel
|
||||
ask()
|
||||
when 4
|
||||
Antunnel.tunnel.close() if Antunnel.tunnel
|
||||
@quit()
|
||||
|
||||
start: () ->
|
||||
return unless @systemsetting.system.tunnel_uri
|
||||
return if Antunnel.tunnel
|
||||
Antunnel.init(@systemsetting.system.tunnel_uri).then (t) =>
|
||||
@notify __("Tunnel now connected to the server at: {0}", @systemsetting.system.tunnel_uri)
|
||||
.catch (e) =>
|
||||
Antunnel.tunnel.close() if Antunnel.tunnel
|
||||
@error __("Unable to connect to the tunnel: {0}", e.toString()), e
|
||||
|
||||
awake: () ->
|
||||
|
||||
|
||||
this.OS.register "AntunnelService", AntunnelService
|
17
Antunnel/package.json
Normal file
17
Antunnel/package.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"pkgname": "Antunnel",
|
||||
"name":"Antunnel",
|
||||
"services": [
|
||||
"AntunnelService"
|
||||
],
|
||||
"description":"Antunnel API library",
|
||||
"info":{
|
||||
"author": "Xuan Sang LE",
|
||||
"email": "xsang.le@lxsang.me"
|
||||
},
|
||||
"version":"0.1.1-a",
|
||||
"category":"Library",
|
||||
"iconclass":"fa fa-adn",
|
||||
"mimes":["none"],
|
||||
"locale": {}
|
||||
}
|
8
Antunnel/project.json
Normal file
8
Antunnel/project.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "Antunnel",
|
||||
"root": "home://workspace/antosdk-apps/Antunnel",
|
||||
"css": [],
|
||||
"javascripts": [],
|
||||
"coffees": ["coffees/Antunnel.coffee", "coffees/AntunnelService.coffee"],
|
||||
"copies": ["package.json", "README.md"]
|
||||
}
|
Reference in New Issue
Block a user