added PING and PONG handling, config

This commit is contained in:
dab 2025-08-13 21:35:47 +00:00
parent f049888aa7
commit 605d72f9b0

View file

@ -28,9 +28,52 @@ const get_siteroot_html = function ({ page_title }) {return `
`.trim()} `.trim()}
const start_server = function ({ context_meta, config, jsbuild_app_frontend }) { const start_server = function ({ context_meta, config, jsbuild_app_frontend }) {
const make_session_object = (ws) => {
const map_obj = {
ws,
closed_by_server: false,
id_interval_ping: null,
id_timeout_checkpong: null,
}
const func_check_pong = () => {
//console.debug('CHECK PONG')
// if this check/timeout was not cancelled yet, indicates it's been "too long" (so, terminate ws)
const terminate_session = () => {
const code = 1008
const reason = 'Policy Violation'
map_obj.closed_by_server = true
map_obj.ws.close(code, reason)
// cleanup here
context_meta.ws_map.delete(ws.data.uid)
return
}
terminate_session()
// reset this for future ref
map_obj.id_timeout_checkpong = null
return
}
const func_periodic_ping = () => {
//console.debug('PING')
ws.ping()
if (config.pong_timeout !== null) {
if (map_obj.id_timeout_checkpong === null) {
map_obj.id_timeout_checkpong = setTimeout(func_check_pong, config.pong_timeout)
}
else {
// avoid double-schedule of this check
console.warn('Unexpected: setTimeout for func_check_pong already scheduled')
}
}
return
}
if (config.ping_interval !== null) {
map_obj.id_interval_ping = setInterval(func_periodic_ping, config.ping_interval)
}
return map_obj
}
const server = Bun.serve({ const server = Bun.serve({
hostname: config.host || '127.0.0.1', hostname: config.hostname,
port : config.port || 8800, port : config.port,
async fetch (req, server) { async fetch (req, server) {
const url = new URL(req.url) const url = new URL(req.url)
let resp let resp
@ -70,10 +113,8 @@ const start_server = function ({ context_meta, config, jsbuild_app_frontend }) {
}, },
websocket: { websocket: {
open: function (ws) { open: function (ws) {
const map_obj = { console.info(['ws open', ws.data.uid])
ws, const map_obj = make_session_object(ws)
closed_by_server: false,
}
context_meta.ws_map.set(ws.data.uid, map_obj) context_meta.ws_map.set(ws.data.uid, map_obj)
return return
}, },
@ -83,6 +124,14 @@ const start_server = function ({ context_meta, config, jsbuild_app_frontend }) {
console.warn(['Unexpected: ws_map missing uid', ws.data.uid]) console.warn(['Unexpected: ws_map missing uid', ws.data.uid])
} }
else { else {
// stop ping-ing
if (map_obj.id_interval_ping !== null) {
clearInterval(map_obj.id_interval_ping)
}
// stop pong-check-ing
if (map_obj.id_timeout_checkpong !== null) {
clearTimeout(map_obj.id_timeout_checkpong)
}
if (map_obj.closed_by_server === true) { if (map_obj.closed_by_server === true) {
console.info(['ws closed by server', ws.data.uid]) console.info(['ws closed by server', ws.data.uid])
// cleanup will happen in outer context // cleanup will happen in outer context
@ -96,6 +145,22 @@ const start_server = function ({ context_meta, config, jsbuild_app_frontend }) {
return return
}, },
message: function (ws, message) {}, message: function (ws, message) {},
pong: function (ws, data) {
//console.debug(['ws pong', ws.data.uid])
const map_obj = context_meta.ws_map.get(ws.data.uid)
if (map_obj === undefined) {
console.warn(['Unexpected: ws_map missing uid', ws.data.uid])
}
else {
// cancel pending check
if (map_obj.id_timeout_checkpong !== null) {
clearTimeout(map_obj.id_timeout_checkpong)
// reset this for future ref
map_obj.id_timeout_checkpong = null
}
}
return
},
}, },
}) })
return server return server
@ -120,10 +185,19 @@ const async_run = async function ({
config, config,
jsbuild_app_frontend, jsbuild_app_frontend,
}) { }) {
const active_config = {
// defaults
hostname: '127.0.0.1',
port: 8800,
ping_interval: 1000 * 15,
pong_timeout : 1000 * 5,
// overrides
...config,
}
const context_meta = { const context_meta = {
ws_map: new Map(), ws_map: new Map(),
} }
const server = start_server({ context_meta, config, jsbuild_app_frontend }) const server = start_server({ context_meta, config: active_config, jsbuild_app_frontend })
console.info(server) console.info(server)
process.on('SIGINT', async () => { process.on('SIGINT', async () => {
console.log('SIGINT intercepted') console.log('SIGINT intercepted')