Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 80 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@
"postman-request": "^2.88.1-postman.48",
"replace-in-file": "^6.3.2",
"replace-last": "^1.2.6",
"roku-deploy": "^3.18.2",
"roku-deploy": "^4.0.0-alpha.3",
"semver": "^7.5.4",
"serialize-error": "^8.1.0",
"smart-buffer": "^4.2.0",
Expand Down
4 changes: 4 additions & 0 deletions src/Exceptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,9 @@ export class SocketConnectionInUseError extends Error {
}

public port: number;
/**
* A label identifying the device the connection was made to: the host for a local device, or
* the instanceUrl/id/esn for a Roku Cloud Emulator device.
*/
public host: string;
}
24 changes: 22 additions & 2 deletions src/LaunchConfiguration.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { DeviceInfoRaw, FileEntry } from 'roku-deploy';
import type { DeviceConfig, DeviceInfoRaw, FileEntry } from 'roku-deploy';
import type { DebugProtocol } from '@vscode/debugprotocol';
import type { LogLevel } from './logging';

Expand All @@ -12,8 +12,17 @@ export interface LaunchConfiguration extends DebugProtocol.LaunchRequestArgument
cwd: string;
/**
* The host or ip address for the target Roku
* @deprecated Use `device` instead. When `device` is omitted, a local device config is built from this field.
*/
host: string;
host?: string;

/**
* The roku-deploy device config for the target device. This is the canonical way to address the
* device: a local network device (`{ host }`) or a Roku Cloud Emulator device
* (`{ instanceUrl | id | esn, rceToken }`). When omitted, a local device config is built from
* the deprecated `host` field.
*/
device?: DeviceConfig;

/**
* The raw `device-info` for the target Roku. When supplied, the debug session uses this instead of
Expand Down Expand Up @@ -411,6 +420,17 @@ export interface LaunchConfiguration extends DebugProtocol.LaunchRequestArgument
clientCapabilities?: ClientCapabilities;
}

/**
* A launch configuration after the debug session has normalized it: the deprecated `host` field has
* been consumed (`normalizeLaunchConfig` converts it into `device`, the only time it is ever read,
* and then deletes it from the object) and `device` is a concrete roku-deploy device config.
* Everything inside the debugger works against this type; the raw `LaunchConfiguration` (with
* `host`) exists only at the DAP input boundary.
*/
export type ResolvedLaunchConfiguration = Omit<LaunchConfiguration, 'host'> & {
device: DeviceConfig;
};

/**
* Optional features the client advertises support for via `LaunchConfiguration.clientCapabilities`.
* The debug adapter only enables the matching behavior when the client opts in here.
Expand Down
16 changes: 8 additions & 8 deletions src/PerfettoManager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('PerfettoManager', () => {

beforeEach(() => {
perfettoManager = new PerfettoManager({
host: '192.168.1.100',
device: { host: '192.168.1.100' },
enabled: true,
dir: s`${tempDir}/profiling`,
filename: 'test_${timestamp}.perfetto-trace',
Expand Down Expand Up @@ -68,7 +68,7 @@ describe('PerfettoManager', () => {
describe('constructor', () => {
it('uses default values when not specified', () => {
perfettoManager = new PerfettoManager({
host: '192.168.1.100',
device: { host: '192.168.1.100' },
enabled: true,
rootDir: rootDir
});
Expand All @@ -81,15 +81,15 @@ describe('PerfettoManager', () => {

it('uses provided values over defaults', () => {
perfettoManager = new PerfettoManager({
host: '10.0.0.1',
device: { host: '10.0.0.1' },
enabled: true,
dir: '/custom/dir',
channelId: 'prod',
remotePort: 9090,
rootDir: rootDir
});
expect((perfettoManager as any).config.device).to.eql({ host: '10.0.0.1' });
expect((perfettoManager as any).config).to.include({
host: '10.0.0.1',
dir: '/custom/dir',
channelId: 'prod',
remotePort: 9090
Expand Down Expand Up @@ -128,7 +128,7 @@ describe('PerfettoManager', () => {
describe('startTracing', () => {
it('throws when no host is configured', async () => {
perfettoManager = new PerfettoManager({
host: undefined as any,
device: undefined as any,
enabled: true,
rootDir: rootDir
});
Expand All @@ -140,7 +140,7 @@ describe('PerfettoManager', () => {
await perfettoManager.startTracing();
expect.fail('Should have thrown an error');
} catch (error) {
expect((error as Error).message).to.include('No host configured');
expect((error as Error).message).to.include('Perfetto tracing requires a device with a host');
}

// Should also emit error event
Expand Down Expand Up @@ -345,7 +345,7 @@ describe('PerfettoManager', () => {
sinon.stub(rokuECP, 'enablePerfettoTracing').rejects(new Error('No host configured'));

perfettoManager = new PerfettoManager({
host: undefined as any,
device: undefined as any,
enabled: true,
dir: '/tmp/traces'
});
Expand Down Expand Up @@ -843,7 +843,7 @@ describe('PerfettoManager', () => {
// Restore the stub to test actual createWebSocket
sinon.restore();
perfettoManager = new PerfettoManager({
host: '192.168.1.200',
device: { host: '192.168.1.200' },
remotePort: 8080,
enabled: true,
rootDir: rootDir
Expand Down
25 changes: 18 additions & 7 deletions src/PerfettoManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,19 @@ import { standardizePath as s } from 'brighterscript';
import { createLogger } from './logging';
import { rokuECP } from './RokuECP';
import { util } from './util';
import { isLocalDeviceConfig } from 'roku-deploy';
import type { DeviceConfig, LocalDeviceConfig } from 'roku-deploy';

/**
* Configuration interface for Perfetto tracing
*/
interface PerfettoConfig {
host: string;
/**
* The roku-deploy device config for the target device. The perfetto trace WebSocket connects
* directly to the device's ECP port, so tracing currently requires a local device (one with a
* host); ECP commands route through roku-deploy and work for any device.
*/
device: DeviceConfig;
enabled?: boolean;
dir?: string;
filename?: string;
Expand Down Expand Up @@ -119,7 +126,8 @@ export class PerfettoManager {
}

private createWebSocket() {
const url = `ws://${this.config.host}:${this.config.remotePort}/perfetto-session`;
const device = this.config.device as LocalDeviceConfig;
const url = `ws://${device.host}:${this.config.remotePort}/perfetto-session`;
this.socket = new WebSocket(url);
return this.socket;
}
Expand All @@ -129,8 +137,11 @@ export class PerfettoManager {
* @param includeResultOnStop whether to include the file path when the 'stop' event fires. This should be false if the caller is going to emit their own 'stop' event (like when heapSnapshot is the activator of tracing.
*/
public async startTracing(options?: { excludeResultOnStop: boolean }): Promise<void> {
if (!this.config.host) {
throw this.emitError(new Error('No host configured for Perfetto tracing'));
//the trace websocket connects straight to the device's ECP port, so only host-addressed
//(local) devices are supported for now
const device = this.config.device;
if (!device || !isLocalDeviceConfig(device) || !device.host) {
throw this.emitError(new Error('Perfetto tracing requires a device with a host'));
}

try {
Expand Down Expand Up @@ -293,11 +304,11 @@ export class PerfettoManager {
* Enable tracing on the Roku device. This returns true if we were successful, and throws if we we failed to enable
*/
public async enableTracing(): Promise<boolean> {
this.logger.log(`Enabling Perfetto tracing on channel ${this.config.channelId} at host ${this.config.host}`);
this.logger.log(`Enabling Perfetto tracing on channel ${this.config.channelId} on device ${util.getDeviceLabel(this.config.device)}`);

try {
const result = await rokuECP.enablePerfettoTracing({
host: this.config.host,
device: this.config.device,
remotePort: this.config.remotePort,
channelId: this.config.channelId
});
Expand Down Expand Up @@ -465,7 +476,7 @@ export class PerfettoManager {

await rokuECP.captureHeapSnapshot({
channelId: this.config.channelId,
host: this.config.host,
device: this.config.device,
remotePort: this.config.remotePort
});

Expand Down
Loading
Loading