dashcam 1.0.1-beta.24 → 1.0.1-beta.26
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.js +15 -5
- package/lib/processManager.js +3 -2
- package/lib/recorder.js +7 -6
- package/lib/systemInfo.js +141 -0
- package/lib/uploader.js +11 -5
- package/package.json +2 -1
- package/test-system-info.js +105 -0
- package/sea-bundle.mjs +0 -34595
package/bin/dashcam.js
CHANGED
|
@@ -417,12 +417,22 @@ program
|
|
|
417
417
|
|
|
418
418
|
console.log('Recording stopped successfully');
|
|
419
419
|
|
|
420
|
-
// Wait
|
|
420
|
+
// Wait for upload to complete (background process handles this)
|
|
421
421
|
logger.debug('Waiting for background upload to complete...');
|
|
422
|
-
|
|
422
|
+
console.log('⏳ Uploading recording...');
|
|
423
|
+
|
|
424
|
+
// Wait up to 2 minutes for upload result to appear
|
|
425
|
+
const maxWaitForUpload = 120000; // 2 minutes
|
|
426
|
+
const startWaitForUpload = Date.now();
|
|
427
|
+
let uploadResult = null;
|
|
428
|
+
|
|
429
|
+
while (!uploadResult && (Date.now() - startWaitForUpload) < maxWaitForUpload) {
|
|
430
|
+
uploadResult = processManager.readUploadResult();
|
|
431
|
+
if (!uploadResult) {
|
|
432
|
+
await new Promise(resolve => setTimeout(resolve, 1000)); // Check every second
|
|
433
|
+
}
|
|
434
|
+
}
|
|
423
435
|
|
|
424
|
-
// Try to read the upload result from the background process
|
|
425
|
-
const uploadResult = processManager.readUploadResult();
|
|
426
436
|
logger.debug('Upload result read attempt', { found: !!uploadResult, shareLink: uploadResult?.shareLink });
|
|
427
437
|
|
|
428
438
|
if (uploadResult && uploadResult.shareLink) {
|
|
@@ -616,7 +626,7 @@ program
|
|
|
616
626
|
|
|
617
627
|
if (options.recover) {
|
|
618
628
|
// Try to recover from interrupted recording
|
|
619
|
-
const tempFileInfoPath = path.join(
|
|
629
|
+
const tempFileInfoPath = path.join(APP.configDir, 'temp-file.json');
|
|
620
630
|
|
|
621
631
|
if (fs.existsSync(tempFileInfoPath)) {
|
|
622
632
|
console.log('Found interrupted recording, attempting recovery...');
|
package/lib/processManager.js
CHANGED
|
@@ -160,8 +160,9 @@ class ProcessManager {
|
|
|
160
160
|
logger.info('Stopping active recording process', { pid });
|
|
161
161
|
process.kill(pid, 'SIGINT');
|
|
162
162
|
|
|
163
|
-
// Wait for the process to actually finish
|
|
164
|
-
|
|
163
|
+
// Wait for the process to actually finish and upload
|
|
164
|
+
// Increase timeout to allow for upload to complete
|
|
165
|
+
const maxWaitTime = 120000; // 2 minutes max to allow for upload
|
|
165
166
|
const startWait = Date.now();
|
|
166
167
|
|
|
167
168
|
while (this.isProcessRunning(pid) && (Date.now() - startWait) < maxWaitTime) {
|
package/lib/recorder.js
CHANGED
|
@@ -4,6 +4,7 @@ import { createGif, createSnapshot } from './ffmpeg.js';
|
|
|
4
4
|
import { applicationTracker } from './applicationTracker.js';
|
|
5
5
|
import { logsTrackerManager, trimLogs } from './logs/index.js';
|
|
6
6
|
import { getFfmpegPath } from './binaries.js';
|
|
7
|
+
import { APP } from './config.js';
|
|
7
8
|
import path from 'path';
|
|
8
9
|
import os from 'os';
|
|
9
10
|
import fs from 'fs';
|
|
@@ -145,8 +146,8 @@ let outputPath = null;
|
|
|
145
146
|
let recordingStartTime = null;
|
|
146
147
|
let currentTempFile = null;
|
|
147
148
|
|
|
148
|
-
// File paths - use
|
|
149
|
-
const DASHCAM_TEMP_DIR =
|
|
149
|
+
// File paths - use APP config directory for better Windows compatibility
|
|
150
|
+
const DASHCAM_TEMP_DIR = APP.configDir;
|
|
150
151
|
const TEMP_FILE_INFO_PATH = path.join(DASHCAM_TEMP_DIR, 'temp-file.json');
|
|
151
152
|
|
|
152
153
|
// Platform-specific configurations
|
|
@@ -238,12 +239,12 @@ async function getPlatformArgs({ fps, includeAudio }) {
|
|
|
238
239
|
}
|
|
239
240
|
|
|
240
241
|
/**
|
|
241
|
-
* Clear the
|
|
242
|
+
* Clear the recordings directory
|
|
242
243
|
*/
|
|
243
244
|
function clearRecordingsDirectory() {
|
|
244
245
|
const logExit = logFunctionCall('clearRecordingsDirectory');
|
|
245
246
|
|
|
246
|
-
const directory =
|
|
247
|
+
const directory = APP.recordingsDir;
|
|
247
248
|
|
|
248
249
|
try {
|
|
249
250
|
if (fs.existsSync(directory)) {
|
|
@@ -281,8 +282,8 @@ function generateOutputPath() {
|
|
|
281
282
|
const logExit = logFunctionCall('generateOutputPath');
|
|
282
283
|
|
|
283
284
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
284
|
-
// Use
|
|
285
|
-
const directory =
|
|
285
|
+
// Use APP recordings directory for consistent cross-platform location
|
|
286
|
+
const directory = APP.recordingsDir;
|
|
286
287
|
const filepath = path.join(directory, `recording-${timestamp}.webm`);
|
|
287
288
|
|
|
288
289
|
logger.verbose('Generating output path', {
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import si from 'systeminformation';
|
|
2
|
+
import { logger } from './logger.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Collects comprehensive system information including CPU, memory, OS, and graphics data.
|
|
6
|
+
* This matches the data format expected by the Dashcam backend (same as desktop app).
|
|
7
|
+
*
|
|
8
|
+
* @returns {Promise<Object>} System information object
|
|
9
|
+
*/
|
|
10
|
+
export async function getSystemInfo() {
|
|
11
|
+
try {
|
|
12
|
+
logger.debug('Collecting system information...');
|
|
13
|
+
|
|
14
|
+
// Collect only essential system information quickly
|
|
15
|
+
// Graphics info can be very slow, so we skip it or use a short timeout
|
|
16
|
+
const [cpu, mem, osInfo, system] = await Promise.all([
|
|
17
|
+
si.cpu(),
|
|
18
|
+
si.mem(),
|
|
19
|
+
si.osInfo(),
|
|
20
|
+
si.system()
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
// Try to get graphics info with a very short timeout (optional)
|
|
24
|
+
let graphics = { controllers: [], displays: [] };
|
|
25
|
+
try {
|
|
26
|
+
graphics = await Promise.race([
|
|
27
|
+
si.graphics(),
|
|
28
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('Graphics timeout')), 2000))
|
|
29
|
+
]);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
logger.debug('Graphics info timed out, using empty graphics data');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const systemInfo = {
|
|
35
|
+
cpu: {
|
|
36
|
+
manufacturer: cpu.manufacturer,
|
|
37
|
+
brand: cpu.brand,
|
|
38
|
+
vendor: cpu.vendor,
|
|
39
|
+
family: cpu.family,
|
|
40
|
+
model: cpu.model,
|
|
41
|
+
stepping: cpu.stepping,
|
|
42
|
+
revision: cpu.revision,
|
|
43
|
+
voltage: cpu.voltage,
|
|
44
|
+
speed: cpu.speed,
|
|
45
|
+
speedMin: cpu.speedMin,
|
|
46
|
+
speedMax: cpu.speedMax,
|
|
47
|
+
cores: cpu.cores,
|
|
48
|
+
physicalCores: cpu.physicalCores,
|
|
49
|
+
processors: cpu.processors,
|
|
50
|
+
socket: cpu.socket,
|
|
51
|
+
cache: cpu.cache
|
|
52
|
+
},
|
|
53
|
+
mem: {
|
|
54
|
+
total: mem.total,
|
|
55
|
+
free: mem.free,
|
|
56
|
+
used: mem.used,
|
|
57
|
+
active: mem.active,
|
|
58
|
+
available: mem.available,
|
|
59
|
+
swaptotal: mem.swaptotal,
|
|
60
|
+
swapused: mem.swapused,
|
|
61
|
+
swapfree: mem.swapfree
|
|
62
|
+
},
|
|
63
|
+
os: {
|
|
64
|
+
platform: osInfo.platform,
|
|
65
|
+
distro: osInfo.distro,
|
|
66
|
+
release: osInfo.release,
|
|
67
|
+
codename: osInfo.codename,
|
|
68
|
+
kernel: osInfo.kernel,
|
|
69
|
+
arch: osInfo.arch,
|
|
70
|
+
hostname: osInfo.hostname,
|
|
71
|
+
fqdn: osInfo.fqdn,
|
|
72
|
+
codepage: osInfo.codepage,
|
|
73
|
+
logofile: osInfo.logofile,
|
|
74
|
+
build: osInfo.build,
|
|
75
|
+
servicepack: osInfo.servicepack,
|
|
76
|
+
uefi: osInfo.uefi
|
|
77
|
+
},
|
|
78
|
+
graphics: {
|
|
79
|
+
controllers: graphics.controllers?.map(controller => ({
|
|
80
|
+
vendor: controller.vendor,
|
|
81
|
+
model: controller.model,
|
|
82
|
+
bus: controller.bus,
|
|
83
|
+
vram: controller.vram,
|
|
84
|
+
vramDynamic: controller.vramDynamic
|
|
85
|
+
})),
|
|
86
|
+
displays: graphics.displays?.map(display => ({
|
|
87
|
+
vendor: display.vendor,
|
|
88
|
+
model: display.model,
|
|
89
|
+
main: display.main,
|
|
90
|
+
builtin: display.builtin,
|
|
91
|
+
connection: display.connection,
|
|
92
|
+
resolutionX: display.resolutionX,
|
|
93
|
+
resolutionY: display.resolutionY,
|
|
94
|
+
sizeX: display.sizeX,
|
|
95
|
+
sizeY: display.sizeY,
|
|
96
|
+
pixelDepth: display.pixelDepth,
|
|
97
|
+
currentResX: display.currentResX,
|
|
98
|
+
currentResY: display.currentResY,
|
|
99
|
+
currentRefreshRate: display.currentRefreshRate
|
|
100
|
+
}))
|
|
101
|
+
},
|
|
102
|
+
system: {
|
|
103
|
+
manufacturer: system.manufacturer,
|
|
104
|
+
model: system.model,
|
|
105
|
+
version: system.version,
|
|
106
|
+
serial: system.serial,
|
|
107
|
+
uuid: system.uuid,
|
|
108
|
+
sku: system.sku,
|
|
109
|
+
virtual: system.virtual
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
logger.verbose('System information collected', {
|
|
114
|
+
cpuBrand: cpu.brand,
|
|
115
|
+
totalMemoryGB: (mem.total / (1024 * 1024 * 1024)).toFixed(2),
|
|
116
|
+
os: `${osInfo.distro} ${osInfo.release}`,
|
|
117
|
+
graphicsControllers: graphics.controllers?.length || 0,
|
|
118
|
+
displays: graphics.displays?.length || 0
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
return systemInfo;
|
|
122
|
+
} catch (error) {
|
|
123
|
+
logger.error('Failed to collect system information:', {
|
|
124
|
+
message: error.message,
|
|
125
|
+
stack: error.stack
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// Return minimal system info as fallback
|
|
129
|
+
return {
|
|
130
|
+
cpu: { brand: 'Unknown', cores: 0 },
|
|
131
|
+
mem: { total: 0 },
|
|
132
|
+
os: {
|
|
133
|
+
platform: process.platform,
|
|
134
|
+
arch: process.arch,
|
|
135
|
+
release: process.version
|
|
136
|
+
},
|
|
137
|
+
graphics: { controllers: [], displays: [] },
|
|
138
|
+
system: { manufacturer: 'Unknown', model: 'Unknown' }
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
}
|
package/lib/uploader.js
CHANGED
|
@@ -5,6 +5,7 @@ import { logger, logFunctionCall } from './logger.js';
|
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import { auth } from './auth.js';
|
|
7
7
|
import got from 'got';
|
|
8
|
+
import { getSystemInfo } from './systemInfo.js';
|
|
8
9
|
|
|
9
10
|
class Uploader {
|
|
10
11
|
constructor() {
|
|
@@ -200,6 +201,15 @@ export async function upload(filePath, metadata = {}) {
|
|
|
200
201
|
hasProject: !!metadata.project
|
|
201
202
|
});
|
|
202
203
|
|
|
204
|
+
// Collect system information
|
|
205
|
+
logger.debug('Collecting system information...');
|
|
206
|
+
const systemInfo = await getSystemInfo();
|
|
207
|
+
logger.verbose('System information collected for upload', {
|
|
208
|
+
cpuBrand: systemInfo.cpu?.brand,
|
|
209
|
+
osDistro: systemInfo.os?.distro,
|
|
210
|
+
totalMemGB: systemInfo.mem?.total ? (systemInfo.mem.total / (1024 * 1024 * 1024)).toFixed(2) : 'unknown'
|
|
211
|
+
});
|
|
212
|
+
|
|
203
213
|
// Handle project ID - use provided project or fetch first available project
|
|
204
214
|
let projectId = metadata.project;
|
|
205
215
|
if (!projectId) {
|
|
@@ -229,11 +239,7 @@ export async function upload(filePath, metadata = {}) {
|
|
|
229
239
|
duration: metadata.duration || 0,
|
|
230
240
|
apps: metadata.apps && metadata.apps.length > 0 ? metadata.apps : ['Screen Recording'], // Use tracked apps or fallback
|
|
231
241
|
title: metadata.title || defaultTitle,
|
|
232
|
-
system:
|
|
233
|
-
platform: process.platform,
|
|
234
|
-
arch: process.arch,
|
|
235
|
-
nodeVersion: process.version
|
|
236
|
-
},
|
|
242
|
+
system: systemInfo, // Include system information
|
|
237
243
|
clientStartDate: metadata.clientStartDate || Date.now() // Use actual recording start time
|
|
238
244
|
};
|
|
239
245
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dashcam",
|
|
3
|
-
"version": "1.0.1-beta.
|
|
3
|
+
"version": "1.0.1-beta.26",
|
|
4
4
|
"description": "Minimal CLI version of Dashcam desktop app",
|
|
5
5
|
"main": "bin/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"mask-sensitive-data": "^0.11.5",
|
|
48
48
|
"node-fetch": "^2.7.0",
|
|
49
49
|
"open": "^9.1.0",
|
|
50
|
+
"systeminformation": "^5.18.15",
|
|
50
51
|
"tail": "^2.2.6",
|
|
51
52
|
"winston": "^3.11.0",
|
|
52
53
|
"ws": "^8.18.3"
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Test script to verify system information collection
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { getSystemInfo } from './lib/systemInfo.js';
|
|
7
|
+
import { logger } from './lib/logger.js';
|
|
8
|
+
|
|
9
|
+
async function testSystemInfo() {
|
|
10
|
+
console.log('Testing system information collection...\n');
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const systemInfo = await getSystemInfo();
|
|
14
|
+
|
|
15
|
+
console.log('✓ System information collected successfully\n');
|
|
16
|
+
console.log('System Information:');
|
|
17
|
+
console.log('==================\n');
|
|
18
|
+
|
|
19
|
+
console.log('CPU:');
|
|
20
|
+
console.log(` Brand: ${systemInfo.cpu.brand}`);
|
|
21
|
+
console.log(` Cores: ${systemInfo.cpu.cores}`);
|
|
22
|
+
console.log(` Speed: ${systemInfo.cpu.speed} GHz`);
|
|
23
|
+
console.log();
|
|
24
|
+
|
|
25
|
+
console.log('Memory:');
|
|
26
|
+
console.log(` Total: ${(systemInfo.mem.total / (1024 ** 3)).toFixed(2)} GB`);
|
|
27
|
+
console.log(` Free: ${(systemInfo.mem.free / (1024 ** 3)).toFixed(2)} GB`);
|
|
28
|
+
console.log(` Used: ${(systemInfo.mem.used / (1024 ** 3)).toFixed(2)} GB`);
|
|
29
|
+
console.log();
|
|
30
|
+
|
|
31
|
+
console.log('Operating System:');
|
|
32
|
+
console.log(` Platform: ${systemInfo.os.platform}`);
|
|
33
|
+
console.log(` Distribution: ${systemInfo.os.distro}`);
|
|
34
|
+
console.log(` Release: ${systemInfo.os.release}`);
|
|
35
|
+
console.log(` Architecture: ${systemInfo.os.arch}`);
|
|
36
|
+
console.log(` Hostname: ${systemInfo.os.hostname}`);
|
|
37
|
+
console.log();
|
|
38
|
+
|
|
39
|
+
console.log('Graphics:');
|
|
40
|
+
console.log(` Controllers: ${systemInfo.graphics.controllers?.length || 0}`);
|
|
41
|
+
if (systemInfo.graphics.controllers?.length > 0) {
|
|
42
|
+
systemInfo.graphics.controllers.forEach((controller, index) => {
|
|
43
|
+
console.log(` ${index + 1}. ${controller.vendor} ${controller.model}`);
|
|
44
|
+
if (controller.vram) {
|
|
45
|
+
console.log(` VRAM: ${controller.vram} MB`);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
console.log(` Displays: ${systemInfo.graphics.displays?.length || 0}`);
|
|
50
|
+
if (systemInfo.graphics.displays?.length > 0) {
|
|
51
|
+
systemInfo.graphics.displays.forEach((display, index) => {
|
|
52
|
+
console.log(` ${index + 1}. ${display.model || 'Unknown'}`);
|
|
53
|
+
console.log(` Resolution: ${display.currentResX}x${display.currentResY}`);
|
|
54
|
+
console.log(` Refresh Rate: ${display.currentRefreshRate} Hz`);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
console.log();
|
|
58
|
+
|
|
59
|
+
console.log('System:');
|
|
60
|
+
console.log(` Manufacturer: ${systemInfo.system.manufacturer}`);
|
|
61
|
+
console.log(` Model: ${systemInfo.system.model}`);
|
|
62
|
+
console.log(` Virtual: ${systemInfo.system.virtual ? 'Yes' : 'No'}`);
|
|
63
|
+
console.log();
|
|
64
|
+
|
|
65
|
+
// Verify all required fields are present
|
|
66
|
+
console.log('Validation:');
|
|
67
|
+
console.log('===========\n');
|
|
68
|
+
|
|
69
|
+
const validations = [
|
|
70
|
+
{ name: 'CPU info', valid: !!systemInfo.cpu && !!systemInfo.cpu.brand },
|
|
71
|
+
{ name: 'Memory info', valid: !!systemInfo.mem && systemInfo.mem.total > 0 },
|
|
72
|
+
{ name: 'OS info', valid: !!systemInfo.os && !!systemInfo.os.platform },
|
|
73
|
+
{ name: 'Graphics info', valid: !!systemInfo.graphics },
|
|
74
|
+
{ name: 'System info', valid: !!systemInfo.system }
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
let allValid = true;
|
|
78
|
+
validations.forEach(v => {
|
|
79
|
+
const status = v.valid ? '✓' : '✗';
|
|
80
|
+
console.log(`${status} ${v.name}: ${v.valid ? 'OK' : 'MISSING'}`);
|
|
81
|
+
if (!v.valid) allValid = false;
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
console.log();
|
|
85
|
+
|
|
86
|
+
if (allValid) {
|
|
87
|
+
console.log('✓ All system information fields are properly populated');
|
|
88
|
+
console.log('✓ System information is ready to be uploaded to the API');
|
|
89
|
+
} else {
|
|
90
|
+
console.log('✗ Some system information is missing');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Show the JSON structure that would be sent to the API
|
|
94
|
+
console.log('\nJSON Structure for API:');
|
|
95
|
+
console.log('======================\n');
|
|
96
|
+
console.log(JSON.stringify(systemInfo, null, 2));
|
|
97
|
+
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error('✗ Failed to collect system information:', error.message);
|
|
100
|
+
console.error(error.stack);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
testSystemInfo();
|