Skip to content

Commit e70ecac

Browse files
manage ip v6 too
1 parent 058f0a2 commit e70ecac

File tree

2 files changed

+72
-22
lines changed

2 files changed

+72
-22
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
- Update packages dependencies
44

5+
- unit tests reworked
6+
57
- Tested with Nelson 1.10.0
68

79
- Requires Nodejs 22.14.0

lib/nelsonProcess.js

Lines changed: 70 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
// Import required modules
2222
const CONFIGURATION = require('../etc/configuration.json');
2323
const { spawn } = require('child_process');
24-
const { Address4 } = require('ip-address');
24+
const { Address4, Address6 } = require('ip-address');
2525
const socketio = require('socket.io');
2626
const os = require('os');
2727
//=============================================================================
@@ -49,7 +49,25 @@ function startNelsonProcess() {
4949
let io = []; // Array to store socket connections
5050
let nelsonApp; // Child process running Nelson application
5151
let commandio; // Socket.IO instance for command communication
52+
let hasCleaned = false;
5253

54+
function cleanup(terminateNelson = false) {
55+
if (hasCleaned) {
56+
return;
57+
}
58+
hasCleaned = true;
59+
if (terminateNelson) {
60+
nelsonApp?.kill();
61+
}
62+
commandio?.close?.();
63+
commandio = undefined;
64+
nelsonApp = undefined;
65+
}
66+
67+
process.once('SIGINT', () => cleanup(true));
68+
process.once('SIGTERM', () => cleanup(true));
69+
process.once('disconnect', () => cleanup(true));
70+
process.once('exit', () => cleanup());
5371
// Listen for messages from the parent process
5472
process.on('message', (msg) => {
5573
switch (msg.msgtype) {
@@ -77,10 +95,11 @@ function startNelsonProcess() {
7795
case 'stop':
7896
// Stop the application
7997
commandio?.emit('stop');
98+
cleanup(true);
8099
break;
81100
case 'quit':
82101
// Terminate Nelson application
83-
nelsonApp?.kill();
102+
cleanup(true);
84103
break;
85104
default:
86105
// Log unknown message types
@@ -93,6 +112,7 @@ function startNelsonProcess() {
93112
* @param {number} port - Port number for socket connection
94113
*/
95114
function handleInitialization(port) {
115+
hasCleaned = false;
96116
// Set up socket connection
97117
const { io: socketIOInstance, address: commandAddress } =
98118
initializeSocket(port);
@@ -106,6 +126,13 @@ function startNelsonProcess() {
106126
// Determine and spawn Nelson application
107127
const { app, parameters } = getAppAndParameters(commandAddress);
108128
nelsonApp = spawn(app, parameters);
129+
nelsonApp.on('exit', (code, signal) => {
130+
process.send?.({ msgtype: 'process_exit', code, signal });
131+
cleanup();
132+
});
133+
nelsonApp.on('error', (error) => {
134+
process.send?.({ msgtype: 'process_error', error: error.message });
135+
});
109136

110137
// Handle socket disconnection
111138
commandio.on('disconnect', () => {
@@ -120,24 +147,15 @@ function startNelsonProcess() {
120147
*/
121148
function initializeSocket(port) {
122149
// Create Socket.IO instance
123-
const commandio = socketio(port);
124-
125-
// Find first external IPv4 network interface
126-
const networkInterfaces = os.networkInterfaces();
127-
const ipv4 = Object.values(networkInterfaces)
128-
.flat()
129-
.find((details) => details.family === 'IPv4' && !details.internal);
130-
131-
// Throw error if no external IPv4 address found
132-
if (!ipv4) {
133-
throw new Error('No external IPv4 address found.');
134-
}
135-
136-
// Create address object
137-
const addr = new Address4(ipv4.address);
150+
const ioInstance = socketio(port);
151+
const addressInfo = resolveNetworkAddress();
152+
const addressString =
153+
addressInfo.family === 'IPv6'
154+
? `http://[${addressInfo.address.correctForm()}]:${port}`
155+
: `http://${addressInfo.address.address}:${port}`;
138156
return {
139-
io: commandio,
140-
address: `http://${addr.address}:${port}`,
157+
io: ioInstance,
158+
address: addressString,
141159
};
142160
}
143161
//=============================================================================
@@ -153,15 +171,45 @@ function startNelsonProcess() {
153171
: CONFIGURATION.NELSON_APPLICATION;
154172

155173
// Get corresponding parameters
156-
const parameters = CONFIGURATION.USE_DOCKER
174+
const baseParameters = CONFIGURATION.USE_DOCKER
157175
? CONFIGURATION.DOCKER_PARAMETERS
158176
: CONFIGURATION.NELSON_APPLICATION_PARAMETERS;
159177

160-
// Append command address to parameters
161-
parameters.push(commandAddress);
178+
const parameters = [...(baseParameters ?? []), commandAddress];
162179
return { app, parameters };
163180
}
164181
//=============================================================================
182+
/**
183+
* Resolve network address for the socket connection
184+
* Favors IPv4 over IPv6, and external over internal addresses
185+
* @returns {Object} Resolved address and family (IPv4/IPv6)
186+
*/
187+
function resolveNetworkAddress() {
188+
const interfaces = Object.values(os.networkInterfaces())
189+
.flat()
190+
.filter(Boolean);
191+
const candidate =
192+
interfaces.find((details) => details.family === 'IPv4' && !details.internal) ??
193+
interfaces.find((details) => details.family === 'IPv6' && !details.internal) ??
194+
interfaces.find((details) => details.family === 'IPv4') ??
195+
interfaces.find((details) => details.family === 'IPv6');
196+
197+
if (!candidate || typeof candidate.address !== 'string') {
198+
throw new Error('No network address available.');
199+
}
200+
201+
const addressValue = candidate.address.includes('%')
202+
? candidate.address.split('%')[0]
203+
: candidate.address;
204+
205+
const address =
206+
candidate.family === 'IPv6'
207+
? new Address6(addressValue)
208+
: new Address4(addressValue);
209+
210+
return { address, family: candidate.family };
211+
}
212+
//=============================================================================
165213
}
166214
//=============================================================================
167215
/**

0 commit comments

Comments
 (0)