Merge branch 'edgarogh-safe-shutdown'
This commit is contained in:
commit
c1d3a42d22
10 changed files with 126 additions and 3 deletions
3
.dockerignore
Normal file
3
.dockerignore
Normal file
|
@ -0,0 +1,3 @@
|
|||
.git
|
||||
.cache
|
||||
node_modules
|
|
@ -4,4 +4,4 @@ WORKDIR /usr/src
|
|||
COPY app/ /usr/src/
|
||||
RUN npm install --production
|
||||
EXPOSE 2222
|
||||
CMD npm run start
|
||||
ENTRYPOINT [ "/usr/local/bin/node", "index.js" ]
|
||||
|
|
|
@ -228,6 +228,8 @@ docker run --name webssh2 -d -p 2222:2222 -v `pwd`/app/config.json:/usr/src/conf
|
|||
|
||||
* **accesslog** - _boolean_ - http style access logging to console.log, default: false
|
||||
|
||||
* **safeShutdownDuration** - _integer_ - maximum delay, in seconds, given to users before the server stops when doing a safe shutdown
|
||||
|
||||
# Experimental client-side logging
|
||||
Clicking `Start logging` on the status bar will log all data to the client. A `Download log` option will appear after starting the logging. You may download at any time to the client. You may stop logging at any time my pressing the `Logging - STOP LOG`. Note that clicking the `Start logging` option again will cause the current log to be overwritten, so be sure to download first.
|
||||
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
})
|
||||
|
|
|
@ -83,7 +83,8 @@ let config = {
|
|||
server: false
|
||||
},
|
||||
accesslog: false,
|
||||
verify: false
|
||||
verify: false,
|
||||
safeShutdownDuration: 300
|
||||
}
|
||||
|
||||
// test if config.json exists, if not provide error message but try to run
|
||||
|
@ -120,6 +121,7 @@ var expressOptions = require('./expressOptions')
|
|||
var favicon = require('serve-favicon');
|
||||
|
||||
// express
|
||||
app.use(safeShutdownGuard)
|
||||
app.use(session)
|
||||
app.use(myutil.basicAuth)
|
||||
if (config.accesslog) app.use(logger('common'))
|
||||
|
@ -199,4 +201,56 @@ io.use(function (socket, next) {
|
|||
// bring up socket
|
||||
io.on('connection', socket)
|
||||
|
||||
// safe shutdown
|
||||
var shutdownMode = false
|
||||
var shutdownInterval = 0
|
||||
var connectionCount = 0
|
||||
|
||||
function safeShutdownGuard (req, res, next) {
|
||||
if (shutdownMode) res.status(503).end('Service unavailable: Server shutting down')
|
||||
else return next()
|
||||
}
|
||||
|
||||
io.on('connection', function (socket) {
|
||||
connectionCount++
|
||||
|
||||
socket.on('disconnect', function () {
|
||||
if ((--connectionCount <= 0) && shutdownMode) {
|
||||
stop('All clients disconnected')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const signals = ['SIGTERM', 'SIGINT']
|
||||
signals.forEach(signal => process.on(signal, function () {
|
||||
if (shutdownMode) stop('Safe shutdown aborted, force quitting')
|
||||
else if (connectionCount > 0) {
|
||||
var remainingSeconds = config.safeShutdownDuration
|
||||
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 }
|
||||
|
|
Loading…
Reference in a new issue