Add safe shudown

- SIGINT is intercepted and force-quits the 2nd time
 - Live countdown on Web UI
 - Countdown ignored if all clients disconnect
 - Clean exit function
This commit is contained in:
Edgar Onghena 2020-03-18 19:01:53 +01:00
parent 7a89d45e48
commit eb7d91ffbc
7 changed files with 111 additions and 1 deletions

View file

@ -19,6 +19,7 @@
</div>
<div id="footer"></div>
<div id="status"></div>
<div id="countdown"></div>
</div>
</div>
<script src="/ssh/webssh2.bundle.js" defer></script>

File diff suppressed because one or more lines are too long

View file

@ -246,6 +246,30 @@ body, html {
text-align: left;
z-index: 100;
}
#countdown {
display: none;
color: rgb(240, 240, 240);
background-color: rgb(50, 50, 50);
padding-left: 10px;
padding-right: 10px;
border-color: white;
border-style: none solid none solid;
border-width: 1px;
text-align: left;
z-index: 100;
}
#countdown.active {
display: inline-block;
animation: countdown infinite alternate 200ms;
}
@keyframes countdown {
from {
background-color: rgb(255, 255, 0);
}
to {
background-color: inherit;
}
}
#menu {
display: inline-block;
font-size: 16px;

View file

@ -19,6 +19,7 @@
</div>
<div id="footer"></div>
<div id="status"></div>
<div id="countdown"></div>
</div>
</div>
<script src="/ssh/webssh2.bundle.js" defer></script>

View file

@ -75,6 +75,30 @@ body, html {
text-align: left;
z-index: 100;
}
#countdown {
display: none;
color: rgb(240, 240, 240);
background-color: rgb(50, 50, 50);
padding-left: 10px;
padding-right: 10px;
border-color: white;
border-style: none solid none solid;
border-width: 1px;
text-align: left;
z-index: 100;
}
#countdown.active {
display: inline-block;
animation: countdown infinite alternate 200ms;
}
@keyframes countdown {
from {
background-color: rgb(255, 255, 0);
}
to {
background-color: inherit;
}
}
#menu {
display: inline-block;
font-size: 16px;

View file

@ -26,6 +26,7 @@ var status = document.getElementById('status')
var header = document.getElementById('header')
var dropupContent = document.getElementById('dropupContent')
var footer = document.getElementById('footer')
var countdown = document.getElementById('countdown')
var fitAddon = new FitAddon()
var terminalContainer = document.getElementById('terminal-container')
term.loadAddon(fitAddon)
@ -136,6 +137,7 @@ socket.on('disconnect', function (err) {
'WEBSOCKET SERVER DISCONNECTED: ' + err
}
socket.io.reconnection(false)
countdown.classList.remove('active')
})
socket.on('error', function (err) {
@ -149,6 +151,18 @@ socket.on('reauth', function () {
(allowreauth) && reauthSession()
})
// safe shutdown
var hasCountdownStarted = false
socket.on('shutdownCountdownUpdate', function (remainingSeconds) {
if (!hasCountdownStarted) {
countdown.classList.add('active')
hasCountdownStarted = true
}
countdown.innerText = 'Shutting down in ' + remainingSeconds + 's'
})
term.onTitleChange(function (title) {
document.title = title
})

View file

@ -199,4 +199,50 @@ io.use(function (socket, next) {
// bring up socket
io.on('connection', socket)
// safe shutdown
var shutdownMode = false
var shutdownInterval = 0
var connectionCount = 0
io.on('connection', function (socket) {
connectionCount++
socket.on('disconnect', function () {
if ((--connectionCount <= 0) && shutdownMode) {
stop('All clients disconnected')
}
})
})
process.on('SIGINT', function () {
if (shutdownMode) stop('Safe shutdown aborted, force quitting')
else if (connectionCount > 0) {
var remainingSeconds = 300
shutdownMode = true
var message = (connectionCount === 1) ? ' client is still connected'
: ' clients are still connected'
console.error(connectionCount + message)
console.error('Starting a ' + remainingSeconds + ' seconds countdown')
console.error('Press Ctrl+C again to force quit')
shutdownInterval = setInterval(function () {
if ((remainingSeconds--) <= 0) {
stop('Countdown is over')
} else {
io.sockets.emit('shutdownCountdownUpdate', remainingSeconds)
}
}, 1000)
} else stop()
})
// clean stop
function stop (reason) {
shutdownMode = false
if (reason) console.log('Stopping: ' + reason)
if (shutdownInterval) clearInterval(shutdownInterval)
io.close()
server.close()
}
module.exports = { server: server, config: config }