Genesis
This commit is contained in:
124
server.js
Normal file
124
server.js
Normal file
@@ -0,0 +1,124 @@
|
||||
import fs from 'node:fs';
|
||||
import https from 'node:https';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import 'dotenv/config';
|
||||
|
||||
import { connectDb, closeDb } from './src/db.js';
|
||||
import { createJtlPosServer } from './src/jtl-server.js';
|
||||
import { createPairingStore } from './src/pairing.js';
|
||||
import { closeOrderLog } from './src/order-log.js';
|
||||
import { closeRequestLog, logRequest } from './src/request-log.js';
|
||||
import { logger } from './src/logger.js';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
const PORT = Number(process.env.PORT) || 4443;
|
||||
const AUTH_TOKEN = process.env.AUTH_TOKEN || 'df40ad2067954646abb0499548a52241';
|
||||
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)) {
|
||||
logger.error('Missing TLS certificate. Run: npm run cert');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const CONSOLE_URL_MAX_LENGTH = 100;
|
||||
|
||||
function truncateUrl(url) {
|
||||
if (url.length <= CONSOLE_URL_MAX_LENGTH) {
|
||||
return url;
|
||||
}
|
||||
return `${url.slice(0, CONSOLE_URL_MAX_LENGTH)}...`;
|
||||
}
|
||||
|
||||
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]`;
|
||||
}
|
||||
|
||||
const pairingStore = createPairingStore();
|
||||
pairingStore.setPairingCode(PAIRING_CODE, 'JTL-POS');
|
||||
pairingStore.registerDevice(AUTH_TOKEN, 'JTL-POS');
|
||||
|
||||
const jtlHandler = createJtlPosServer(pairingStore, { authToken: AUTH_TOKEN });
|
||||
|
||||
const loggedJtlHandler = async (req, res) => {
|
||||
const started = Date.now();
|
||||
let responseBuffer = Buffer.alloc(0);
|
||||
|
||||
const originalEnd = res.end.bind(res);
|
||||
res.end = (chunk, ...args) => {
|
||||
if (chunk) {
|
||||
responseBuffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
||||
}
|
||||
return originalEnd(chunk, ...args);
|
||||
};
|
||||
|
||||
await jtlHandler(req, res);
|
||||
|
||||
const responseBody = formatBody(responseBuffer);
|
||||
const durationMs = Date.now() - started;
|
||||
logger.info(`${req.socket.remoteAddress} ${req.method} ${truncateUrl(req.url)} ${res.statusCode} ${durationMs}ms`);
|
||||
|
||||
logRequest({
|
||||
remoteAddress: req.socket.remoteAddress,
|
||||
method: req.method,
|
||||
url: req.url,
|
||||
statusCode: res.statusCode,
|
||||
durationMs,
|
||||
response: responseBody,
|
||||
});
|
||||
};
|
||||
|
||||
const httpsServer = https.createServer(
|
||||
{
|
||||
key: fs.readFileSync(keyPath),
|
||||
cert: fs.readFileSync(certPath),
|
||||
},
|
||||
loggedJtlHandler
|
||||
);
|
||||
|
||||
async function start() {
|
||||
try {
|
||||
await connectDb();
|
||||
logger.success(`MSSQL connected: ${process.env.MSSQL_SERVER}/${process.env.MSSQL_DATABASE}`);
|
||||
} catch (err) {
|
||||
logger.warn(`MSSQL connection skipped: ${err.message}`);
|
||||
logger.warn('POS handshake will still work; sync from database is not available yet.');
|
||||
}
|
||||
|
||||
httpsServer.listen(PORT, '0.0.0.0', () => {
|
||||
logger.success(`HTTPS POS server listening on https://0.0.0.0:${PORT}`);
|
||||
logger.info(`Certificate: ${certPath}`);
|
||||
logger.info(`Pairing code: ${PAIRING_CODE}`);
|
||||
logger.info(`Auth token: ${AUTH_TOKEN}`);
|
||||
logger.info('Import cert.pem into JTL POS trust store if required.');
|
||||
});
|
||||
}
|
||||
|
||||
async function shutdown() {
|
||||
logger.info('Shutting down...');
|
||||
httpsServer.close();
|
||||
await closeDb();
|
||||
closeRequestLog();
|
||||
closeOrderLog();
|
||||
}
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
shutdown().finally(() => process.exit(0));
|
||||
});
|
||||
process.on('SIGTERM', () => {
|
||||
shutdown().finally(() => process.exit(0));
|
||||
});
|
||||
|
||||
start();
|
||||
Reference in New Issue
Block a user