Implemented reconnect logic
This commit is contained in:
parent
37a3f85037
commit
8e5788b6e5
3 changed files with 170 additions and 22 deletions
|
@ -54,6 +54,7 @@ body, h1, h2, h3, h4, h5, h6, p, ol, ul {
|
||||||
|
|
||||||
[hidden] { display: none !important; }
|
[hidden] { display: none !important; }
|
||||||
|
|
||||||
|
/* ---------------------------- Header ---------------------------- */
|
||||||
header {
|
header {
|
||||||
border-bottom: 1px solid black;
|
border-bottom: 1px solid black;
|
||||||
background: var(--header-bg);
|
background: var(--header-bg);
|
||||||
|
@ -78,10 +79,38 @@ header span {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
main {
|
header .overlay {
|
||||||
flex: 2 1 auto;
|
background: var(--header-bg);
|
||||||
|
color: var(--foreground);
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
header .overlay h2 {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
header .overlay .bar {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
header .overlay .bar .led {
|
||||||
|
margin: 0 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------- Nav ---------------------------- */
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -133,6 +162,15 @@ nav::after {
|
||||||
border-top: 1px solid var(--nav-above-border-color);
|
border-top: 1px solid var(--nav-above-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---------------------------- Main ---------------------------- */
|
||||||
|
|
||||||
|
main {
|
||||||
|
flex: 2 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------- Extra ---------------------------- */
|
||||||
|
|
||||||
/* Taken from https://github.com/aus/led.css */
|
/* Taken from https://github.com/aus/led.css */
|
||||||
.led {
|
.led {
|
||||||
margin-top: 1px;
|
margin-top: 1px;
|
||||||
|
|
|
@ -1,10 +1,37 @@
|
||||||
|
class Animator {
|
||||||
|
constructor() {
|
||||||
|
this.running = null
|
||||||
|
this.runningInterval = null
|
||||||
|
}
|
||||||
|
|
||||||
|
begin(time) {
|
||||||
|
if (this.runningInterval === time && this.running) return
|
||||||
|
if (this.running) {
|
||||||
|
clearInterval(this.running)
|
||||||
|
}
|
||||||
|
this.runningInterval = time
|
||||||
|
this.running = setInterval(function() {
|
||||||
|
m.redraw()
|
||||||
|
}, time)
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
clearInterval(this.running)
|
||||||
|
this.running = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const animator = new Animator()
|
||||||
|
|
||||||
class WSClient
|
class WSClient
|
||||||
{
|
{
|
||||||
constructor(url = 'ws://localhost:4040') {
|
constructor(url = 'ws://localhost:4040') {
|
||||||
this.url = url
|
this.url = url
|
||||||
this.socket = null
|
this.socket = null
|
||||||
this.connected = false
|
this.connected = false
|
||||||
this.connecting = false
|
this.connecting = null
|
||||||
|
this.connectingAt = null
|
||||||
|
this.reconnecting = null
|
||||||
this.reconnectingAt = null
|
this.reconnectingAt = null
|
||||||
this.retryDuration = 1000
|
this.retryDuration = 1000
|
||||||
this.open()
|
this.open()
|
||||||
|
@ -12,22 +39,31 @@ class WSClient
|
||||||
|
|
||||||
open() {
|
open() {
|
||||||
if (this.connected || this.connecting) return
|
if (this.connected || this.connecting) return
|
||||||
this.connecting = true
|
clearTimeout(this.reconnecting)
|
||||||
|
this.reconnecting = this.reconnectingAt = null
|
||||||
|
this.connectingAt = new Date()
|
||||||
this.socket = new WebSocket(this.url)
|
this.socket = new WebSocket(this.url)
|
||||||
|
|
||||||
this.socket.addEventListener('open', this.onopen.bind(this))
|
this.socket.addEventListener('open', this.onopen.bind(this))
|
||||||
this.socket.addEventListener('message', this.onmessage.bind(this))
|
this.socket.addEventListener('message', this.onmessage.bind(this))
|
||||||
this.socket.addEventListener('error', this.onerror.bind(this))
|
this.socket.addEventListener('error', this.onerror.bind(this))
|
||||||
this.socket.addEventListener('close', this.onclose.bind(this))
|
this.socket.addEventListener('close', this.onclose.bind(this))
|
||||||
|
|
||||||
|
animator.begin(1000)
|
||||||
|
this.connecting = setTimeout(() => {
|
||||||
|
this.socket.close()
|
||||||
|
}, 5000)
|
||||||
m.redraw()
|
m.redraw()
|
||||||
}
|
}
|
||||||
|
|
||||||
onopen() {
|
onopen() {
|
||||||
|
animator.stop()
|
||||||
this.retryDuration = 1000
|
this.retryDuration = 1000
|
||||||
this.connecting = false
|
clearTimeout(this.connecting)
|
||||||
|
this.connecting = null
|
||||||
|
this.connectingAt = null
|
||||||
this.reconnectingAt = null
|
this.reconnectingAt = null
|
||||||
this.connected = true
|
this.connected = true
|
||||||
console.log('Sending hello server')
|
|
||||||
this.send({ msg: 'Hello Server!' })
|
this.send({ msg: 'Hello Server!' })
|
||||||
m.redraw()
|
m.redraw()
|
||||||
}
|
}
|
||||||
|
@ -37,8 +73,7 @@ class WSClient
|
||||||
this.socket.send(JSON.stringify(payload))
|
this.socket.send(JSON.stringify(payload))
|
||||||
}
|
}
|
||||||
|
|
||||||
onerror(err) {
|
onerror() {
|
||||||
console.error(err)
|
|
||||||
this.reconnect()
|
this.reconnect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,14 +83,17 @@ class WSClient
|
||||||
|
|
||||||
reconnect() {
|
reconnect() {
|
||||||
if (this.reconnectingAt) return
|
if (this.reconnectingAt) return
|
||||||
|
animator.begin(100)
|
||||||
this.socket = null
|
this.socket = null
|
||||||
this.connected = false
|
this.connected = false
|
||||||
this.connecting = false
|
clearTimeout(this.connecting)
|
||||||
|
this.connecting = null
|
||||||
|
this.connectingAt = null
|
||||||
|
|
||||||
this.reconnectingAt = new Date(new Date().getTime() + this.retryDuration)
|
this.reconnectingAt = new Date(new Date().getTime() + this.retryDuration)
|
||||||
setTimeout(() => {
|
clearTimeout(this.reconnecting)
|
||||||
this.reconnectingAt = null
|
this.reconnecting = setTimeout(() => {
|
||||||
this.retryDuration *= 1.5
|
this.retryDuration = Math.min(this.retryDuration * 1.5, 60000)
|
||||||
this.open()
|
this.open()
|
||||||
}, this.retryDuration)
|
}, this.retryDuration)
|
||||||
m.redraw()
|
m.redraw()
|
||||||
|
@ -73,20 +111,93 @@ const client = new WSClient()
|
||||||
|
|
||||||
class Header {
|
class Header {
|
||||||
view(vnode) {
|
view(vnode) {
|
||||||
|
console.log(client.connecting)
|
||||||
return [
|
return [
|
||||||
m('h1', 'Fíladelfíu streymi'),
|
m('h1', 'Fíladelfíu streymi'),
|
||||||
m('div.status.green', { hidden: true }, 'No errors'),
|
m('div.status.green', { hidden: true }, 'No errors'),
|
||||||
m('div.filler'),
|
m('div.filler'),
|
||||||
m('span', 'Live:'),
|
|
||||||
m('div.led'),
|
|
||||||
client.connected
|
client.connected
|
||||||
? null
|
? null
|
||||||
: m('div.overlay', [
|
: m('div.overlay', [
|
||||||
m('h2', client.connecting ? 'Connecting to server...' : 'Connection lost'),
|
m('h2', client.connecting ? 'Connecting to server...' : 'Failed to connect, retrying in...'),
|
||||||
m('')
|
client.connecting
|
||||||
]),
|
? this.viewConnectingBar()
|
||||||
|
: this.viewWaitingCircle(),
|
||||||
|
]),
|
||||||
|
m('span', 'Live:'),
|
||||||
|
m('div.led'),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
viewConnectingBar() {
|
||||||
|
let diff = Math.round((new Date() - client.connectingAt) / 1000)
|
||||||
|
let out = []
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
out.push(m('div.led', { class: diff >= i ? 'led-blue' : '' }))
|
||||||
|
}
|
||||||
|
return m('div.bar', out)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewWaitingCircle() {
|
||||||
|
var diff = Math.min((new Date() - client.reconnectingAt + 200), client.retryDuration)
|
||||||
|
var percentage = Math.abs(Math.min(diff / client.retryDuration, 0))
|
||||||
|
return m('svg', {
|
||||||
|
onclick: function() { client.open() },
|
||||||
|
style: 'width: 150px; transform: rotate(-90deg);',
|
||||||
|
viewBox: '0 0 150 150',
|
||||||
|
preserveAspectRatio: 'xMidYMid meet',
|
||||||
|
}, [
|
||||||
|
m('filter', { id: 'darker' }, [
|
||||||
|
m('feFlood', { 'flood-color': '#000000', 'flood-opacity': '1', in: 'SourceGraphic' }),
|
||||||
|
m('feComposite', { operator: 'in', in2: 'SourceGraphic' }),
|
||||||
|
m('feGaussianBlur', { stdDeviation: '2' }), // approx size, with higher values meaning less intensity
|
||||||
|
m('feComponentTransfer', { result: 'glowd' }, m('feFuncA', { type: 'linear', slope: 1, intercept: 0 })),
|
||||||
|
|
||||||
|
m('feMerge', [
|
||||||
|
m('feMergeNode', { in: 'SourceGraphic' }),
|
||||||
|
m('feMergeNode', { in: 'glowd' }),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
m('filter', { id: 'glower' }, [
|
||||||
|
m('feFlood', { 'flood-color': '#0066ff', 'flood-opacity': '1', in: 'SourceGraphic' }),
|
||||||
|
m('feComposite', { operator: 'in', in2: 'SourceGraphic' }),
|
||||||
|
m('feGaussianBlur', { stdDeviation: '10' }), // approx size, with higher values meaning less intensity
|
||||||
|
m('feComponentTransfer', { result: 'glow1' }, m('feFuncA', { type: 'linear', slope: 1, intercept: 0 })),
|
||||||
|
|
||||||
|
m('feFlood', { 'flood-color': '#0066ff', 'flood-opacity': '0.5', in: 'SourceGraphic' }),
|
||||||
|
m('feComposite', { operator: 'in', in2: 'SourceGraphic' }),
|
||||||
|
m('feGaussianBlur', { stdDeviation: '1' }), // approx size, with higher values meaning less intensity
|
||||||
|
m('feComponentTransfer', { result: 'glow2' }, m('feFuncA', { type: 'linear', slope: 2, intercept: 0 })),
|
||||||
|
|
||||||
|
m('feMerge', [
|
||||||
|
m('feMergeNode', { in: 'SourceGraphic' }),
|
||||||
|
m('feMergeNode', { in: 'glow2' }),
|
||||||
|
m('feMergeNode', { in: 'glow1' }),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
m('g', { width: '150px', height: '150px', filter: 'url(#darker)',}, [
|
||||||
|
m('rect', { width: '100%', height: '100%', fill: 'transparent' }),
|
||||||
|
m('circle', {
|
||||||
|
cx: '50%',
|
||||||
|
cy: '50%',
|
||||||
|
fill: 'transparent',
|
||||||
|
stroke: '#000000',
|
||||||
|
style: `stroke-width: 12%; transform-origin: 50% 50% 0px; transition: stroke-dashoffset 100ms;`,
|
||||||
|
r: 45,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
m('g', { width: '150px', height: '150px', filter: 'url(#glower)',}, [
|
||||||
|
m('rect', { width: '100%', height: '100%', fill: 'transparent' }),
|
||||||
|
m('circle', {
|
||||||
|
cx: '50%',
|
||||||
|
cy: '50%',
|
||||||
|
fill: 'transparent',
|
||||||
|
stroke: '#000000',
|
||||||
|
style: `stroke-dashoffset: ${Math.round(280 * percentage)}px; stroke-dasharray: 280px; stroke-width: 10%; transform-origin: 50% 50% 0px; transition: stroke-dashoffset 100ms;`,
|
||||||
|
r: 45,
|
||||||
|
})
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Nav {
|
class Nav {
|
||||||
|
@ -94,7 +205,7 @@ class Nav {
|
||||||
let path = m.route.get()
|
let path = m.route.get()
|
||||||
return [
|
return [
|
||||||
m(m.route.Link, {
|
m(m.route.Link, {
|
||||||
class: path === '/' ? 'active' : '',
|
class: path === '/' || path === '' ? 'active' : '',
|
||||||
href: '/',
|
href: '/',
|
||||||
}, [
|
}, [
|
||||||
m('svg', {
|
m('svg', {
|
||||||
|
|
|
@ -42,7 +42,9 @@ export function run(http, port, core) {
|
||||||
flaska.get('/::file', serve.serve.bind(serve))
|
flaska.get('/::file', serve.serve.bind(serve))
|
||||||
|
|
||||||
return flaska.listenAsync(port).then(function() {
|
return flaska.listenAsync(port).then(function() {
|
||||||
/*const wss = new WebSocketServer({ server: flaska.server })
|
core.log.info('Server is listening on port ' + port)
|
||||||
|
|
||||||
|
const wss = new WebSocketServer({ server: flaska.server })
|
||||||
|
|
||||||
wss.on('connection', function(ws) {
|
wss.on('connection', function(ws) {
|
||||||
console.log('new connection')
|
console.log('new connection')
|
||||||
|
@ -88,8 +90,5 @@ export function run(http, port, core) {
|
||||||
wss.on('close', function() {
|
wss.on('close', function() {
|
||||||
clearInterval(interval)
|
clearInterval(interval)
|
||||||
})
|
})
|
||||||
*/
|
|
||||||
|
|
||||||
core.log.info('Server is listening on port ' + port)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
Loading…
Reference in a new issue