mirror of
https://github.com/antos-rde/antosdk-apps.git
synced 2024-11-07 22:18:29 +01:00
add new package
This commit is contained in:
parent
694afc162d
commit
525badca3f
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"]
|
||||
}
|
@ -245,7 +245,8 @@ class Blogger extends this.OS.application.BaseApplication
|
||||
.then (d) ->
|
||||
console.log "Email sent"
|
||||
}
|
||||
]
|
||||
],
|
||||
|
||||
@bloglist.onlistselect = (e) =>
|
||||
el = @bloglist.selectedItem
|
||||
return unless el
|
||||
|
@ -17,6 +17,15 @@
|
||||
"version": "0.0.6-a",
|
||||
"download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/ActivityMonitor/build/release/ActivityMonitor.zip"
|
||||
},
|
||||
{
|
||||
"pkgname": "Antunnel",
|
||||
"name": "Antunnel",
|
||||
"description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/Antunnel/README.md",
|
||||
"category": "Library",
|
||||
"author": "Xuan Sang LE",
|
||||
"version": "0.1.1-a",
|
||||
"download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/Antunnel/build/release/Antunnel.zip"
|
||||
},
|
||||
{
|
||||
"pkgname": "Archive",
|
||||
"name": "Archive",
|
||||
@ -49,7 +58,7 @@
|
||||
"name": "Clipper",
|
||||
"description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/Clipper/README.md",
|
||||
"category": "Other",
|
||||
"author": "",
|
||||
"author": "Xuan Sang LE",
|
||||
"version": "0.1.2-a",
|
||||
"download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/Clipper/build/release/Clipper.zip"
|
||||
},
|
||||
@ -134,6 +143,15 @@
|
||||
"version": "0.0.4-a",
|
||||
"download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/TinyEditor/build/release/TinyEditor.zip"
|
||||
},
|
||||
{
|
||||
"pkgname": "vTerm",
|
||||
"name": "Virtual Terminal",
|
||||
"description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/vTerm/README.md",
|
||||
"category": "System",
|
||||
"author": "Xuan Sang LE",
|
||||
"version": "0.0.5-a",
|
||||
"download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/vTerm/build/release/vTerm.zip"
|
||||
},
|
||||
{
|
||||
"pkgname": "wTerm",
|
||||
"name": "Terminal",
|
||||
|
12
vTerm/README.md
Normal file
12
vTerm/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
# AntOS Virual Terminal
|
||||
|
||||
Terminal emulator to connect to remote server using AntOS Tunnel plugin.
|
||||
|
||||
Unlike wTerm that uses a dedicated websocket connection for each terminal to
|
||||
communicate with remote terminal session via the Antd **wterm** plugin,
|
||||
VTerm uses only one websocket connection for multiple terminal session
|
||||
thanks to the Antd **tunnel** plugin.
|
||||
|
||||
|
||||
VTerm depends on the server side **tunnel** plugin and the AntOS **Antunnel**
|
||||
client side package
|
12
vTerm/build/debug/README.md
Normal file
12
vTerm/build/debug/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
# AntOS Virual Terminal
|
||||
|
||||
Terminal emulator to connect to remote server using AntOS Tunnel plugin.
|
||||
|
||||
Unlike wTerm that uses a dedicated websocket connection for each terminal to
|
||||
communicate with remote terminal session via the Antd **wterm** plugin,
|
||||
VTerm uses only one websocket connection for multiple terminal session
|
||||
thanks to the Antd **tunnel** plugin.
|
||||
|
||||
|
||||
VTerm depends on the server side **tunnel** plugin and the AntOS **Antunnel**
|
||||
client side package
|
173
vTerm/build/debug/main.css
Normal file
173
vTerm/build/debug/main.css
Normal file
@ -0,0 +1,173 @@
|
||||
|
||||
/**
|
||||
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
||||
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
||||
* https://github.com/chjj/term.js
|
||||
* @license MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* Originally forked from (with the author's permission):
|
||||
* Fabrice Bellard's javascript vt100 for jslinux:
|
||||
* http://bellard.org/jslinux/
|
||||
* Copyright (c) 2011 Fabrice Bellard
|
||||
* The original design remains. The terminal itself
|
||||
* has been extended to include xterm CSI codes, among
|
||||
* other features.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default styles for xterm.js
|
||||
*/
|
||||
|
||||
.xterm {
|
||||
font-feature-settings: "liga" 0;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.xterm.focus,
|
||||
.xterm:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.xterm .xterm-helpers {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
/**
|
||||
* The z-index of the helpers must be higher than the canvases in order for
|
||||
* IMEs to appear on top.
|
||||
*/
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.xterm .xterm-helper-textarea {
|
||||
/*
|
||||
* HACK: to fix IE's blinking cursor
|
||||
* Move textarea out of the screen to the far left, so that the cursor is not visible.
|
||||
*/
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
left: -9999em;
|
||||
top: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
z-index: -5;
|
||||
/** Prevent wrapping so the IME appears against the textarea at the correct position */
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.xterm .composition-view {
|
||||
/* TODO: Composition position got messed up somewhere */
|
||||
background: #000;
|
||||
color: #FFF;
|
||||
display: none;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.xterm .composition-view.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.xterm .xterm-viewport {
|
||||
/* On OS X this is required in order for the scroll bar to appear fully opaque */
|
||||
background-color: #000;
|
||||
overflow-y: scroll;
|
||||
cursor: default;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-screen {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.xterm .xterm-screen canvas {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-scroll-area {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.xterm-char-measure-element {
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -9999em;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.xterm {
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.xterm.enable-mouse-events {
|
||||
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.xterm.xterm-cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.xterm.column-select.focus {
|
||||
/* Column selection mode */
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.xterm .xterm-accessibility,
|
||||
.xterm .xterm-message {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.xterm .live-region {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.xterm-dim {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.xterm-underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
167
vTerm/build/debug/main.js
Normal file
167
vTerm/build/debug/main.js
Normal file
File diff suppressed because one or more lines are too long
22
vTerm/build/debug/package.json
Normal file
22
vTerm/build/debug/package.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"app":"vTerm",
|
||||
"name":"Virtual Terminal",
|
||||
"description":"Access Unix terminal from web",
|
||||
"info":{
|
||||
"author": "Xuan Sang LE",
|
||||
"email": "xsang.le@gmail.com"
|
||||
},
|
||||
"version":"0.0.5-a",
|
||||
"category":"System",
|
||||
"iconclass":"fa fa-terminal",
|
||||
"mimes":["none"],
|
||||
"locales":{
|
||||
"fr_FR": {
|
||||
"Open terminal": "Ouvrir terminal",
|
||||
"Edit": "Modifier",
|
||||
"Please enter terminal URI": "Merci d'entrer l'URI du terminal",
|
||||
"Unable to connect to: {0}": "Impossible de connecter a: {0}",
|
||||
"Terminal connection closed": "Connexion terminal est fermee"
|
||||
}
|
||||
}
|
||||
}
|
5
vTerm/build/debug/scheme.html
Normal file
5
vTerm/build/debug/scheme.html
Normal file
@ -0,0 +1,5 @@
|
||||
<afx-app-window apptitle="__(Terminal)" width="600" height="400">
|
||||
<afx-hbox data-id = "mybox">
|
||||
<div data-id="myterm" ></div>
|
||||
</afx-hbox>
|
||||
</afx-app-window>
|
BIN
vTerm/build/release/vTerm.zip
Normal file
BIN
vTerm/build/release/vTerm.zip
Normal file
Binary file not shown.
BIN
vTerm/build/release/wTerm.zip
Normal file
BIN
vTerm/build/release/wTerm.zip
Normal file
Binary file not shown.
119
vTerm/main.coffee
Normal file
119
vTerm/main.coffee
Normal file
@ -0,0 +1,119 @@
|
||||
# Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
||||
|
||||
# AnTOS Web desktop is is licensed under the GNU General Public
|
||||
# License v3.0, see the LICENCE file for more information
|
||||
|
||||
# This program is free software: you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of
|
||||
# the License, or (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
#along with this program. If not, see https://www.gnu.org/licenses/
|
||||
|
||||
class vTerm extends this.OS.application.BaseApplication
|
||||
constructor: (args) ->
|
||||
super "vTerm", args
|
||||
|
||||
main: () ->
|
||||
@mterm = @find "myterm"
|
||||
@term = new Terminal { cursorBlink: true }
|
||||
@fitAddon = new FitAddon.FitAddon()
|
||||
@term.loadAddon(@fitAddon)
|
||||
@term.setOption('fontSize', '12')
|
||||
@term.open @mterm
|
||||
@term.onKey (d) =>
|
||||
return unless @sub
|
||||
@sub.send Antunnel.Msg.DATA, new TextEncoder("utf-8").encode(d.key)
|
||||
|
||||
@sub = undefined
|
||||
|
||||
@on "focus", () => @term.focus()
|
||||
|
||||
@mterm.contextmenuHandle = (e, m) =>
|
||||
m.items = [
|
||||
{ text: "__(Copy)", id: "copy" },
|
||||
{ text: "__(Paste)", id: "paste"}
|
||||
]
|
||||
m.onmenuselect = (e) =>
|
||||
return unless e
|
||||
@mctxHandle e.data.item.data
|
||||
m.show e
|
||||
@resizeContent()
|
||||
# make desktop menu if not exist
|
||||
@systemsetting.desktop.menu[@name] = { text: "__(Open terminal)", app: "vTerm" } unless @systemsetting.desktop.menu[@name]
|
||||
|
||||
@on "hboxchange", (e) =>
|
||||
@resizeContent()
|
||||
|
||||
if not Antunnel.tunnel
|
||||
@error __("The Antunnel service is not started, please start it first")
|
||||
@_gui.pushService("Antunnel/AntunnelService")
|
||||
.catch (e) =>
|
||||
@error e.toString(), e
|
||||
@quit()
|
||||
else
|
||||
@tunnel = Antunnel.tunnel
|
||||
@openSession()
|
||||
|
||||
mctxHandle: (data) ->
|
||||
switch data.id
|
||||
when "paste"
|
||||
@_api.getClipboard().then (text) =>
|
||||
return unless text and text isnt ""
|
||||
@sub.send Antunnel.Msg.DATA, new TextEncoder("utf-8").encode(text) if @sub
|
||||
.catch (e) => @error __("Unable to paste"), e
|
||||
when "copy"
|
||||
text = @term.getSelection()
|
||||
return unless text and text isnt ""
|
||||
@_api.setClipboard text
|
||||
else
|
||||
|
||||
|
||||
resizeContent: () ->
|
||||
@fitAddon.fit()
|
||||
ncol = @term.cols
|
||||
nrow = @term.rows
|
||||
return unless @sub
|
||||
arr = new Uint8Array(8)
|
||||
arr.set Antunnel.Msg.bytes_of(ncol), 0
|
||||
arr.set Antunnel.Msg.bytes_of(nrow), 4
|
||||
@sub.send Antunnel.Msg.CTRL, arr
|
||||
|
||||
openSession: () ->
|
||||
@term.clear()
|
||||
@term.focus()
|
||||
@sub = new Antunnel.Subscriber("vterm")
|
||||
@sub.onopen = () =>
|
||||
console.log("Subscribed")
|
||||
@resizeContent (($ @mterm).width()) , (($ @mterm).height())
|
||||
@term.focus()
|
||||
|
||||
@sub.onerror = (e) =>
|
||||
@error __("Unable to connect to: vterm"), e
|
||||
@sub = undefined
|
||||
|
||||
@sub.onmessage = (e) =>
|
||||
@term.write(new TextDecoder("utf-8").decode(e.data)) if @term and e.data
|
||||
|
||||
@sub.onclose = () =>
|
||||
@sub = undefined
|
||||
@notify __("Terminal connection closed")
|
||||
@quit()
|
||||
|
||||
@tunnel.subscribe @sub
|
||||
|
||||
cleanup: (e) ->
|
||||
@sub.close() if @sub
|
||||
|
||||
|
||||
vTerm.dependencies = [
|
||||
"pkg://Antunnel/main.js"
|
||||
]
|
||||
|
||||
this.OS.register "vTerm", vTerm
|
0
vTerm/main.css
Normal file
0
vTerm/main.css
Normal file
22
vTerm/package.json
Normal file
22
vTerm/package.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"app":"vTerm",
|
||||
"name":"Virtual Terminal",
|
||||
"description":"Access Unix terminal from web",
|
||||
"info":{
|
||||
"author": "Xuan Sang LE",
|
||||
"email": "xsang.le@gmail.com"
|
||||
},
|
||||
"version":"0.0.5-a",
|
||||
"category":"System",
|
||||
"iconclass":"fa fa-terminal",
|
||||
"mimes":["none"],
|
||||
"locales":{
|
||||
"fr_FR": {
|
||||
"Open terminal": "Ouvrir terminal",
|
||||
"Edit": "Modifier",
|
||||
"Please enter terminal URI": "Merci d'entrer l'URI du terminal",
|
||||
"Unable to connect to: {0}": "Impossible de connecter a: {0}",
|
||||
"Terminal connection closed": "Connexion terminal est fermee"
|
||||
}
|
||||
}
|
||||
}
|
8
vTerm/project.json
Normal file
8
vTerm/project.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "vTerm",
|
||||
"root": "home://workspace/antosdk-apps/vTerm",
|
||||
"css": ["xterm.css", "main.css"],
|
||||
"javascripts": ["xterm-addon-fit.js", "xterm.js"],
|
||||
"coffees": ["main.coffee"],
|
||||
"copies": ["scheme.html", "package.json", "README.md"]
|
||||
}
|
5
vTerm/scheme.html
Normal file
5
vTerm/scheme.html
Normal file
@ -0,0 +1,5 @@
|
||||
<afx-app-window apptitle="__(Terminal)" width="600" height="400">
|
||||
<afx-hbox data-id = "mybox">
|
||||
<div data-id="myterm" ></div>
|
||||
</afx-hbox>
|
||||
</afx-app-window>
|
2
vTerm/xterm-addon-fit.js
Normal file
2
vTerm/xterm-addon-fit.js
Normal file
@ -0,0 +1,2 @@
|
||||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.FitAddon=t():e.FitAddon=t()}(window,(function(){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=0)}([function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.FitAddon=void 0;var n=function(){function e(){}return e.prototype.activate=function(e){this._terminal=e},e.prototype.dispose=function(){},e.prototype.fit=function(){var e=this.proposeDimensions();if(e&&this._terminal){var t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}},e.prototype.proposeDimensions=function(){if(this._terminal&&this._terminal.element&&this._terminal.element.parentElement){var e=this._terminal._core,t=window.getComputedStyle(this._terminal.element.parentElement),r=parseInt(t.getPropertyValue("height")),n=Math.max(0,parseInt(t.getPropertyValue("width"))),o=window.getComputedStyle(this._terminal.element),i=r-(parseInt(o.getPropertyValue("padding-top"))+parseInt(o.getPropertyValue("padding-bottom"))),a=n-(parseInt(o.getPropertyValue("padding-right"))+parseInt(o.getPropertyValue("padding-left")))-e.viewport.scrollBarWidth;return{cols:Math.max(2,Math.floor(a/e._renderService.dimensions.actualCellWidth)),rows:Math.max(1,Math.floor(i/e._renderService.dimensions.actualCellHeight))}}},e}();t.FitAddon=n}])}));
|
||||
//# sourceMappingURL=xterm-addon-fit.js.map
|
171
vTerm/xterm.css
Normal file
171
vTerm/xterm.css
Normal file
@ -0,0 +1,171 @@
|
||||
/**
|
||||
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
||||
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
||||
* https://github.com/chjj/term.js
|
||||
* @license MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* Originally forked from (with the author's permission):
|
||||
* Fabrice Bellard's javascript vt100 for jslinux:
|
||||
* http://bellard.org/jslinux/
|
||||
* Copyright (c) 2011 Fabrice Bellard
|
||||
* The original design remains. The terminal itself
|
||||
* has been extended to include xterm CSI codes, among
|
||||
* other features.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default styles for xterm.js
|
||||
*/
|
||||
|
||||
.xterm {
|
||||
font-feature-settings: "liga" 0;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.xterm.focus,
|
||||
.xterm:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.xterm .xterm-helpers {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
/**
|
||||
* The z-index of the helpers must be higher than the canvases in order for
|
||||
* IMEs to appear on top.
|
||||
*/
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.xterm .xterm-helper-textarea {
|
||||
/*
|
||||
* HACK: to fix IE's blinking cursor
|
||||
* Move textarea out of the screen to the far left, so that the cursor is not visible.
|
||||
*/
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
left: -9999em;
|
||||
top: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
z-index: -5;
|
||||
/** Prevent wrapping so the IME appears against the textarea at the correct position */
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.xterm .composition-view {
|
||||
/* TODO: Composition position got messed up somewhere */
|
||||
background: #000;
|
||||
color: #FFF;
|
||||
display: none;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.xterm .composition-view.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.xterm .xterm-viewport {
|
||||
/* On OS X this is required in order for the scroll bar to appear fully opaque */
|
||||
background-color: #000;
|
||||
overflow-y: scroll;
|
||||
cursor: default;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-screen {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.xterm .xterm-screen canvas {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-scroll-area {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.xterm-char-measure-element {
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -9999em;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.xterm {
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.xterm.enable-mouse-events {
|
||||
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.xterm.xterm-cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.xterm.column-select.focus {
|
||||
/* Column selection mode */
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.xterm .xterm-accessibility,
|
||||
.xterm .xterm-message {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.xterm .live-region {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.xterm-dim {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.xterm-underline {
|
||||
text-decoration: underline;
|
||||
}
|
2
vTerm/xterm.js
Normal file
2
vTerm/xterm.js
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user