92 lines
2.9 KiB
JavaScript
92 lines
2.9 KiB
JavaScript
const fs = require('node:fs');
|
|
const https = require('node:https');
|
|
const path = require('node:path');
|
|
|
|
const { createStore, createJtlPosServer, createAdminServer } = require('./lib/src');
|
|
const actions = require('./lib/src/actions');
|
|
|
|
const PORT = Number(process.env.PORT) || 8086;
|
|
const ADMIN_PORT = Number(process.env.ADMIN_PORT) || 8087;
|
|
const AUTH_TOKEN =
|
|
process.env.AUTH_TOKEN || '9a2e3036ed9c47e389741d9dbb7590e9';
|
|
const PAIRING_CODE = process.env.PAIRING_CODE || '307018';
|
|
|
|
const certsDir = path.join(__dirname, 'certs');
|
|
const keyPath = path.join(certsDir, 'key.pem');
|
|
const certPath = path.join(certsDir, 'cert.pem');
|
|
|
|
if (!fs.existsSync(keyPath) || !fs.existsSync(certPath)) {
|
|
console.error('Missing TLS certificate. Run: npm run cert');
|
|
process.exit(1);
|
|
}
|
|
|
|
function serverTimestamp() {
|
|
const d = new Date();
|
|
const pad = (n) => String(n).padStart(2, '0');
|
|
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
|
}
|
|
|
|
function formatBody(buffer) {
|
|
if (!buffer.length) {
|
|
return '(empty)';
|
|
}
|
|
const text = buffer.toString('utf8');
|
|
if (/^[\x09\x0A\x0D\x20-\x7E\u0080-\uFFFF]*$/.test(text)) {
|
|
return text;
|
|
}
|
|
return `[binary ${buffer.length} bytes]\n${buffer.toString('hex')}`;
|
|
}
|
|
|
|
const store = createStore();
|
|
|
|
// Pre-register the fixed pairing code so the POS can pair out of the box.
|
|
store.dispatch(actions.setPairingCode(PAIRING_CODE, 'JTL-POS'));
|
|
// Treat the fixed auth token as a pre-paired device for display in the admin UI.
|
|
store.dispatch(actions.registerDevice(AUTH_TOKEN, 'JTL-POS'));
|
|
|
|
const jtlHandler = createJtlPosServer(store, { authToken: AUTH_TOKEN });
|
|
|
|
const loggedJtlHandler = async (req, res) => {
|
|
const started = Date.now();
|
|
const originalEnd = res.end.bind(res);
|
|
|
|
console.log('\n--- incoming POS request ---');
|
|
console.log(`${req.method} ${req.url}`);
|
|
console.log('remote:', req.socket.remoteAddress, req.socket.remotePort);
|
|
console.log('headers:', JSON.stringify(req.headers, null, 2));
|
|
|
|
await jtlHandler(req, res);
|
|
|
|
// req.rawBody is attached by jtlHandler's body reader
|
|
console.log('body:', formatBody(req.rawBody ?? Buffer.alloc(0)));
|
|
console.log(`responded ${res.statusCode} in ${Date.now() - started}ms`);
|
|
};
|
|
|
|
const httpsServer = https.createServer(
|
|
{
|
|
key: fs.readFileSync(keyPath),
|
|
cert: fs.readFileSync(certPath),
|
|
},
|
|
loggedJtlHandler
|
|
);
|
|
|
|
httpsServer.listen(PORT, '0.0.0.0', () => {
|
|
console.log(`HTTPS POS server listening on https://0.0.0.0:${PORT}`);
|
|
console.log(`Certificate: ${certPath}`);
|
|
console.log('Import cert.pem into JTL POS / Windows trust store if required.');
|
|
});
|
|
|
|
const { server: adminServer } = createAdminServer(store, {
|
|
adminPort: ADMIN_PORT,
|
|
staticDir: path.join(__dirname, 'web', 'dist'),
|
|
});
|
|
|
|
function shutdown() {
|
|
console.log('\nShutting down...');
|
|
httpsServer.close();
|
|
adminServer.close();
|
|
}
|
|
|
|
process.on('SIGINT', shutdown);
|
|
process.on('SIGTERM', shutdown);
|