forked from node-red/node-red
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathindex.js
More file actions
170 lines (145 loc) · 5.19 KB
/
Copy pathindex.js
File metadata and controls
170 lines (145 loc) · 5.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#!/usr/bin/env node
//james was here
const { spawn } = require('child_process');
const path = require('path');
const fs = require('fs');
const os = require('node:os');
// Resolve home path
const homePath = path.resolve(os.homedir(), '.neuron-node-builder');
// Create home directory if it doesn't exist
if (!fs.existsSync(homePath)) {
fs.mkdirSync(homePath, { recursive: true });
}
// Resolve path to the .env file
const envPath = path.resolve(os.homedir(), '.neuron-node-builder', '.env');
// Check if the .env file exists and create if needed
if (!fs.existsSync(envPath)) {
const envTemplate = path.resolve(__dirname, '.env.example');
if (fs.existsSync(envTemplate)) {
fs.copyFileSync(envTemplate, envPath);
}
}
// Load .env file
require('dotenv').config({
path: envPath,
});
// Construct binary map
const binaries = {
'win32': 'neuron-wrapper-win64.exe',
'darwin': 'neuron-wrapper-darwin64',
'linux': 'neuron-wrapper-linux64'
};
// Resolve path to the neuron-wrapper binary
const binPath = path.resolve(__dirname, 'build', 'bin', binaries[os.platform()]);
// Check if the binary exists
if (!fs.existsSync(binPath)) {
console.error(`Binary not found: ${binPath}`);
process.exit(1);
}
// Resolve path to the CLI JS file inside node_modules
const cliPath = path.resolve(__dirname, 'packages', 'node_modules', 'node-red', 'red.js');
// Pass command line args through to Node-RED
const args = [
'--settings',
path.resolve(__dirname, 'neuron-settings.js')
];
const child = spawn(process.execPath, [cliPath, ...args], {
stdio: 'inherit',
env: {
...process.env,
NEURON_SDK_PATH: binPath,
NEURON_ENV_PATH: envPath,
}
});
// Global cleanup function
async function globalCleanup(signal) {
console.log(`\n🛑 Received ${signal}, initiating graceful shutdown...`);
try {
// 1. Stop loading server if running
if (loadingServer) {
console.log('🛑 Stopping loading server...');
loadingServer.stop();
}
// 2. Stop all child processes via ProcessManager
const ProcessManager = require('./neuron/nodes/process-manager');
const processManager = new ProcessManager();
await processManager.shutdownAllProcesses();
// 3. Kill the Node-RED child process gracefully
if (child && !child.killed) {
console.log('🔄 Terminating Node-RED process...');
child.kill('SIGTERM');
// Wait for graceful shutdown, then force kill
setTimeout(() => {
if (!child.killed) {
console.log('⚡ Force killing Node-RED process...');
child.kill('SIGKILL');
}
}, 5000);
}
console.log('✅ Cleanup completed');
process.exit(0);
} catch (error) {
console.error('❌ Error during cleanup:', error.message);
process.exit(1);
}
}
// Register signal handlers for graceful shutdown
process.on('SIGTERM', () => globalCleanup('SIGTERM'));
process.on('SIGINT', () => globalCleanup('SIGINT'));
process.on('SIGHUP', () => globalCleanup('SIGHUP'));
process.on('SIGUSR1', () => globalCleanup('SIGUSR1'));
process.on('SIGUSR2', () => globalCleanup('SIGUSR2'));
// Handle uncaught exceptions and unhandled rejections
process.on('uncaughtException', (error) => {
console.error('💥 Uncaught Exception:', error);
globalCleanup('uncaughtException');
});
process.on('unhandledRejection', (reason, promise) => {
console.error('💥 Unhandled Rejection at:', promise, 'reason:', reason);
globalCleanup('unhandledRejection');
});
child.on('exit', (code) => {
if (code !== 0) {
console.error(`Node-RED process exited with code: ${code}`);
}
// Exit the parent process when Node-RED exits
process.exit(code);
});
// Track if loading page was successfully opened
let loadingPageOpened = false;
let loadingServer = null;
// Start loading server and open loading page immediately
setTimeout(() => {
try {
const LoadingServer = require('./loading-server');
const opener = require('opener');
// Start the loading server
loadingServer = new LoadingServer(1881);
if (loadingServer.start()) {
// Open the loading page in browser
const loadingUrl = loadingServer.getUrl();
opener(loadingUrl);
console.log('🌐 Loading page opened in browser');
console.log(`📁 Loading page URL: ${loadingUrl}`);
loadingPageOpened = true;
} else {
console.log('⚠️ Loading server failed to start, will open Node-RED directly when ready');
loadingPageOpened = false;
}
} catch (err) {
console.error('❌ Failed to start loading server:', err.message);
loadingPageOpened = false;
}
}, 500); // Start loading server almost immediately (0.5 seconds)
// Fallback: Open Node-RED when it's ready (only if loading page wasn't opened)
setTimeout(() => {
if (!loadingPageOpened) {
try {
const opener = require('opener');
opener('http://localhost:1880');
console.log('🌐 Node-RED opened in browser (fallback)');
} catch (err) {
console.error('❌ Failed to open Node-RED:', err.message);
}
}
}, 3000); // Wait 3 seconds for Node-RED to start up