'use strict'; const coap = require('coap'); const PORT = Number(process.env.COAP_PORT) || 5683; const HOST = process.env.COAP_HOST || '0.0.0.0'; // --- helpers --------------------------------------------------------------- const TEXT = 'text/plain'; const JSON_FMT = 'application/json'; /** Split "/hello?name=Bob" into ["/hello", "name=Bob"]. */ function splitUrl(url) { const i = url.indexOf('?'); const path = (i === -1 ? url : url.slice(0, i)).replace(/\/+$/, '') || '/'; return [path, i === -1 ? '' : url.slice(i + 1)]; } /** Pull a name out of "?name=Bob" style queries. */ function nameFromQuery(query) { return new URLSearchParams(query || '').get('name'); } /** Pull a name out of a POST body: raw text or {"name":"Bob"}. */ function nameFromBody(buf) { const body = buf.toString('utf8').trim(); if (!body) return null; if (body.startsWith('{')) { try { const parsed = JSON.parse(body); return typeof parsed.name === 'string' ? parsed.name.trim() : null; } catch { return null; } } return body; } function greet(name) { return `Hello, ${name && name.length ? name : 'World'}!`; } function send(res, code, payload, format = TEXT) { res.code = code; res.setOption('Content-Format', format); res.end(typeof payload === 'string' ? payload : JSON.stringify(payload)); } // --- routes ---------------------------------------------------------------- // key: "METHOD /path" const routes = { 'GET /hello': (req, res) => { send(res, '2.05', greet(nameFromQuery(req.query))); }, 'POST /hello': (req, res) => { const name = nameFromBody(req.payload) || nameFromQuery(req.query); if (!name) { return send(res, '4.00', 'Bad Request: send a name as the payload'); } send(res, '2.01', greet(name)); }, 'GET /health': (_req, res) => { send(res, '2.05', { status: 'ok', uptime: Math.round(process.uptime()) }, JSON_FMT); }, }; // --- server ---------------------------------------------------------------- const server = coap.createServer({ type: 'udp4' }); server.on('request', (req, res) => { const [path, query] = splitUrl(req.url); req.query = query; // node-coap only gives us req.url on the server side const key = `${req.method} ${path}`; const handler = routes[key]; console.log(`${req.method} ${req.url} from ${req.rsinfo.address}:${req.rsinfo.port}`); if (!handler) return send(res, '4.04', `Not Found: ${path}`); try { handler(req, res); } catch (err) { console.error('handler error:', err); send(res, '5.00', 'Internal Server Error'); } }); server.on('error', (err) => console.error('server error:', err)); server.listen(PORT, HOST, () => { console.log(`CoAP server (UDP) listening on coap://${HOST}:${PORT}`); console.log(' GET /hello?name=Imran'); console.log(' POST /hello (payload: Imran | {"name":"Imran"})'); console.log(' GET /health'); }); process.on('SIGINT', () => server.close(() => process.exit(0)));