hedgequantx 2.9.162 → 2.9.163
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -37,15 +37,20 @@ class RithmicBrokerClient extends EventEmitter {
|
|
|
37
37
|
// Ensure daemon is running
|
|
38
38
|
const daemonStatus = await manager.ensureRunning();
|
|
39
39
|
if (!daemonStatus.success) {
|
|
40
|
-
|
|
40
|
+
const errorMsg = daemonStatus.error || 'Failed to start daemon';
|
|
41
|
+
return { success: false, error: `Daemon error: ${errorMsg}` };
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
return new Promise((resolve) => {
|
|
44
|
-
|
|
45
|
+
try {
|
|
46
|
+
this.ws = new WebSocket(`ws://127.0.0.1:${BROKER_PORT}`);
|
|
47
|
+
} catch (err) {
|
|
48
|
+
return resolve({ success: false, error: `WebSocket create error: ${err.message}` });
|
|
49
|
+
}
|
|
45
50
|
|
|
46
51
|
const timeout = setTimeout(() => {
|
|
47
52
|
this.ws?.terminate();
|
|
48
|
-
resolve({ success: false, error:
|
|
53
|
+
resolve({ success: false, error: `Connection timeout (port ${BROKER_PORT})` });
|
|
49
54
|
}, 5000);
|
|
50
55
|
|
|
51
56
|
this.ws.on('open', () => {
|
|
@@ -64,7 +69,7 @@ class RithmicBrokerClient extends EventEmitter {
|
|
|
64
69
|
this.ws.on('error', (err) => {
|
|
65
70
|
clearTimeout(timeout);
|
|
66
71
|
this.connected = false;
|
|
67
|
-
resolve({ success: false, error: err.message });
|
|
72
|
+
resolve({ success: false, error: `Daemon connection failed: ${err.message}` });
|
|
68
73
|
});
|
|
69
74
|
});
|
|
70
75
|
}
|
|
@@ -67,16 +67,35 @@ class RithmicBrokerDaemon {
|
|
|
67
67
|
|
|
68
68
|
if (!fs.existsSync(BROKER_DIR)) fs.mkdirSync(BROKER_DIR, { recursive: true });
|
|
69
69
|
fs.writeFileSync(PID_FILE, String(process.pid));
|
|
70
|
+
log('INFO', 'Starting daemon...', { pid: process.pid });
|
|
70
71
|
|
|
71
72
|
// Restore connections from state (with cached accounts - no API spam)
|
|
72
|
-
|
|
73
|
+
try {
|
|
74
|
+
await this.reconnectManager.restoreConnections(STATE_FILE);
|
|
75
|
+
} catch (e) {
|
|
76
|
+
log('WARN', 'Failed to restore connections', { error: e.message });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Create WebSocket server with proper error handling
|
|
80
|
+
try {
|
|
81
|
+
this.wss = new WebSocket.Server({ port: BROKER_PORT, host: '127.0.0.1' });
|
|
82
|
+
} catch (e) {
|
|
83
|
+
log('ERROR', 'Failed to create WebSocket server', { error: e.message, port: BROKER_PORT });
|
|
84
|
+
throw e;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Wait for server to be listening
|
|
88
|
+
await new Promise((resolve, reject) => {
|
|
89
|
+
const timeout = setTimeout(() => reject(new Error('WSS listen timeout')), 5000);
|
|
90
|
+
this.wss.on('listening', () => { clearTimeout(timeout); resolve(); });
|
|
91
|
+
this.wss.on('error', (err) => { clearTimeout(timeout); reject(err); });
|
|
92
|
+
});
|
|
73
93
|
|
|
74
|
-
this.wss = new WebSocket.Server({ port: BROKER_PORT, host: '127.0.0.1' });
|
|
75
94
|
this.wss.on('connection', (ws) => this._handleClient(ws));
|
|
76
95
|
this.wss.on('error', (err) => log('ERROR', 'WSS error', { error: err.message }));
|
|
77
96
|
|
|
78
97
|
this.running = true;
|
|
79
|
-
log('INFO', 'Daemon started', { pid: process.pid, port: BROKER_PORT });
|
|
98
|
+
log('INFO', 'Daemon started successfully', { pid: process.pid, port: BROKER_PORT });
|
|
80
99
|
|
|
81
100
|
// Save state on ANY termination signal
|
|
82
101
|
const gracefulShutdown = (signal) => {
|
|
@@ -392,8 +411,31 @@ class RithmicBrokerDaemon {
|
|
|
392
411
|
|
|
393
412
|
// Main entry point
|
|
394
413
|
if (require.main === module) {
|
|
395
|
-
|
|
396
|
-
|
|
414
|
+
// Ensure log directory exists early
|
|
415
|
+
if (!fs.existsSync(BROKER_DIR)) {
|
|
416
|
+
fs.mkdirSync(BROKER_DIR, { recursive: true });
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Log startup attempt
|
|
420
|
+
const startupLog = (msg) => {
|
|
421
|
+
const ts = new Date().toISOString();
|
|
422
|
+
fs.appendFileSync(LOG_FILE, `[${ts}] [STARTUP] ${msg}\n`);
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
startupLog(`Daemon starting (pid=${process.pid}, node=${process.version})`);
|
|
426
|
+
|
|
427
|
+
try {
|
|
428
|
+
const daemon = new RithmicBrokerDaemon();
|
|
429
|
+
daemon.start().catch((e) => {
|
|
430
|
+
startupLog(`FATAL: start() failed - ${e.message}`);
|
|
431
|
+
console.error('Daemon failed:', e.message);
|
|
432
|
+
process.exit(1);
|
|
433
|
+
});
|
|
434
|
+
} catch (e) {
|
|
435
|
+
startupLog(`FATAL: constructor failed - ${e.message}`);
|
|
436
|
+
console.error('Daemon failed:', e.message);
|
|
437
|
+
process.exit(1);
|
|
438
|
+
}
|
|
397
439
|
}
|
|
398
440
|
|
|
399
441
|
module.exports = { RithmicBrokerDaemon, BROKER_PORT, BROKER_DIR, PID_FILE, LOG_FILE, STATE_FILE };
|
|
@@ -86,21 +86,29 @@ const start = async () => {
|
|
|
86
86
|
child.unref();
|
|
87
87
|
fs.closeSync(logFd);
|
|
88
88
|
|
|
89
|
-
// Wait for daemon to start
|
|
90
|
-
|
|
89
|
+
// Wait for daemon to start (poll every 500ms, max 5s)
|
|
90
|
+
let attempts = 0;
|
|
91
|
+
const maxAttempts = 10;
|
|
92
|
+
let runStatus = { running: false, pid: null };
|
|
91
93
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
let errorDetail = 'Failed to start RithmicBroker daemon';
|
|
98
|
-
if (fs.existsSync(LOG_FILE)) {
|
|
99
|
-
const log = fs.readFileSync(LOG_FILE, 'utf8').slice(-500);
|
|
100
|
-
if (log) errorDetail += `: ${log.split('\n').filter(l => l).pop()}`;
|
|
94
|
+
while (attempts < maxAttempts) {
|
|
95
|
+
await new Promise(r => setTimeout(r, 500));
|
|
96
|
+
runStatus = await isRunning();
|
|
97
|
+
if (runStatus.running) {
|
|
98
|
+
return { success: true, error: null, pid: runStatus.pid || child.pid };
|
|
101
99
|
}
|
|
102
|
-
|
|
100
|
+
attempts++;
|
|
103
101
|
}
|
|
102
|
+
|
|
103
|
+
// Read log for error details
|
|
104
|
+
let errorDetail = 'Daemon failed to start';
|
|
105
|
+
if (fs.existsSync(LOG_FILE)) {
|
|
106
|
+
const logContent = fs.readFileSync(LOG_FILE, 'utf8');
|
|
107
|
+
const lines = logContent.split('\n').filter(l => l.trim());
|
|
108
|
+
const lastLines = lines.slice(-5).join(' | ');
|
|
109
|
+
if (lastLines) errorDetail += ` - Log: ${lastLines}`;
|
|
110
|
+
}
|
|
111
|
+
return { success: false, error: errorDetail, pid: null };
|
|
104
112
|
} catch (error) {
|
|
105
113
|
return { success: false, error: error.message, pid: null };
|
|
106
114
|
}
|