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 CHANGED
@@ -417,12 +417,22 @@ program
417
417
 
418
418
  console.log('Recording stopped successfully');
419
419
 
420
- // Wait a moment for upload to complete (background process handles this)
420
+ // Wait for upload to complete (background process handles this)
421
421
  logger.debug('Waiting for background upload to complete...');
422
- await new Promise(resolve => setTimeout(resolve, 5000));
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(process.cwd(), '.dashcam', 'temp-file.json');
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...');
@@ -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
- const maxWaitTime = 30000; // 30 seconds max
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 system temp for runtime data
149
- const DASHCAM_TEMP_DIR = path.join(os.tmpdir(), 'dashcam');
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 tmp/recordings directory
242
+ * Clear the recordings directory
242
243
  */
243
244
  function clearRecordingsDirectory() {
244
245
  const logExit = logFunctionCall('clearRecordingsDirectory');
245
246
 
246
- const directory = path.join(process.cwd(), 'tmp', 'recordings');
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 system temp directory with dashcam subdirectory
285
- const directory = path.join(os.tmpdir(), 'dashcam', 'recordings');
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.24",
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();