improved loader and reconnect behavior

cpsdqs/unified-input
Ondřej Hruška 7 years ago
parent e8e84ce4ca
commit 2b4b364d0d
  1. 16
      js/appcommon.js
  2. 12
      js/term.js
  3. 50
      js/term_conn.js
  4. 14
      js/term_screen.js
  5. 7
      sass/pages/_term.scss

@ -116,14 +116,28 @@ $._loader = function (vis) {
$('#loader').toggleClass('show', vis) $('#loader').toggleClass('show', vis)
} }
let pageShown = false
// reveal content on load // reveal content on load
function showPage () { function showPage () {
pageShown = true
$('#content').addClass('load') $('#content').addClass('load')
} }
// Auto reveal pages other than the terminal (sets window.noAutoShow) // Auto reveal pages other than the terminal (sets window.noAutoShow)
$.ready(function () { $.ready(function () {
if (window.noAutoShow !== true) { if (window.noAutoShow === true) {
setTimeout(function () {
if (!pageShown) {
let bnr = mk('P')
bnr.id = 'load-failed'
bnr.innerHTML =
'Server connection failed! Trying again' +
'<span class="anim-dots" style="width:1.5em;text-align:left;display:inline-block">.</span>'
qs('#screen').appendChild(bnr)
showPage()
}
}, 2000)
} else {
setTimeout(function () { setTimeout(function () {
showPage() showPage()
}, 1) }, 1)

@ -6,12 +6,12 @@ window.termInit = function ({ labels, theme, allFn }) {
const termUpload = TermUpl(conn, input, screen) const termUpload = TermUpl(conn, input, screen)
screen.input = input screen.input = input
conn.on('open', () => { screen.window.statusScreen = null }) conn.on('open', () => { screen.window.statusScreen = { title: 'Connecting', loading: true } })
conn.on('connect', () => { screen.window.statusScreen = { title: 'Connecting', loading: true } }) conn.on('connect', () => { screen.window.statusScreen = null })
conn.on('close', () => { screen.window.statusScreen = { title: 'Disconnected' } }) conn.on('disconnect', () => { screen.window.statusScreen = { title: 'Disconnected' } })
conn.on('ping', () => { screen.window.statusScreen = { title: 'Disconnected', loading: true } }) conn.on('silence', () => { screen.window.statusScreen = { title: 'Waiting for server', loading: true } })
conn.on('ping-fail', () => { screen.window.statusScreen = { title: 'Disconnected' } }) // conn.on('ping-fail', () => { screen.window.statusScreen = { title: 'Disconnected' } })
conn.on('ping-success', () => { screen.window.statusScreen = { title: 'Reloading', loading: true } }) conn.on('ping-success', () => { screen.window.statusScreen = { title: 'Re-connecting', loading: true } })
conn.init() conn.init()
input.init({ allFn }) input.init({ allFn })

@ -9,7 +9,8 @@ window.Conn = class TermConnection extends EventEmitter {
this.pingInterval = null this.pingInterval = null
this.xoff = false this.xoff = false
this.autoXoffTimeout = null this.autoXoffTimeout = null
this.reconTimeout = null this.reconnTimeout = null
this.forceClosing = false
this.pageShown = false this.pageShown = false
} }
@ -19,22 +20,26 @@ window.Conn = class TermConnection extends EventEmitter {
this.heartbeat() this.heartbeat()
this.send('i') this.send('i')
this.emit('open') this.emit('connect')
} }
onWSClose (evt) { onWSClose (evt) {
if (this.forceClosing) return
console.warn('SOCKET CLOSED, code ' + evt.code + '. Reconnecting...') console.warn('SOCKET CLOSED, code ' + evt.code + '. Reconnecting...')
clearTimeout(this.reconTimeout) if (evt.code < 1000) {
this.reconTimeout = setTimeout(() => this.init(), 2000) console.error('Bad code from socket!')
// this happens when the buffer gets fucked up via invalid unicode. // this sometimes happens for unknown reasons, code < 1000 is invalid
// we basically use polling instead of socket then location.reload()
}
this.emit('close', evt.code) clearTimeout(this.reconnTimeout)
this.reconnTimeout = setTimeout(() => this.init(), 2000)
this.emit('disconnect', evt.code)
} }
onWSMessage (evt) { onWSMessage (evt) {
try { try {
// . = heartbeat
switch (evt.data.charAt(0)) { switch (evt.data.charAt(0)) {
case '.': case '.':
// heartbeat, no-op message // heartbeat, no-op message
@ -99,10 +104,20 @@ window.Conn = class TermConnection extends EventEmitter {
return true return true
} }
/** Safely close the socket */
closeSocket () {
if (this.ws) {
this.forceClosing = true
this.ws.close()
this.forceClosing = false
this.ws = null
}
}
init () { init () {
if (window._demo) { if (window._demo) {
if (typeof window.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 build!') // this will catch mistakes when deploying to the website
} else { } else {
demoInterface.init(screen) demoInterface.init(screen)
showPage() showPage()
@ -110,9 +125,11 @@ window.Conn = class TermConnection extends EventEmitter {
return return
} }
clearTimeout(this.reconTimeout) clearTimeout(this.reconnTimeout)
clearTimeout(this.heartbeatTimeout) clearTimeout(this.heartbeatTimeout)
this.closeSocket()
this.ws = new WebSocket('ws://' + _root + '/term/update.ws') this.ws = new WebSocket('ws://' + _root + '/term/update.ws')
this.ws.addEventListener('open', (...args) => this.onWSOpen(...args)) this.ws.addEventListener('open', (...args) => this.onWSOpen(...args))
this.ws.addEventListener('close', (...args) => this.onWSClose(...args)) this.ws.addEventListener('close', (...args) => this.onWSClose(...args))
@ -120,7 +137,7 @@ window.Conn = class TermConnection extends EventEmitter {
console.log('Opening socket.') console.log('Opening socket.')
this.heartbeat() this.heartbeat()
this.emit('connect') this.emit('open')
} }
heartbeat () { heartbeat () {
@ -129,20 +146,25 @@ window.Conn = class TermConnection extends EventEmitter {
} }
onHeartbeatFail () { onHeartbeatFail () {
this.closeSocket()
this.emit('silence')
console.error('Heartbeat lost, probing server...') console.error('Heartbeat lost, probing server...')
clearInterval(this.pingInterval) clearInterval(this.pingInterval)
this.pingInterval = setInterval(() => { this.pingInterval = setInterval(() => {
console.log('> ping') console.log('> ping')
this.emit('ping') this.emit('ping')
$.get('http://' + _root + '/system/ping', (resp, status) => { $.get('http://' + _root + '/system/ping', (resp, status) => {
if (status === 200) { if (status === 200) {
clearInterval(this.pingInterval) clearInterval(this.pingInterval)
console.info('Server ready, reloading page...') console.info('Server ready, opening socket…')
this.emit('ping-success') this.emit('ping-success')
location.reload() this.init()
// location.reload()
} else this.emit('ping-fail', status) } else this.emit('ping-fail', status)
}, { }, {
timeout: 100 timeout: 100,
loader: false // we have loader on-screen
}) })
}, 1000) }, 1000)
} }

@ -72,6 +72,8 @@ window.TermScreen = class TermScreen extends EventEmitter {
this._debug = null this._debug = null
this.contentLoaded = false
this.canvas = mk('canvas') this.canvas = mk('canvas')
this.ctx = this.canvas.getContext('2d') this.ctx = this.canvas.getContext('2d')
@ -1136,16 +1138,16 @@ window.TermScreen = class TermScreen extends EventEmitter {
ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0) ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0)
ctx.clearRect(0, 0, screenWidth, screenHeight) ctx.clearRect(0, 0, screenWidth, screenHeight)
ctx.font = `40px ${fontFamily}` ctx.font = `24px ${fontFamily}`
ctx.fillStyle = '#fff' ctx.fillStyle = '#fff'
ctx.textAlign = 'center' ctx.textAlign = 'center'
ctx.textBaseline = 'middle' ctx.textBaseline = 'middle'
ctx.fillText(statusScreen.title || '', screenWidth / 2, screenHeight / 2 - 20) ctx.fillText(statusScreen.title || '', screenWidth / 2, screenHeight / 2 - 50)
if (statusScreen.loading) { if (statusScreen.loading) {
// show loading spinner // show loading spinner
ctx.save() ctx.save()
ctx.translate(screenWidth / 2, screenHeight / 2 + 50) ctx.translate(screenWidth / 2, screenHeight / 2 + 20)
ctx.strokeStyle = '#fff' ctx.strokeStyle = '#fff'
ctx.lineWidth = 5 ctx.lineWidth = 5
@ -1194,6 +1196,12 @@ window.TermScreen = class TermScreen extends EventEmitter {
// Uncomment to capture screen content for the demo page // Uncomment to capture screen content for the demo page
// console.log(JSON.stringify(`S${str}`)) // console.log(JSON.stringify(`S${str}`))
if (!this.contentLoaded) {
let errmsg = qs('#load-failed')
if (errmsg) errmsg.parentNode.removeChild(errmsg)
this.contentLoaded = true
}
// window size // window size
const newHeight = parse2B(str, i) const newHeight = parse2B(str, i)
const newWidth = parse2B(str, i + 2) const newWidth = parse2B(str, i + 2)

@ -85,6 +85,13 @@ body.term {
} }
} }
#load-failed {
color: red;
font-size: 18px;
font-weight: bold;
margin: 10px 5px 14px 5px;
}
#term-nav { #term-nav {
padding-top: 1.5em; padding-top: 1.5em;
text-align: center; text-align: center;

Loading…
Cancel
Save