dashcam 1.3.28 → 1.3.29
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/bin/dashcam-background.js +2 -19
- package/bin/dashcam.js +48 -21
- package/lib/processManager.js +14 -26
- package/package.json +1 -1
|
@@ -14,7 +14,6 @@ import os from 'os';
|
|
|
14
14
|
const PROCESS_DIR = path.join(os.homedir(), '.dashcam-cli');
|
|
15
15
|
const STATUS_FILE = path.join(PROCESS_DIR, 'status.json');
|
|
16
16
|
const RESULT_FILE = path.join(PROCESS_DIR, 'recording-result.json');
|
|
17
|
-
const STOP_REQUEST_FILE = path.join(PROCESS_DIR, 'stop-request.txt');
|
|
18
17
|
|
|
19
18
|
console.log('[Background INIT] Process directory:', PROCESS_DIR);
|
|
20
19
|
console.log('[Background INIT] Status file:', STATUS_FILE);
|
|
@@ -218,26 +217,10 @@ async function runBackgroundRecording() {
|
|
|
218
217
|
process.on('SIGINT', () => handleShutdown('SIGINT'));
|
|
219
218
|
process.on('SIGTERM', () => handleShutdown('SIGTERM'));
|
|
220
219
|
|
|
221
|
-
// Keep the process alive - wait indefinitely for
|
|
222
|
-
// Also poll for stop request file (for Windows compatibility)
|
|
220
|
+
// Keep the process alive - wait indefinitely for SIGKILL from stop command
|
|
223
221
|
logger.info('Background recording is now running. Waiting for stop signal...');
|
|
224
222
|
console.log('[Background] Waiting for stop signal...');
|
|
225
223
|
|
|
226
|
-
// Poll for stop request file every 500ms (Windows SIGTERM workaround)
|
|
227
|
-
const pollInterval = setInterval(() => {
|
|
228
|
-
if (fs.existsSync(STOP_REQUEST_FILE)) {
|
|
229
|
-
console.log('[Background] Stop request file detected');
|
|
230
|
-
clearInterval(pollInterval);
|
|
231
|
-
// Delete the stop request file
|
|
232
|
-
try {
|
|
233
|
-
fs.unlinkSync(STOP_REQUEST_FILE);
|
|
234
|
-
} catch (e) {
|
|
235
|
-
// Ignore deletion errors
|
|
236
|
-
}
|
|
237
|
-
handleShutdown('STOP_FILE');
|
|
238
|
-
}
|
|
239
|
-
}, 500);
|
|
240
|
-
|
|
241
224
|
} catch (error) {
|
|
242
225
|
logger.error('Background recording setup failed:', error);
|
|
243
226
|
console.error('[Background] Recording setup failed:', error.message);
|
|
@@ -252,7 +235,7 @@ async function runBackgroundRecording() {
|
|
|
252
235
|
process.exit(1);
|
|
253
236
|
}
|
|
254
237
|
|
|
255
|
-
// Infinite loop - process will only exit via signal handlers
|
|
238
|
+
// Infinite loop - process will only exit via signal handlers or stop file
|
|
256
239
|
await new Promise(() => {});
|
|
257
240
|
}
|
|
258
241
|
|
package/bin/dashcam.js
CHANGED
|
@@ -469,36 +469,63 @@ program
|
|
|
469
469
|
console.log('Recording stopped successfully');
|
|
470
470
|
logger.debug('Stop result:', result);
|
|
471
471
|
|
|
472
|
-
//
|
|
473
|
-
|
|
474
|
-
|
|
472
|
+
// Reconstruct recording data from status and fix video with FFmpeg
|
|
473
|
+
console.log('Processing recording...');
|
|
474
|
+
logger.debug('Reconstructing recording data from status file');
|
|
475
475
|
|
|
476
|
-
|
|
477
|
-
const
|
|
478
|
-
const
|
|
479
|
-
let recordingResult = null;
|
|
480
|
-
let checkCount = 0;
|
|
476
|
+
const { fixVideoContainer } = await import('../lib/recorder.js');
|
|
477
|
+
const { applicationTracker } = await import('../lib/applicationTracker.js');
|
|
478
|
+
const { logsTrackerManager } = await import('../lib/logs/index.js');
|
|
481
479
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
480
|
+
// Get temp file path
|
|
481
|
+
const tempFileInfoPath = path.join(os.tmpdir(), 'dashcam', 'temp-file.json');
|
|
482
|
+
let tempFileInfo = null;
|
|
483
|
+
try {
|
|
484
|
+
tempFileInfo = JSON.parse(fs.readFileSync(tempFileInfoPath, 'utf8'));
|
|
485
|
+
} catch (error) {
|
|
486
|
+
logger.error('Failed to read temp file info', { error });
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const tempFile = tempFileInfo?.tempFile || result.outputPath.replace('.webm', '-temp.webm');
|
|
490
|
+
const outputPath = result.outputPath;
|
|
491
|
+
|
|
492
|
+
// Fix the video with FFmpeg (handle incomplete recordings)
|
|
493
|
+
logger.info('Fixing video with FFmpeg', { tempFile, outputPath });
|
|
494
|
+
if (fs.existsSync(tempFile)) {
|
|
495
|
+
try {
|
|
496
|
+
await fixVideoContainer(tempFile, outputPath);
|
|
497
|
+
logger.info('Video fixed successfully');
|
|
498
|
+
} catch (error) {
|
|
499
|
+
logger.warn('FFmpeg fix failed, using temp file as-is', { error: error.message });
|
|
500
|
+
// If fix fails, just copy the temp file
|
|
501
|
+
fs.copyFileSync(tempFile, outputPath);
|
|
492
502
|
}
|
|
503
|
+
} else {
|
|
504
|
+
logger.warn('Temp file not found, using output path directly', { tempFile });
|
|
493
505
|
}
|
|
494
506
|
|
|
507
|
+
// Collect application and log data
|
|
508
|
+
const apps = await applicationTracker.getApps(activeStatus.startTime);
|
|
509
|
+
const logs = await logsTrackerManager.getLogsForRecording();
|
|
510
|
+
|
|
511
|
+
const recordingResult = {
|
|
512
|
+
outputPath,
|
|
513
|
+
duration: result.duration,
|
|
514
|
+
clientStartDate: activeStatus.startTime,
|
|
515
|
+
apps,
|
|
516
|
+
logs,
|
|
517
|
+
title: activeStatus?.options?.title,
|
|
518
|
+
description: activeStatus?.options?.description,
|
|
519
|
+
project: activeStatus?.options?.project
|
|
520
|
+
};
|
|
521
|
+
|
|
495
522
|
if (!recordingResult || !recordingResult.outputPath) {
|
|
496
|
-
console.error('Failed to
|
|
497
|
-
logger.error('No recording result
|
|
523
|
+
console.error('Failed to process recording');
|
|
524
|
+
logger.error('No recording result', { recordingResult });
|
|
498
525
|
process.exit(1);
|
|
499
526
|
}
|
|
500
527
|
|
|
501
|
-
console.log('
|
|
528
|
+
console.log('Uploading recording...');
|
|
502
529
|
logger.debug('Recording result:', recordingResult);
|
|
503
530
|
|
|
504
531
|
try {
|
package/lib/processManager.js
CHANGED
|
@@ -11,8 +11,7 @@ const __dirname = path.dirname(__filename);
|
|
|
11
11
|
// Use user home directory for cross-session communication
|
|
12
12
|
const PROCESS_DIR = path.join(os.homedir(), '.dashcam-cli');
|
|
13
13
|
const STATUS_FILE = path.join(PROCESS_DIR, 'status.json');
|
|
14
|
-
const
|
|
15
|
-
const STOP_REQUEST_FILE = path.join(PROCESS_DIR, 'stop-request.txt');
|
|
14
|
+
const RECORDING_RESULT_FILE = path.join(PROCESS_DIR, 'recording-result.json');
|
|
16
15
|
|
|
17
16
|
console.log('[INIT] Process Manager initialized');
|
|
18
17
|
console.log('[INIT] Process directory:', PROCESS_DIR);
|
|
@@ -282,44 +281,33 @@ class ProcessManager {
|
|
|
282
281
|
return false;
|
|
283
282
|
}
|
|
284
283
|
|
|
285
|
-
logger.info('
|
|
284
|
+
logger.info('Killing background process', { pid });
|
|
286
285
|
|
|
287
|
-
//
|
|
286
|
+
// Kill the process immediately - no graceful shutdown needed
|
|
287
|
+
// Video is already being streamed to disk, we'll fix it with FFmpeg
|
|
288
288
|
try {
|
|
289
|
-
|
|
290
|
-
logger.
|
|
289
|
+
process.kill(pid, 'SIGKILL');
|
|
290
|
+
logger.info('Sent SIGKILL to background process');
|
|
291
291
|
} catch (error) {
|
|
292
|
-
logger.error('Failed to
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// Send SIGTERM to the background process to trigger graceful shutdown (Unix/Mac)
|
|
296
|
-
try {
|
|
297
|
-
process.kill(pid, 'SIGTERM');
|
|
298
|
-
logger.info('Sent SIGTERM to background process');
|
|
299
|
-
} catch (error) {
|
|
300
|
-
logger.error('Failed to send signal to background process', { error });
|
|
292
|
+
logger.error('Failed to kill background process', { error });
|
|
301
293
|
throw new Error('Failed to stop background recording process');
|
|
302
294
|
}
|
|
303
295
|
|
|
304
|
-
// Wait for
|
|
305
|
-
logger.debug('Waiting for background process to
|
|
306
|
-
const maxWaitTime =
|
|
296
|
+
// Wait briefly for process to die
|
|
297
|
+
logger.debug('Waiting for background process to exit...');
|
|
298
|
+
const maxWaitTime = 5000; // 5 seconds should be plenty for SIGKILL
|
|
307
299
|
const startWait = Date.now();
|
|
308
300
|
|
|
309
301
|
while (this.isProcessRunning(pid) && (Date.now() - startWait) < maxWaitTime) {
|
|
310
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
302
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
311
303
|
}
|
|
312
304
|
|
|
313
305
|
if (this.isProcessRunning(pid)) {
|
|
314
|
-
logger.error('Background process did not exit
|
|
315
|
-
|
|
316
|
-
process.kill(pid, 'SIGKILL');
|
|
317
|
-
} catch (error) {
|
|
318
|
-
logger.error('Failed to force kill background process', { error });
|
|
319
|
-
}
|
|
306
|
+
logger.error('Background process did not exit after SIGKILL');
|
|
307
|
+
throw new Error('Failed to kill background process');
|
|
320
308
|
}
|
|
321
309
|
|
|
322
|
-
logger.info('Background process
|
|
310
|
+
logger.info('Background process killed');
|
|
323
311
|
|
|
324
312
|
// Mark status as completed
|
|
325
313
|
this.markStatusCompleted({
|