|
|
@ -1,31 +1,38 @@ |
|
|
|
/** Handle connections */ |
|
|
|
/** Handle connections */ |
|
|
|
window.Conn = function (screen) { |
|
|
|
window.Conn = class TermConnection extends EventEmitter { |
|
|
|
let ws |
|
|
|
constructor (screen) { |
|
|
|
let heartbeatTout |
|
|
|
super() |
|
|
|
let pingIv |
|
|
|
|
|
|
|
let xoff = false |
|
|
|
this.screen = screen |
|
|
|
let autoXoffTout |
|
|
|
this.ws = null |
|
|
|
let reconTout |
|
|
|
this.heartbeatTimeout = null |
|
|
|
|
|
|
|
this.pingInterval = null |
|
|
|
let pageShown = false |
|
|
|
this.xoff = false |
|
|
|
|
|
|
|
this.autoXoffTimeout = null |
|
|
|
|
|
|
|
this.reconTimeout = null |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.pageShown = false |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function onOpen (evt) { |
|
|
|
onWSOpen (evt) { |
|
|
|
console.log('CONNECTED') |
|
|
|
console.log('CONNECTED') |
|
|
|
heartbeat() |
|
|
|
this.heartbeat() |
|
|
|
doSend('i') |
|
|
|
this.send('i') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.emit('open') |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function onClose (evt) { |
|
|
|
onWSClose (evt) { |
|
|
|
console.warn('SOCKET CLOSED, code ' + evt.code + '. Reconnecting...') |
|
|
|
console.warn('SOCKET CLOSED, code ' + evt.code + '. Reconnecting...') |
|
|
|
clearTimeout(reconTout) |
|
|
|
clearTimeout(this.reconTimeout) |
|
|
|
reconTout = setTimeout(function () { |
|
|
|
this.reconTimeout = setTimeout(() => this.init(), 2000) |
|
|
|
init() |
|
|
|
|
|
|
|
}, 2000) |
|
|
|
|
|
|
|
// this happens when the buffer gets fucked up via invalid unicode.
|
|
|
|
// this happens when the buffer gets fucked up via invalid unicode.
|
|
|
|
// we basically use polling instead of socket then
|
|
|
|
// we basically use polling instead of socket then
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.emit('close', evt.code) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function onMessage (evt) { |
|
|
|
onWSMessage (evt) { |
|
|
|
try { |
|
|
|
try { |
|
|
|
// . = heartbeat
|
|
|
|
// . = heartbeat
|
|
|
|
switch (evt.data.charAt(0)) { |
|
|
|
switch (evt.data.charAt(0)) { |
|
|
@ -35,66 +42,66 @@ window.Conn = function (screen) { |
|
|
|
|
|
|
|
|
|
|
|
case '-': |
|
|
|
case '-': |
|
|
|
// console.log('xoff');
|
|
|
|
// console.log('xoff');
|
|
|
|
xoff = true |
|
|
|
this.xoff = true |
|
|
|
autoXoffTout = setTimeout(function () { |
|
|
|
this.autoXoffTimeout = setTimeout(() => { |
|
|
|
xoff = false |
|
|
|
this.xoff = false |
|
|
|
}, 250) |
|
|
|
}, 250) |
|
|
|
break |
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
case '+': |
|
|
|
case '+': |
|
|
|
// console.log('xon');
|
|
|
|
// console.log('xon');
|
|
|
|
xoff = false |
|
|
|
this.xoff = false |
|
|
|
clearTimeout(autoXoffTout) |
|
|
|
clearTimeout(this.autoXoffTimeout) |
|
|
|
break |
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
default: |
|
|
|
default: |
|
|
|
screen.load(evt.data) |
|
|
|
this.screen.load(evt.data) |
|
|
|
if (!pageShown) { |
|
|
|
if (!this.pageShown) { |
|
|
|
showPage() |
|
|
|
showPage() |
|
|
|
pageShown = true |
|
|
|
this.pageShown = true |
|
|
|
} |
|
|
|
} |
|
|
|
break |
|
|
|
break |
|
|
|
} |
|
|
|
} |
|
|
|
heartbeat() |
|
|
|
this.heartbeat() |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
console.error(e) |
|
|
|
console.error(e) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function canSend () { |
|
|
|
canSend () { |
|
|
|
return !xoff |
|
|
|
return !this.xoff |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function doSend (message) { |
|
|
|
send (message) { |
|
|
|
if (_demo) { |
|
|
|
if (window._demo) { |
|
|
|
if (typeof demoInterface !== 'undefined') { |
|
|
|
if (typeof window.demoInterface !== 'undefined') { |
|
|
|
demoInterface.input(message) |
|
|
|
demoInterface.input(message) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
console.log(`TX: ${JSON.stringify(message)}`) |
|
|
|
console.log(`TX: ${JSON.stringify(message)}`) |
|
|
|
} |
|
|
|
} |
|
|
|
return true // Simulate success
|
|
|
|
return true // Simulate success
|
|
|
|
} |
|
|
|
} |
|
|
|
if (xoff) { |
|
|
|
if (this.xoff) { |
|
|
|
// TODO queue
|
|
|
|
// TODO queue
|
|
|
|
console.log("Can't send, flood control.") |
|
|
|
console.log("Can't send, flood control.") |
|
|
|
return false |
|
|
|
return false |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (!ws) return false // for dry testing
|
|
|
|
if (!this.ws) return false // for dry testing
|
|
|
|
if (ws.readyState !== 1) { |
|
|
|
if (this.ws.readyState !== 1) { |
|
|
|
console.error('Socket not ready') |
|
|
|
console.error('Socket not ready') |
|
|
|
return false |
|
|
|
return false |
|
|
|
} |
|
|
|
} |
|
|
|
if (typeof message != 'string') { |
|
|
|
if (typeof message != 'string') { |
|
|
|
message = JSON.stringify(message) |
|
|
|
message = JSON.stringify(message) |
|
|
|
} |
|
|
|
} |
|
|
|
ws.send(message) |
|
|
|
this.ws.send(message) |
|
|
|
return true |
|
|
|
return true |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function init () { |
|
|
|
init () { |
|
|
|
if (window._demo) { |
|
|
|
if (window._demo) { |
|
|
|
if (typeof demoInterface === 'undefined') { |
|
|
|
if (typeof window.demoInterface === 'undefined') { |
|
|
|
alert('Demoing non-demo demo!') // this will catch mistakes when deploying to the website
|
|
|
|
alert('Demoing non-demo demo!') // this will catch mistakes when deploying to the website
|
|
|
|
} else { |
|
|
|
} else { |
|
|
|
demoInterface.init(screen) |
|
|
|
demoInterface.init(screen) |
|
|
@ -103,42 +110,40 @@ window.Conn = function (screen) { |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
clearTimeout(reconTout) |
|
|
|
clearTimeout(this.reconTimeout) |
|
|
|
clearTimeout(heartbeatTout) |
|
|
|
clearTimeout(this.heartbeatTimeout) |
|
|
|
|
|
|
|
|
|
|
|
ws = new WebSocket('ws://' + _root + '/term/update.ws') |
|
|
|
this.ws = new WebSocket('ws://' + _root + '/term/update.ws') |
|
|
|
ws.onopen = onOpen |
|
|
|
this.ws.addEventListener('open', (...args) => this.onWSOpen(...args)) |
|
|
|
ws.onclose = onClose |
|
|
|
this.ws.addEventListener('close', (...args) => this.onWSClose(...args)) |
|
|
|
ws.onmessage = onMessage |
|
|
|
this.ws.addEventListener('message', (...args) => this.onWSMessage(...args)) |
|
|
|
console.log('Opening socket.') |
|
|
|
console.log('Opening socket.') |
|
|
|
heartbeat() |
|
|
|
this.heartbeat() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.emit('connect') |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function heartbeat () { |
|
|
|
heartbeat () { |
|
|
|
clearTimeout(heartbeatTout) |
|
|
|
clearTimeout(this.heartbeatTimeout) |
|
|
|
heartbeatTout = setTimeout(heartbeatFail, 2000) |
|
|
|
this.heartbeatTimeout = setTimeout(() => this.onHeartbeatFail(), 2000) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function heartbeatFail () { |
|
|
|
onHeartbeatFail () { |
|
|
|
console.error('Heartbeat lost, probing server...') |
|
|
|
console.error('Heartbeat lost, probing server...') |
|
|
|
pingIv = setInterval(function () { |
|
|
|
clearInterval(this.pingInterval) |
|
|
|
|
|
|
|
this.pingInterval = setInterval(() => { |
|
|
|
console.log('> ping') |
|
|
|
console.log('> ping') |
|
|
|
$.get('http://' + _root + '/system/ping', function (resp, status) { |
|
|
|
this.emit('ping') |
|
|
|
|
|
|
|
$.get('http://' + _root + '/system/ping', (resp, status) => { |
|
|
|
if (status === 200) { |
|
|
|
if (status === 200) { |
|
|
|
clearInterval(pingIv) |
|
|
|
clearInterval(this.pingInterval) |
|
|
|
console.info('Server ready, reloading page...') |
|
|
|
console.info('Server ready, reloading page...') |
|
|
|
|
|
|
|
this.emit('ping-success') |
|
|
|
location.reload() |
|
|
|
location.reload() |
|
|
|
} |
|
|
|
} else this.emit('ping-fail', status) |
|
|
|
}, { |
|
|
|
}, { |
|
|
|
timeout: 100 |
|
|
|
timeout: 100 |
|
|
|
}) |
|
|
|
}) |
|
|
|
}, 1000) |
|
|
|
}, 1000) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
|
|
|
ws: null, |
|
|
|
|
|
|
|
init, |
|
|
|
|
|
|
|
send: doSend, |
|
|
|
|
|
|
|
canSend // check flood control
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|