diff --git a/Dockerfile b/Dockerfile index dc52248..159f183 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,17 @@ FROM node:22-alpine +ENV NODE_ENV=production + WORKDIR /app COPY package*.json ./ -RUN npm install +RUN npm install && npm cache clean --force COPY . . +RUN chown -R node:node /app + +USER node + CMD ["sh", "-c", "node index.mjs ${DEVICE:-/dev/ttyACM0}"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index b0204b7..a74d786 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,9 @@ services: map-uploader: build: . + # Optionally expose the port if you want to monitor the container's health externally + # ports: + # - "8080:8080" environment: # Set to the appropriate device for your setup, either /dev/ttyACM0 if connected by USB to a USB companion or IP:port if connected over network to a wifi companion - DEVICE=/dev/ttyACM0 @@ -9,4 +12,10 @@ services: privileged: true # Adjust according to your setup, but this is the default devices: - - /dev/ttyACM0:/dev/ttyACM0 \ No newline at end of file + - /dev/ttyACM0:/dev/ttyACM0 + healthcheck: + test: ["CMD", "wget", "--spider", "-q", "http://localhost:8080/health"] + interval: 30s + timeout: 10s + retries: 1 + start_period: 5s \ No newline at end of file diff --git a/index.mjs b/index.mjs index 15d6e56..47411eb 100644 --- a/index.mjs +++ b/index.mjs @@ -6,11 +6,24 @@ import { import { KeyPair } from './supercop/index.mjs'; import crypto from 'crypto'; +import http from 'http'; const device = process.argv[2] ?? '/dev/ttyACM0'; const apiURL = 'https://map.meshcore.dev/api/v1/uploader/node'; const seenAdverts = {}; let clientInfo = {}; +let isHealthy = false; + +// Health check server +http.createServer((req, res) => { + if (req.url === '/health') { + res.writeHead(isHealthy ? 200 : 503); + res.end(isHealthy ? 'OK' : 'Not Ready'); + } else { + res.writeHead(404); + res.end(); + } +}).listen(8080); const signData = async (kp, data) => { const json = JSON.stringify(data); @@ -88,6 +101,7 @@ if(device.startsWith('/') || device.startsWith('COM')){ connection.on('connected', async () => { console.log(`Connected.`); + isHealthy = true; connection.setManualAddContacts(); @@ -97,6 +111,21 @@ connection.on('connected', async () => { console.log('Map uploader waiting for adverts...'); }); +connection.on('disconnected', () => { + console.log('Disconnected. Exiting...'); + process.exit(1); +}); + +connection.on('close', () => { + console.log('Connection closed. Exiting...'); + process.exit(1); +}); + +connection.on('error', (err) => { + console.error('Connection error:', err); + process.exit(1); +}); + connection.on(Constants.PushCodes.LogRxData, async (event) => { try { await processPacket(connection, event.raw);