roku-debug 0.23.16 → 0.24.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/CHANGELOG.md +19 -0
- package/dist/Exceptions.d.ts +4 -0
- package/dist/Exceptions.js.map +1 -1
- package/dist/FileUtils.js +4 -9
- package/dist/FileUtils.js.map +1 -1
- package/dist/LaunchConfiguration.d.ts +20 -2
- package/dist/PerfettoManager.d.ts +7 -1
- package/dist/PerfettoManager.js +11 -6
- package/dist/PerfettoManager.js.map +1 -1
- package/dist/RendezvousTracker.d.ts +2 -2
- package/dist/RendezvousTracker.js +14 -41
- package/dist/RendezvousTracker.js.map +1 -1
- package/dist/RokuECP.d.ts +11 -4
- package/dist/RokuECP.js +48 -62
- package/dist/RokuECP.js.map +1 -1
- package/dist/SceneGraphDebugCommandController.d.ts +28 -2
- package/dist/SceneGraphDebugCommandController.js +100 -4
- package/dist/SceneGraphDebugCommandController.js.map +1 -1
- package/dist/adapters/DebugProtocolAdapter.d.ts +6 -0
- package/dist/adapters/DebugProtocolAdapter.js +30 -11
- package/dist/adapters/DebugProtocolAdapter.js.map +1 -1
- package/dist/adapters/TelnetAdapter.d.ts +6 -0
- package/dist/adapters/TelnetAdapter.js +21 -13
- package/dist/adapters/TelnetAdapter.js.map +1 -1
- package/dist/adapters/TelnetRequestPipeline.d.ts +3 -4
- package/dist/adapters/TelnetRequestPipeline.js.map +1 -1
- package/dist/debugProtocol/DebugProtocolClientReplaySession.js +1 -1
- package/dist/debugProtocol/DebugProtocolClientReplaySession.js.map +1 -1
- package/dist/debugProtocol/client/DebugProtocolClient.d.ts +13 -2
- package/dist/debugProtocol/client/DebugProtocolClient.js +21 -14
- package/dist/debugProtocol/client/DebugProtocolClient.js.map +1 -1
- package/dist/debugProtocol/client/DebugProtocolClientPlugin.d.ts +2 -3
- package/dist/debugSession/BrightScriptDebugSession.d.ts +68 -9
- package/dist/debugSession/BrightScriptDebugSession.js +286 -110
- package/dist/debugSession/BrightScriptDebugSession.js.map +1 -1
- package/dist/debugSession/Events.d.ts +5 -5
- package/dist/debugSession/Events.js +15 -2
- package/dist/debugSession/Events.js.map +1 -1
- package/dist/interfaces.d.ts +8 -1
- package/dist/interfaces.js.map +1 -1
- package/dist/managers/BreakpointManager.d.ts +9 -5
- package/dist/managers/BreakpointManager.js +22 -11
- package/dist/managers/BreakpointManager.js.map +1 -1
- package/dist/managers/LocationManager.js +2 -2
- package/dist/managers/LocationManager.js.map +1 -1
- package/dist/managers/ProjectManager.d.ts +56 -1
- package/dist/managers/ProjectManager.js +146 -23
- package/dist/managers/ProjectManager.js.map +1 -1
- package/dist/util.d.ts +46 -2
- package/dist/util.js +71 -1
- package/dist/util.js.map +1 -1
- package/package.json +5 -5
package/dist/RokuECP.js
CHANGED
|
@@ -2,16 +2,19 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.rokuECP = exports.AppState = exports.EcpStatus = exports.RokuECP = void 0;
|
|
4
4
|
const util_1 = require("./util");
|
|
5
|
+
const roku_deploy_1 = require("roku-deploy");
|
|
5
6
|
class RokuECP {
|
|
7
|
+
/**
|
|
8
|
+
* Send a raw ECP request through roku-deploy's `sendEcpRequest()` transport, which routes a local device
|
|
9
|
+
* over plain HTTP and a Roku Cloud Emulator device through its instance's ECP proxy.
|
|
10
|
+
*/
|
|
6
11
|
async doRequest(route, options, method = 'get') {
|
|
7
12
|
var _a;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return util_1.util.httpGet(url, options.requestOptions);
|
|
14
|
-
}
|
|
13
|
+
return roku_deploy_1.rokuDeploy.sendEcpRequest(options.device, route, {
|
|
14
|
+
method: method === 'post' ? 'POST' : 'GET',
|
|
15
|
+
ecpPort: options.remotePort,
|
|
16
|
+
timeout: (_a = options.requestOptions) === null || _a === void 0 ? void 0 : _a.timeout
|
|
17
|
+
});
|
|
15
18
|
}
|
|
16
19
|
/**
|
|
17
20
|
* Enables perfetto tracing for the specified channel
|
|
@@ -20,7 +23,7 @@ class RokuECP {
|
|
|
20
23
|
*/
|
|
21
24
|
async enablePerfettoTracing(options) {
|
|
22
25
|
const response = await this.doRequest(`/perfetto/enable/${options.channelId}`, options, 'post');
|
|
23
|
-
return this.parseResponse(response, 'perfetto-enable', (parsed, status) => {
|
|
26
|
+
return this.parseResponse(response.body, 'perfetto-enable', (parsed, status) => {
|
|
24
27
|
var _a, _b, _c, _d, _e;
|
|
25
28
|
return {
|
|
26
29
|
enabledChannels: (_c = (_b = (_a = parsed === null || parsed === void 0 ? void 0 : parsed['enabled-channels']) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.channel) !== null && _c !== void 0 ? _c : [],
|
|
@@ -37,7 +40,7 @@ class RokuECP {
|
|
|
37
40
|
*/
|
|
38
41
|
async captureHeapSnapshot(options) {
|
|
39
42
|
const response = await this.doRequest(`/perfetto/heapgraph/trigger/${options.channelId}`, options, 'post');
|
|
40
|
-
return this.parseResponse(response, 'perfetto-heapgraph-trigger', (parsed, status) => {
|
|
43
|
+
return this.parseResponse(response.body, 'perfetto-heapgraph-trigger', (parsed, status) => {
|
|
41
44
|
var _a, _b;
|
|
42
45
|
return {
|
|
43
46
|
timestamp: Number((_a = parsed === null || parsed === void 0 ? void 0 : parsed.timestamp) === null || _a === void 0 ? void 0 : _a[0]),
|
|
@@ -50,80 +53,63 @@ class RokuECP {
|
|
|
50
53
|
var _a, _b, _c, _d;
|
|
51
54
|
return (_d = EcpStatus[(_c = (_b = (_a = response === null || response === void 0 ? void 0 : response[rootKey]) === null || _a === void 0 ? void 0 : _a.status) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.toLowerCase()]) !== null && _d !== void 0 ? _d : EcpStatus.failed;
|
|
52
55
|
}
|
|
53
|
-
async parseResponse(
|
|
54
|
-
var _a, _b, _c
|
|
55
|
-
if (typeof
|
|
56
|
+
async parseResponse(body, rootKey, callback) {
|
|
57
|
+
var _a, _b, _c;
|
|
58
|
+
if (typeof body === 'string') {
|
|
56
59
|
let parsed;
|
|
57
60
|
try {
|
|
58
|
-
parsed = await util_1.util.parseXml(
|
|
61
|
+
parsed = await util_1.util.parseXml(body);
|
|
59
62
|
}
|
|
60
|
-
catch (
|
|
63
|
+
catch (_d) {
|
|
61
64
|
//if the response is not xml, just return the body as-is
|
|
62
|
-
throw new Error(
|
|
65
|
+
throw new Error(body !== null && body !== void 0 ? body : 'Unknown error');
|
|
63
66
|
}
|
|
64
67
|
const status = this.getEcpStatus(parsed, rootKey);
|
|
65
68
|
if (status === EcpStatus.ok) {
|
|
66
69
|
return callback(parsed === null || parsed === void 0 ? void 0 : parsed[rootKey], status);
|
|
67
70
|
}
|
|
68
71
|
else {
|
|
69
|
-
throw new Error((
|
|
72
|
+
throw new Error((_c = (_b = (_a = parsed === null || parsed === void 0 ? void 0 : parsed[rootKey]) === null || _a === void 0 ? void 0 : _a.error) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : 'Unknown error');
|
|
70
73
|
}
|
|
71
74
|
}
|
|
72
75
|
}
|
|
73
76
|
async getRegistry(options) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return this.parseResponse(response, 'plugin-registry', (parsed, status) => {
|
|
79
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
80
|
-
const registry = (_a = parsed === null || parsed === void 0 ? void 0 : parsed.registry) === null || _a === void 0 ? void 0 : _a[0];
|
|
81
|
-
let sections = {};
|
|
82
|
-
for (const section of (_d = (_c = (_b = registry === null || registry === void 0 ? void 0 : registry.sections) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.section) !== null && _d !== void 0 ? _d : []) {
|
|
83
|
-
if (typeof section === 'string') {
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
let sectionName = section.name[0];
|
|
87
|
-
for (const item of section.items[0].item) {
|
|
88
|
-
(_e = sections[sectionName]) !== null && _e !== void 0 ? _e : (sections[sectionName] = {});
|
|
89
|
-
sections[sectionName][item.key[0]] = item.value[0];
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return {
|
|
93
|
-
devId: (_f = registry === null || registry === void 0 ? void 0 : registry['dev-id']) === null || _f === void 0 ? void 0 : _f[0],
|
|
94
|
-
plugins: (_h = (_g = registry === null || registry === void 0 ? void 0 : registry.plugins) === null || _g === void 0 ? void 0 : _g[0]) === null || _h === void 0 ? void 0 : _h.split(','),
|
|
95
|
-
sections: sections,
|
|
96
|
-
spaceAvailable: (_j = registry === null || registry === void 0 ? void 0 : registry['space-available']) === null || _j === void 0 ? void 0 : _j[0],
|
|
97
|
-
status: status
|
|
98
|
-
};
|
|
77
|
+
const registry = await roku_deploy_1.rokuDeploy.queryRegistry({
|
|
78
|
+
device: options.device,
|
|
79
|
+
appId: options.appId,
|
|
80
|
+
ecpPort: options.remotePort
|
|
99
81
|
});
|
|
82
|
+
return {
|
|
83
|
+
devId: registry.devId,
|
|
84
|
+
plugins: registry.plugins,
|
|
85
|
+
sections: registry.sections,
|
|
86
|
+
spaceAvailable: registry.spaceAvailable,
|
|
87
|
+
status: EcpStatus.ok
|
|
88
|
+
};
|
|
100
89
|
}
|
|
101
90
|
async getAppState(options) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
108
|
-
const state = (_c = AppState[(_b = (_a = parsed.state) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.toLowerCase()]) !== null && _c !== void 0 ? _c : AppState.unknown;
|
|
109
|
-
return {
|
|
110
|
-
appId: (_d = parsed['app-id']) === null || _d === void 0 ? void 0 : _d[0],
|
|
111
|
-
appDevId: (_e = parsed['app-dev-id']) === null || _e === void 0 ? void 0 : _e[0],
|
|
112
|
-
appTitle: (_f = parsed['app-title']) === null || _f === void 0 ? void 0 : _f[0],
|
|
113
|
-
appVersion: (_g = parsed['app-version']) === null || _g === void 0 ? void 0 : _g[0],
|
|
114
|
-
state: state,
|
|
115
|
-
status: status
|
|
116
|
-
};
|
|
91
|
+
var _a;
|
|
92
|
+
const appState = await roku_deploy_1.rokuDeploy.queryAppState({
|
|
93
|
+
device: options.device,
|
|
94
|
+
appId: options.appId,
|
|
95
|
+
ecpPort: options.remotePort
|
|
117
96
|
});
|
|
97
|
+
return {
|
|
98
|
+
appId: appState.appId,
|
|
99
|
+
appDevId: appState.appDevId,
|
|
100
|
+
appTitle: appState.appTitle,
|
|
101
|
+
appVersion: appState.appVersion,
|
|
102
|
+
state: (_a = AppState[appState.state]) !== null && _a !== void 0 ? _a : AppState.unknown,
|
|
103
|
+
status: EcpStatus.ok
|
|
104
|
+
};
|
|
118
105
|
}
|
|
119
106
|
async exitApp(options) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
return this.parseResponse(response, 'exit-app', (parsed, status) => {
|
|
125
|
-
return { status: status };
|
|
107
|
+
await roku_deploy_1.rokuDeploy.exitApp({
|
|
108
|
+
device: options.device,
|
|
109
|
+
appId: options.appId,
|
|
110
|
+
ecpPort: options.remotePort
|
|
126
111
|
});
|
|
112
|
+
return { status: EcpStatus.ok };
|
|
127
113
|
}
|
|
128
114
|
}
|
|
129
115
|
exports.RokuECP = RokuECP;
|
package/dist/RokuECP.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RokuECP.js","sourceRoot":"","sources":["../src/RokuECP.ts"],"names":[],"mappings":";;;AAAA,iCAA8B;
|
|
1
|
+
{"version":3,"file":"RokuECP.js","sourceRoot":"","sources":["../src/RokuECP.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import type { DeviceConfig, RokuDeploySocket, SocketOptions } from 'roku-deploy';
|
|
1
2
|
export declare class SceneGraphDebugCommandController {
|
|
2
|
-
|
|
3
|
-
|
|
3
|
+
constructor(device: DeviceConfig, port?: number);
|
|
4
|
+
/**
|
|
5
|
+
* The roku-deploy device config for the target device
|
|
6
|
+
*/
|
|
7
|
+
private device;
|
|
4
8
|
private connection;
|
|
5
9
|
private shellPrompt;
|
|
6
10
|
private echoLines;
|
|
@@ -9,10 +13,32 @@ export declare class SceneGraphDebugCommandController {
|
|
|
9
13
|
private port;
|
|
10
14
|
private maxBufferLength;
|
|
11
15
|
private logger;
|
|
16
|
+
/**
|
|
17
|
+
* Create the transport used to reach the SceneGraph debug server. Extracted to a protected
|
|
18
|
+
* method so tests can substitute a fake socket.
|
|
19
|
+
*/
|
|
20
|
+
protected createRokuDeploySocket(options: SocketOptions): RokuDeploySocket;
|
|
12
21
|
connect(options?: {
|
|
13
22
|
execTimeout?: number;
|
|
14
23
|
timeout?: number;
|
|
15
24
|
}): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Waits for the transport-level connection to establish (the tcp handshake for a local device,
|
|
27
|
+
* or the websocket handshake for an RCE device), racing its 'connect' event against 'error' and
|
|
28
|
+
* a manual timeout. An injected sock bypasses telnet-client's own connect timeout entirely
|
|
29
|
+
* (telnet-client resolves immediately for an injected sock, before its timeout is even armed),
|
|
30
|
+
* so this is the only thing enforcing one here.
|
|
31
|
+
*/
|
|
32
|
+
private waitForSocketConnect;
|
|
33
|
+
/**
|
|
34
|
+
* Waits for the connection greeting (a bare `>` shell prompt) to arrive and consumes it before
|
|
35
|
+
* the socket is handed to telnet-client. This mirrors the prompt wait telnet-client performs
|
|
36
|
+
* when it owns the socket, which it skips entirely for an injected sock (it treats one as
|
|
37
|
+
* already `'ready'`); without it the greeting would instead arrive mid-exec, where its prompt
|
|
38
|
+
* would prematurely terminate the first command's response. Rejects if the prompt does not
|
|
39
|
+
* arrive within `timeoutMs`.
|
|
40
|
+
*/
|
|
41
|
+
private waitForConnectPrompt;
|
|
16
42
|
private removeConnection;
|
|
17
43
|
/**
|
|
18
44
|
* executes the different bsprof commands used for brightscript profiling.
|
|
@@ -1,46 +1,142 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SceneGraphDebugCommandController = void 0;
|
|
4
|
+
const roku_deploy_1 = require("roku-deploy");
|
|
4
5
|
const logging_1 = require("./logging");
|
|
5
6
|
// eslint-disable-next-line
|
|
6
7
|
const Telnet = require('telnet-client');
|
|
7
8
|
class SceneGraphDebugCommandController {
|
|
8
|
-
constructor(
|
|
9
|
-
this.host = host;
|
|
9
|
+
constructor(device, port) {
|
|
10
10
|
this.shellPrompt = /^>$/img;
|
|
11
11
|
this.echoLines = 0;
|
|
12
12
|
this.timeout = 5000;
|
|
13
13
|
this.execTimeout = 2000;
|
|
14
14
|
this.maxBufferLength = 5242880;
|
|
15
15
|
this.logger = logging_1.logger.createLogger(`[${SceneGraphDebugCommandController.name}]`);
|
|
16
|
+
this.device = device;
|
|
16
17
|
this.port = port !== null && port !== void 0 ? port : 8080;
|
|
17
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Create the transport used to reach the SceneGraph debug server. Extracted to a protected
|
|
21
|
+
* method so tests can substitute a fake socket.
|
|
22
|
+
*/
|
|
23
|
+
createRokuDeploySocket(options) {
|
|
24
|
+
return (0, roku_deploy_1.createRokuDeploySocket)(options);
|
|
25
|
+
}
|
|
18
26
|
async connect(options = {}) {
|
|
27
|
+
var _a;
|
|
19
28
|
this.removeConnection();
|
|
29
|
+
const timeoutMs = (_a = options.timeout) !== null && _a !== void 0 ? _a : this.timeout;
|
|
30
|
+
let socket;
|
|
20
31
|
try {
|
|
32
|
+
socket = this.createRokuDeploySocket({
|
|
33
|
+
device: this.device,
|
|
34
|
+
port: this.port
|
|
35
|
+
});
|
|
36
|
+
//keep an error listener attached for the socket's whole life: waitForConnectPrompt and
|
|
37
|
+
//telnet-client each remove or narrow theirs at various points, and a socket 'error'
|
|
38
|
+
//emitted while no listener is attached would crash the whole process
|
|
39
|
+
socket.on('error', (error) => {
|
|
40
|
+
this.logger.debug('SceneGraph debug server socket error', error);
|
|
41
|
+
});
|
|
42
|
+
await this.waitForSocketConnect(socket, timeoutMs);
|
|
43
|
+
//an injected sock skips telnet-client's own prompt wait entirely (see the comment on
|
|
44
|
+
//waitForConnectPrompt below), so the greeting has to be consumed here first or it would
|
|
45
|
+
//otherwise arrive mid-exec and prematurely terminate the first command's response
|
|
46
|
+
await this.waitForConnectPrompt(socket, timeoutMs);
|
|
21
47
|
// Make a new telnet connections object
|
|
22
48
|
let connection = new Telnet();
|
|
23
49
|
connection.on('close', () => {
|
|
24
50
|
this.removeConnection();
|
|
25
51
|
});
|
|
26
52
|
const config = {
|
|
27
|
-
host: this.host,
|
|
28
53
|
port: this.port,
|
|
29
54
|
shellPrompt: this.shellPrompt,
|
|
30
55
|
echoLines: this.echoLines,
|
|
31
56
|
timeout: this.timeout,
|
|
32
57
|
execTimeout: this.execTimeout,
|
|
33
58
|
maxBufferLength: this.maxBufferLength,
|
|
34
|
-
...options
|
|
59
|
+
...options,
|
|
60
|
+
sock: socket
|
|
35
61
|
};
|
|
36
62
|
this.logger.debug('Establishing telnet connection', config);
|
|
37
63
|
await connection.connect(config);
|
|
38
64
|
this.connection = connection;
|
|
39
65
|
}
|
|
40
66
|
catch (e) {
|
|
67
|
+
//the socket was created but never became the live connection, so nothing else will ever
|
|
68
|
+
//destroy it. Leaving it dangling would leak an open socket or websocket.
|
|
69
|
+
socket === null || socket === void 0 ? void 0 : socket.destroy();
|
|
41
70
|
throw new Error(e.message);
|
|
42
71
|
}
|
|
43
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Waits for the transport-level connection to establish (the tcp handshake for a local device,
|
|
75
|
+
* or the websocket handshake for an RCE device), racing its 'connect' event against 'error' and
|
|
76
|
+
* a manual timeout. An injected sock bypasses telnet-client's own connect timeout entirely
|
|
77
|
+
* (telnet-client resolves immediately for an injected sock, before its timeout is even armed),
|
|
78
|
+
* so this is the only thing enforcing one here.
|
|
79
|
+
*/
|
|
80
|
+
waitForSocketConnect(socket, timeoutMs) {
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
const cleanup = () => {
|
|
83
|
+
clearTimeout(timeoutHandle);
|
|
84
|
+
socket.removeListener('connect', onConnect);
|
|
85
|
+
socket.removeListener('error', onError);
|
|
86
|
+
};
|
|
87
|
+
const onConnect = () => {
|
|
88
|
+
cleanup();
|
|
89
|
+
resolve();
|
|
90
|
+
};
|
|
91
|
+
const onError = (error) => {
|
|
92
|
+
cleanup();
|
|
93
|
+
reject(error);
|
|
94
|
+
};
|
|
95
|
+
const timeoutHandle = setTimeout(() => {
|
|
96
|
+
cleanup();
|
|
97
|
+
reject(new Error(`Timed out connecting to the SceneGraph debug server after ${timeoutMs}ms`));
|
|
98
|
+
}, timeoutMs);
|
|
99
|
+
socket.once('connect', onConnect);
|
|
100
|
+
socket.once('error', onError);
|
|
101
|
+
socket.connect();
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Waits for the connection greeting (a bare `>` shell prompt) to arrive and consumes it before
|
|
106
|
+
* the socket is handed to telnet-client. This mirrors the prompt wait telnet-client performs
|
|
107
|
+
* when it owns the socket, which it skips entirely for an injected sock (it treats one as
|
|
108
|
+
* already `'ready'`); without it the greeting would instead arrive mid-exec, where its prompt
|
|
109
|
+
* would prematurely terminate the first command's response. Rejects if the prompt does not
|
|
110
|
+
* arrive within `timeoutMs`.
|
|
111
|
+
*/
|
|
112
|
+
waitForConnectPrompt(socket, timeoutMs) {
|
|
113
|
+
return new Promise((resolve, reject) => {
|
|
114
|
+
let accumulatedText = '';
|
|
115
|
+
//a fresh non-global copy avoids a stateful lastIndex across calls, since
|
|
116
|
+
//this.shellPrompt carries the 'g' flag
|
|
117
|
+
const nonGlobalShellPrompt = new RegExp(this.shellPrompt.source, this.shellPrompt.flags.replace('g', ''));
|
|
118
|
+
const finish = (error) => {
|
|
119
|
+
socket.removeListener('data', onData);
|
|
120
|
+
clearTimeout(timeoutHandle);
|
|
121
|
+
if (error) {
|
|
122
|
+
reject(error);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
resolve();
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
const onData = (chunk) => {
|
|
129
|
+
accumulatedText += chunk.toString('utf8');
|
|
130
|
+
if (nonGlobalShellPrompt.test(accumulatedText)) {
|
|
131
|
+
finish();
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
const timeoutHandle = setTimeout(() => {
|
|
135
|
+
finish(new Error(`Timed out after ${timeoutMs}ms waiting for the SceneGraph debug server's shell prompt`));
|
|
136
|
+
}, timeoutMs);
|
|
137
|
+
socket.on('data', onData);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
44
140
|
removeConnection() {
|
|
45
141
|
this.connection = null;
|
|
46
142
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SceneGraphDebugCommandController.js","sourceRoot":"","sources":["../src/SceneGraphDebugCommandController.ts"],"names":[],"mappings":";;;AAAA,uCAAmC;AACnC,2BAA2B;AAC3B,MAAM,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;AAExC,MAAa,gCAAgC;IACzC,
|
|
1
|
+
{"version":3,"file":"SceneGraphDebugCommandController.js","sourceRoot":"","sources":["../src/SceneGraphDebugCommandController.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RokuDeploySocket, SocketOptions } from 'roku-deploy';
|
|
1
2
|
import type { BSDebugDiagnostic } from '../CompileErrorProcessor';
|
|
2
3
|
import type { RendezvousHistory, RendezvousTracker } from '../RendezvousTracker';
|
|
3
4
|
import type { ChanperfData } from '../ChanperfTracker';
|
|
@@ -128,6 +129,11 @@ export declare class DebugProtocolAdapter {
|
|
|
128
129
|
* Resolves when the first connection to the client is established
|
|
129
130
|
*/
|
|
130
131
|
onReady(): Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Create the transport used to reach the device's BrightScript console. Extracted to a
|
|
134
|
+
* protected method so tests can substitute a fake socket.
|
|
135
|
+
*/
|
|
136
|
+
protected createRokuDeploySocket(options: SocketOptions): RokuDeploySocket;
|
|
131
137
|
/**
|
|
132
138
|
* Connect to the telnet session. This should be called before the channel is launched.
|
|
133
139
|
*/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.KeyType = exports.EventName = exports.DebugProtocolAdapter = void 0;
|
|
4
4
|
const EventEmitter = require("events");
|
|
5
|
-
const
|
|
5
|
+
const roku_deploy_1 = require("roku-deploy");
|
|
6
6
|
const brighterscript_1 = require("brighterscript");
|
|
7
7
|
const CompileErrorProcessor_1 = require("../CompileErrorProcessor");
|
|
8
8
|
const ChanperfTracker_1 = require("../ChanperfTracker");
|
|
@@ -197,6 +197,13 @@ class DebugProtocolAdapter {
|
|
|
197
197
|
onReady() {
|
|
198
198
|
return this.firstConnectDeferred.promise;
|
|
199
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* Create the transport used to reach the device's BrightScript console. Extracted to a
|
|
202
|
+
* protected method so tests can substitute a fake socket.
|
|
203
|
+
*/
|
|
204
|
+
createRokuDeploySocket(options) {
|
|
205
|
+
return (0, roku_deploy_1.createRokuDeploySocket)(options);
|
|
206
|
+
}
|
|
200
207
|
/**
|
|
201
208
|
* Connect to the telnet session. This should be called before the channel is launched.
|
|
202
209
|
*/
|
|
@@ -287,7 +294,7 @@ class DebugProtocolAdapter {
|
|
|
287
294
|
});
|
|
288
295
|
//handle when the device verifies breakpoints
|
|
289
296
|
this.client.on('breakpoints-verified', (event) => {
|
|
290
|
-
var _a;
|
|
297
|
+
var _a, _b;
|
|
291
298
|
let unverifiableDeviceIds = [];
|
|
292
299
|
//mark the breakpoints as verified
|
|
293
300
|
for (let breakpoint of (_a = event === null || event === void 0 ? void 0 : event.breakpoints) !== null && _a !== void 0 ? _a : []) {
|
|
@@ -299,7 +306,7 @@ class DebugProtocolAdapter {
|
|
|
299
306
|
//if there were any unsuccessful breakpoint verifications, we need to ask the device to delete those breakpoints as they've gone missing on our side
|
|
300
307
|
if (unverifiableDeviceIds.length > 0) {
|
|
301
308
|
this.logger.warn('Could not find breakpoints to verify. Removing from device:', { deviceBreakpointIds: unverifiableDeviceIds });
|
|
302
|
-
void this.client.removeBreakpoints(unverifiableDeviceIds);
|
|
309
|
+
void ((_b = this.client) === null || _b === void 0 ? void 0 : _b.removeBreakpoints(unverifiableDeviceIds));
|
|
303
310
|
}
|
|
304
311
|
this.emit('breakpoints-verified', event);
|
|
305
312
|
});
|
|
@@ -315,7 +322,16 @@ class DebugProtocolAdapter {
|
|
|
315
322
|
this.emit('diagnostics', diagnostics);
|
|
316
323
|
});
|
|
317
324
|
await this.client.connect();
|
|
318
|
-
|
|
325
|
+
//the client can be torn down while the connect above is still settling (its 'close'
|
|
326
|
+
//handler clears `this.client` - for example the device immediately killing the session
|
|
327
|
+
//it accepted). Everything below configures a client that no longer exists, so bail and
|
|
328
|
+
//leave the queued breakpoint state for the next connection instead of crashing.
|
|
329
|
+
if (!this.client) {
|
|
330
|
+
this.logger.warn('Debug protocol client closed before setup completed; waiting for a new connection');
|
|
331
|
+
deferred.resolve();
|
|
332
|
+
return await deferred.promise;
|
|
333
|
+
}
|
|
334
|
+
this.logger.log(`Connected to device`, { device: util_1.util.getDeviceLabel(this.options.device), connected: this.connected });
|
|
319
335
|
this.connected = true;
|
|
320
336
|
this.isAppRunning = true;
|
|
321
337
|
this.handleStartupIfReady();
|
|
@@ -364,7 +380,10 @@ class DebugProtocolAdapter {
|
|
|
364
380
|
this.processingTelnetOutput = true;
|
|
365
381
|
let deferred = (0, util_1.defer)();
|
|
366
382
|
try {
|
|
367
|
-
|
|
383
|
+
//normalizeAdapterOptions guarantees `device` is a concrete device config
|
|
384
|
+
const device = this.options.device;
|
|
385
|
+
const deviceLabel = util_1.util.getDeviceLabel(device);
|
|
386
|
+
this.compileClient = this.createRokuDeploySocket({ device: device, port: this.options.brightScriptConsolePort });
|
|
368
387
|
util_1.util.registerSocketLogging(this.compileClient, this.logger, 'CompileClient');
|
|
369
388
|
this.compileErrorProcessor.on('diagnostics', (errors) => {
|
|
370
389
|
this.compileClient.end();
|
|
@@ -378,20 +397,20 @@ class DebugProtocolAdapter {
|
|
|
378
397
|
//After a successful connection the deferred is already resolved, so a post-connection
|
|
379
398
|
//socket error (e.g. ECONNRESET on device disconnect) must not crash the process.
|
|
380
399
|
this.compileClient.on('error', (err) => {
|
|
381
|
-
deferred.tryReject(new Error(`Error with connection to: ${
|
|
400
|
+
deferred.tryReject(new Error(`Error with connection to: ${deviceLabel}:${this.options.brightScriptConsolePort} \n\n ${err.message} `));
|
|
382
401
|
});
|
|
383
|
-
this.logger.info('Connecting via telnet to gather compile info', {
|
|
384
|
-
this.compileClient.connect(
|
|
385
|
-
this.logger.log(`CONNECTED via telnet to gather compile info`, {
|
|
402
|
+
this.logger.info('Connecting via telnet to gather compile info', { device: deviceLabel, port: this.options.brightScriptConsolePort });
|
|
403
|
+
this.compileClient.connect(() => {
|
|
404
|
+
this.logger.log(`CONNECTED via telnet to gather compile info`, { device: deviceLabel, port: this.options.brightScriptConsolePort });
|
|
386
405
|
});
|
|
387
406
|
this.logger.debug('Waiting for the compile client to settle');
|
|
388
407
|
const settledLogs = await this.settleCompileClient(this.compileClient);
|
|
389
408
|
this.logger.debug('Compile client has settled');
|
|
390
409
|
this.logger.trace('Settled logs:', settledLogs);
|
|
391
410
|
if (settledLogs.trim().startsWith('Console connection is already in use.')) {
|
|
392
|
-
throw new Exceptions_1.SocketConnectionInUseError(`Telnet connection ${
|
|
411
|
+
throw new Exceptions_1.SocketConnectionInUseError(`Telnet connection ${deviceLabel}:${this.options.brightScriptConsolePort} already is use`, {
|
|
393
412
|
port: this.options.brightScriptConsolePort,
|
|
394
|
-
host:
|
|
413
|
+
host: deviceLabel
|
|
395
414
|
});
|
|
396
415
|
}
|
|
397
416
|
let lastPartialLine = '';
|