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