dashcam 1.3.8-beta → 1.3.10-beta
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 +1 -1
- package/bin/dashcam-background.js +0 -196
- package/lib/processManager.js +0 -340
package/package.json
CHANGED
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Background recording process for dashcam CLI
|
|
4
|
-
* This script runs detached from the parent process to handle long-running recordings
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { startRecording, stopRecording } from '../lib/recorder.js';
|
|
8
|
-
import { upload } from '../lib/uploader.js';
|
|
9
|
-
import { logger, setVerbose } from '../lib/logger.js';
|
|
10
|
-
import fs from 'fs';
|
|
11
|
-
import path from 'path';
|
|
12
|
-
import os from 'os';
|
|
13
|
-
|
|
14
|
-
// Get process directory for status files
|
|
15
|
-
// Use a fixed system-wide directory for cross-process communication
|
|
16
|
-
// On Windows: C:\ProgramData\dashcam-cli
|
|
17
|
-
// On Unix: /tmp/dashcam-cli
|
|
18
|
-
const PROCESS_DIR = process.platform === 'win32'
|
|
19
|
-
? path.join('C:', 'ProgramData', 'dashcam-cli')
|
|
20
|
-
: path.join('/tmp', 'dashcam-cli');
|
|
21
|
-
const PID_FILE = path.join(PROCESS_DIR, 'recording.pid');
|
|
22
|
-
const STATUS_FILE = path.join(PROCESS_DIR, 'status.json');
|
|
23
|
-
const RESULT_FILE = path.join(PROCESS_DIR, 'upload-result.json');
|
|
24
|
-
|
|
25
|
-
// Ensure process directory exists
|
|
26
|
-
if (!fs.existsSync(PROCESS_DIR)) {
|
|
27
|
-
fs.mkdirSync(PROCESS_DIR, { recursive: true });
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Parse options from command line argument
|
|
31
|
-
const optionsJson = process.argv[2];
|
|
32
|
-
if (!optionsJson) {
|
|
33
|
-
console.error('No options provided to background process');
|
|
34
|
-
process.exit(1);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const options = JSON.parse(optionsJson);
|
|
38
|
-
|
|
39
|
-
// Enable verbose logging in background
|
|
40
|
-
setVerbose(true);
|
|
41
|
-
|
|
42
|
-
logger.info('Background recording process started', {
|
|
43
|
-
pid: process.pid,
|
|
44
|
-
options
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
// Write PID file immediately
|
|
48
|
-
try {
|
|
49
|
-
fs.writeFileSync(PID_FILE, process.pid.toString());
|
|
50
|
-
logger.info('PID file written', { path: PID_FILE, pid: process.pid });
|
|
51
|
-
} catch (error) {
|
|
52
|
-
logger.error('Failed to write PID file', { error });
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Write status file
|
|
56
|
-
function writeStatus(status) {
|
|
57
|
-
try {
|
|
58
|
-
fs.writeFileSync(STATUS_FILE, JSON.stringify({
|
|
59
|
-
...status,
|
|
60
|
-
timestamp: Date.now(),
|
|
61
|
-
pid: process.pid
|
|
62
|
-
}, null, 2));
|
|
63
|
-
} catch (error) {
|
|
64
|
-
logger.error('Failed to write status file', { error });
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Write upload result file
|
|
69
|
-
function writeUploadResult(result) {
|
|
70
|
-
try {
|
|
71
|
-
logger.info('Writing upload result to file', { path: RESULT_FILE, shareLink: result.shareLink });
|
|
72
|
-
fs.writeFileSync(RESULT_FILE, JSON.stringify({
|
|
73
|
-
...result,
|
|
74
|
-
timestamp: Date.now()
|
|
75
|
-
}, null, 2));
|
|
76
|
-
logger.info('Successfully wrote upload result to file');
|
|
77
|
-
} catch (error) {
|
|
78
|
-
logger.error('Failed to write upload result file', { error });
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Main recording function
|
|
83
|
-
async function runBackgroundRecording() {
|
|
84
|
-
let recordingResult = null;
|
|
85
|
-
let isShuttingDown = false;
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
// Start the recording
|
|
89
|
-
const recordingOptions = {
|
|
90
|
-
fps: parseInt(options.fps) || 10,
|
|
91
|
-
includeAudio: options.audio || false,
|
|
92
|
-
customOutputPath: options.output || null
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
logger.info('Starting recording with options', { recordingOptions });
|
|
96
|
-
|
|
97
|
-
recordingResult = await startRecording(recordingOptions);
|
|
98
|
-
|
|
99
|
-
// Write status to track the recording
|
|
100
|
-
writeStatus({
|
|
101
|
-
isRecording: true,
|
|
102
|
-
startTime: recordingResult.startTime,
|
|
103
|
-
options,
|
|
104
|
-
pid: process.pid,
|
|
105
|
-
outputPath: recordingResult.outputPath
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
logger.info('Recording started successfully', {
|
|
109
|
-
outputPath: recordingResult.outputPath,
|
|
110
|
-
startTime: recordingResult.startTime
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
// Set up signal handlers for graceful shutdown
|
|
114
|
-
const handleShutdown = async (signal) => {
|
|
115
|
-
if (isShuttingDown) {
|
|
116
|
-
logger.info('Shutdown already in progress...');
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
isShuttingDown = true;
|
|
120
|
-
|
|
121
|
-
logger.info(`Received ${signal}, stopping background recording...`);
|
|
122
|
-
|
|
123
|
-
try {
|
|
124
|
-
// Stop the recording
|
|
125
|
-
const stopResult = await stopRecording();
|
|
126
|
-
|
|
127
|
-
if (stopResult) {
|
|
128
|
-
logger.info('Recording stopped successfully', {
|
|
129
|
-
outputPath: stopResult.outputPath,
|
|
130
|
-
duration: stopResult.duration
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
// Upload the recording
|
|
134
|
-
logger.info('Starting upload...');
|
|
135
|
-
const uploadResult = await upload(stopResult.outputPath, {
|
|
136
|
-
title: options.title || 'Dashcam Recording',
|
|
137
|
-
description: options.description || 'Recorded with Dashcam CLI',
|
|
138
|
-
project: options.project || options.k,
|
|
139
|
-
duration: stopResult.duration,
|
|
140
|
-
clientStartDate: stopResult.clientStartDate,
|
|
141
|
-
apps: stopResult.apps,
|
|
142
|
-
logs: stopResult.logs,
|
|
143
|
-
gifPath: stopResult.gifPath,
|
|
144
|
-
snapshotPath: stopResult.snapshotPath
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
logger.info('Upload complete', { shareLink: uploadResult.shareLink });
|
|
148
|
-
|
|
149
|
-
// Write upload result for stop command to read
|
|
150
|
-
writeUploadResult({
|
|
151
|
-
shareLink: uploadResult.shareLink,
|
|
152
|
-
replayId: uploadResult.replay?.id
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Update status to indicate recording stopped
|
|
157
|
-
writeStatus({
|
|
158
|
-
isRecording: false,
|
|
159
|
-
completedTime: Date.now(),
|
|
160
|
-
pid: process.pid
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
logger.info('Background process exiting successfully');
|
|
164
|
-
process.exit(0);
|
|
165
|
-
} catch (error) {
|
|
166
|
-
logger.error('Error during shutdown:', error);
|
|
167
|
-
process.exit(1);
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
process.on('SIGINT', () => handleShutdown('SIGINT'));
|
|
172
|
-
process.on('SIGTERM', () => handleShutdown('SIGTERM'));
|
|
173
|
-
|
|
174
|
-
// Keep the process alive
|
|
175
|
-
logger.info('Background recording is now running. Waiting for stop signal...');
|
|
176
|
-
await new Promise(() => {}); // Wait indefinitely for signals
|
|
177
|
-
|
|
178
|
-
} catch (error) {
|
|
179
|
-
logger.error('Background recording failed:', error);
|
|
180
|
-
|
|
181
|
-
// Update status to indicate failure
|
|
182
|
-
writeStatus({
|
|
183
|
-
isRecording: false,
|
|
184
|
-
error: error.message,
|
|
185
|
-
pid: process.pid
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
process.exit(1);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// Run the background recording
|
|
193
|
-
runBackgroundRecording().catch(error => {
|
|
194
|
-
logger.error('Fatal error in background process:', error);
|
|
195
|
-
process.exit(1);
|
|
196
|
-
});
|
package/lib/processManager.js
DELETED
|
@@ -1,340 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import os from 'os';
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
5
|
-
import { spawn } from 'child_process';
|
|
6
|
-
import { logger } from './logger.js';
|
|
7
|
-
|
|
8
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
-
const __dirname = path.dirname(__filename);
|
|
10
|
-
|
|
11
|
-
// Use a fixed system-wide directory for cross-process communication
|
|
12
|
-
// On Windows: C:\ProgramData\dashcam-cli
|
|
13
|
-
// On Unix: /tmp/dashcam-cli
|
|
14
|
-
const PROCESS_DIR = process.platform === 'win32'
|
|
15
|
-
? path.join('C:', 'ProgramData', 'dashcam-cli')
|
|
16
|
-
: path.join('/tmp', 'dashcam-cli');
|
|
17
|
-
const PID_FILE = path.join(PROCESS_DIR, 'recording.pid');
|
|
18
|
-
const STATUS_FILE = path.join(PROCESS_DIR, 'status.json');
|
|
19
|
-
const RESULT_FILE = path.join(PROCESS_DIR, 'upload-result.json');
|
|
20
|
-
|
|
21
|
-
// Ensure process directory exists
|
|
22
|
-
if (!fs.existsSync(PROCESS_DIR)) {
|
|
23
|
-
fs.mkdirSync(PROCESS_DIR, { recursive: true });
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
class ProcessManager {
|
|
27
|
-
constructor() {
|
|
28
|
-
this.isBackgroundMode = false;
|
|
29
|
-
this.isStopping = false;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
setBackgroundMode(enabled = true) {
|
|
33
|
-
this.isBackgroundMode = enabled;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
writeStatus(status) {
|
|
37
|
-
try {
|
|
38
|
-
fs.writeFileSync(STATUS_FILE, JSON.stringify({
|
|
39
|
-
...status,
|
|
40
|
-
timestamp: Date.now(),
|
|
41
|
-
pid: process.pid
|
|
42
|
-
}, null, 2));
|
|
43
|
-
} catch (error) {
|
|
44
|
-
logger.error('Failed to write status file', { error });
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
readStatus() {
|
|
49
|
-
try {
|
|
50
|
-
if (!fs.existsSync(STATUS_FILE)) return null;
|
|
51
|
-
const data = fs.readFileSync(STATUS_FILE, 'utf8');
|
|
52
|
-
return JSON.parse(data);
|
|
53
|
-
} catch (error) {
|
|
54
|
-
logger.error('Failed to read status file', { error });
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
writeUploadResult(result) {
|
|
60
|
-
try {
|
|
61
|
-
logger.info('Writing upload result to file', { path: RESULT_FILE, shareLink: result.shareLink });
|
|
62
|
-
fs.writeFileSync(RESULT_FILE, JSON.stringify({
|
|
63
|
-
...result,
|
|
64
|
-
timestamp: Date.now()
|
|
65
|
-
}, null, 2));
|
|
66
|
-
logger.info('Successfully wrote upload result to file');
|
|
67
|
-
// Verify it was written
|
|
68
|
-
if (fs.existsSync(RESULT_FILE)) {
|
|
69
|
-
logger.info('Verified upload result file exists');
|
|
70
|
-
} else {
|
|
71
|
-
logger.error('Upload result file does not exist after write!');
|
|
72
|
-
}
|
|
73
|
-
} catch (error) {
|
|
74
|
-
logger.error('Failed to write upload result file', { error });
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
readUploadResult() {
|
|
79
|
-
try {
|
|
80
|
-
if (!fs.existsSync(RESULT_FILE)) return null;
|
|
81
|
-
const data = fs.readFileSync(RESULT_FILE, 'utf8');
|
|
82
|
-
return JSON.parse(data);
|
|
83
|
-
} catch (error) {
|
|
84
|
-
logger.error('Failed to read upload result file', { error });
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
writePid(pid = process.pid) {
|
|
90
|
-
try {
|
|
91
|
-
fs.writeFileSync(PID_FILE, pid.toString());
|
|
92
|
-
} catch (error) {
|
|
93
|
-
logger.error('Failed to write PID file', { error });
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
readPid() {
|
|
98
|
-
try {
|
|
99
|
-
if (!fs.existsSync(PID_FILE)) return null;
|
|
100
|
-
const pid = parseInt(fs.readFileSync(PID_FILE, 'utf8').trim());
|
|
101
|
-
return isNaN(pid) ? null : pid;
|
|
102
|
-
} catch (error) {
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
isProcessRunning(pid) {
|
|
108
|
-
if (!pid) return false;
|
|
109
|
-
try {
|
|
110
|
-
process.kill(pid, 0); // Signal 0 just checks if process exists
|
|
111
|
-
return true;
|
|
112
|
-
} catch (error) {
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
isRecordingActive() {
|
|
118
|
-
const status = this.readStatus();
|
|
119
|
-
|
|
120
|
-
if (!status || !status.pid) {
|
|
121
|
-
// Clean up but preserve upload result in case the background process just finished uploading
|
|
122
|
-
this.cleanup({ preserveResult: true });
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const pid = status.pid;
|
|
127
|
-
|
|
128
|
-
if (!this.isProcessRunning(pid)) {
|
|
129
|
-
// Clean up but preserve upload result in case the background process just finished uploading
|
|
130
|
-
this.cleanup({ preserveResult: true });
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return status.isRecording;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
getActiveStatus() {
|
|
138
|
-
if (!this.isRecordingActive()) return null;
|
|
139
|
-
return this.readStatus();
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
cleanup(options = {}) {
|
|
143
|
-
const { preserveResult = false } = options;
|
|
144
|
-
try {
|
|
145
|
-
if (fs.existsSync(PID_FILE)) fs.unlinkSync(PID_FILE);
|
|
146
|
-
if (fs.existsSync(STATUS_FILE)) fs.unlinkSync(STATUS_FILE);
|
|
147
|
-
if (!preserveResult && fs.existsSync(RESULT_FILE)) fs.unlinkSync(RESULT_FILE);
|
|
148
|
-
} catch (error) {
|
|
149
|
-
logger.error('Failed to cleanup process files', { error });
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
async stopActiveRecording() {
|
|
154
|
-
if (this.isStopping) {
|
|
155
|
-
logger.info('Stop already in progress, ignoring additional stop request');
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
this.isStopping = true;
|
|
160
|
-
|
|
161
|
-
try {
|
|
162
|
-
const status = this.readStatus();
|
|
163
|
-
|
|
164
|
-
if (!status || !status.isRecording) {
|
|
165
|
-
logger.warn('No active recording found');
|
|
166
|
-
return false;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const pid = status.pid;
|
|
170
|
-
|
|
171
|
-
if (!pid || !this.isProcessRunning(pid)) {
|
|
172
|
-
logger.warn('Background process not running');
|
|
173
|
-
this.cleanup({ preserveResult: true });
|
|
174
|
-
return false;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
logger.info('Sending stop signal to background process', { pid });
|
|
178
|
-
|
|
179
|
-
// Send SIGTERM to the background process to trigger graceful shutdown
|
|
180
|
-
try {
|
|
181
|
-
process.kill(pid, 'SIGTERM');
|
|
182
|
-
logger.info('Sent SIGTERM to background process');
|
|
183
|
-
} catch (error) {
|
|
184
|
-
logger.error('Failed to send signal to background process', { error });
|
|
185
|
-
throw new Error('Failed to stop background recording process');
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Wait for the background process to finish and write results
|
|
189
|
-
logger.debug('Waiting for background process to complete...');
|
|
190
|
-
const maxWaitTime = 30000; // 30 seconds
|
|
191
|
-
const startWait = Date.now();
|
|
192
|
-
|
|
193
|
-
while (this.isProcessRunning(pid) && (Date.now() - startWait) < maxWaitTime) {
|
|
194
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
if (this.isProcessRunning(pid)) {
|
|
198
|
-
logger.error('Background process did not exit within timeout, forcing kill');
|
|
199
|
-
try {
|
|
200
|
-
process.kill(pid, 'SIGKILL');
|
|
201
|
-
} catch (error) {
|
|
202
|
-
logger.error('Failed to force kill background process', { error });
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
logger.info('Background process stopped');
|
|
207
|
-
|
|
208
|
-
// Return a minimal result indicating success
|
|
209
|
-
// The upload will be handled by the stop command checking the result file
|
|
210
|
-
return {
|
|
211
|
-
outputPath: status.outputPath,
|
|
212
|
-
duration: Date.now() - status.startTime
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
} catch (error) {
|
|
216
|
-
logger.error('Failed to stop recording', { error });
|
|
217
|
-
throw error;
|
|
218
|
-
} finally {
|
|
219
|
-
this.isStopping = false;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
async startRecording(options) {
|
|
224
|
-
// Check if recording is already active
|
|
225
|
-
if (this.isRecordingActive()) {
|
|
226
|
-
throw new Error('Recording already in progress');
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Spawn background process
|
|
230
|
-
const backgroundScriptPath = path.join(__dirname, '..', 'bin', 'dashcam-background.js');
|
|
231
|
-
|
|
232
|
-
logger.info('Starting background recording process', {
|
|
233
|
-
backgroundScriptPath,
|
|
234
|
-
options
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
// Serialize options to pass to background process
|
|
238
|
-
const optionsJson = JSON.stringify(options);
|
|
239
|
-
|
|
240
|
-
// Determine node executable path
|
|
241
|
-
const nodePath = process.execPath;
|
|
242
|
-
|
|
243
|
-
// Create log file for background process output
|
|
244
|
-
const logDir = path.join(PROCESS_DIR, 'logs');
|
|
245
|
-
if (!fs.existsSync(logDir)) {
|
|
246
|
-
fs.mkdirSync(logDir, { recursive: true });
|
|
247
|
-
}
|
|
248
|
-
const logFile = path.join(logDir, `recording-${Date.now()}.log`);
|
|
249
|
-
const logStream = fs.createWriteStream(logFile, { flags: 'a' });
|
|
250
|
-
|
|
251
|
-
logger.info('Background process log file', { logFile });
|
|
252
|
-
|
|
253
|
-
// Spawn the background process with proper detachment
|
|
254
|
-
const child = spawn(
|
|
255
|
-
nodePath,
|
|
256
|
-
[backgroundScriptPath, optionsJson],
|
|
257
|
-
{
|
|
258
|
-
detached: true, // Detach from parent on Unix-like systems
|
|
259
|
-
stdio: ['ignore', logStream, logStream], // Redirect output to log file
|
|
260
|
-
windowsHide: true, // Hide console window on Windows
|
|
261
|
-
shell: false // Don't use shell to avoid extra process wrapper
|
|
262
|
-
}
|
|
263
|
-
);
|
|
264
|
-
|
|
265
|
-
// Unref to allow parent to exit independently
|
|
266
|
-
child.unref();
|
|
267
|
-
|
|
268
|
-
const pid = child.pid;
|
|
269
|
-
|
|
270
|
-
logger.info('Background process spawned', {
|
|
271
|
-
pid,
|
|
272
|
-
logFile,
|
|
273
|
-
detached: true
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
// Wait for status file to be created by background process
|
|
277
|
-
logger.debug('Waiting for background process to write status file...');
|
|
278
|
-
const maxWaitTime = 10000; // 10 seconds
|
|
279
|
-
const startWait = Date.now();
|
|
280
|
-
let statusCreated = false;
|
|
281
|
-
|
|
282
|
-
while (!statusCreated && (Date.now() - startWait) < maxWaitTime) {
|
|
283
|
-
const status = this.readStatus();
|
|
284
|
-
if (status && status.isRecording && status.pid === pid) {
|
|
285
|
-
statusCreated = true;
|
|
286
|
-
logger.debug('Status file created by background process', { status });
|
|
287
|
-
break;
|
|
288
|
-
}
|
|
289
|
-
// Wait a bit before checking again
|
|
290
|
-
await new Promise(resolve => setTimeout(resolve, 200));
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
if (!statusCreated) {
|
|
294
|
-
logger.error('Background process did not create status file within timeout');
|
|
295
|
-
throw new Error('Failed to start background recording process - status file not created. Check log: ' + logFile);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// Read the status to get output path and start time
|
|
299
|
-
const status = this.readStatus();
|
|
300
|
-
|
|
301
|
-
logger.info('Recording started successfully in background', {
|
|
302
|
-
pid,
|
|
303
|
-
outputPath: status.outputPath,
|
|
304
|
-
startTime: status.startTime,
|
|
305
|
-
logFile
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
return {
|
|
309
|
-
pid,
|
|
310
|
-
outputPath: status.outputPath,
|
|
311
|
-
startTime: status.startTime,
|
|
312
|
-
logFile
|
|
313
|
-
};
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
async gracefulExit() {
|
|
317
|
-
logger.info('Graceful exit requested');
|
|
318
|
-
|
|
319
|
-
// If we're currently recording, stop it properly
|
|
320
|
-
if (this.isRecordingActive()) {
|
|
321
|
-
try {
|
|
322
|
-
logger.info('Stopping active recording before exit');
|
|
323
|
-
await this.stopActiveRecording();
|
|
324
|
-
logger.info('Recording stopped successfully during graceful exit');
|
|
325
|
-
} catch (error) {
|
|
326
|
-
logger.error('Failed to stop recording during graceful exit', { error });
|
|
327
|
-
this.cleanup(); // Fallback cleanup
|
|
328
|
-
}
|
|
329
|
-
} else {
|
|
330
|
-
// Just cleanup if no recording is active
|
|
331
|
-
this.cleanup();
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
process.exit(0);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
const processManager = new ProcessManager();
|
|
339
|
-
|
|
340
|
-
export { processManager };
|