Skip to content

Commit

Permalink
Fix rendezvous crash (#156)
Browse files Browse the repository at this point in the history
* Fix timing bugs during rendezvous tracking startup

* Only emit rendezvous data if new data was received
  • Loading branch information
TwitchBronBron authored Jul 7, 2023
1 parent d116921 commit 02df15f
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 34 deletions.
44 changes: 33 additions & 11 deletions src/RendezvousTracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,15 @@ export class RendezvousTracker {
* Clears the current rendezvous history
*/
public clearHistory() {
this.logger.log('Clear rendezvous history');
this.rendezvousHistory = this.createNewRendezvousHistory();
this.emit('rendezvous', this.rendezvousHistory);
}

private ecpPingTimer: NodeJS.Timer;

public startEcpPingTimer(): void {
this.logger.log('Start ecp ping timer');
if (!this.ecpPingTimer) {
this.ecpPingTimer = setInterval(() => {
void this.pingEcpRendezvous();
Expand All @@ -106,17 +108,25 @@ export class RendezvousTracker {
}

public async pingEcpRendezvous(): Promise<void> {
// Get ECP rendezvous data, parse it, and send it to event emitter
let ecpData = await this.getEcpRendezvous();
for (let blockInfo of ecpData.items) {
let duration = ((parseInt(blockInfo.endTime) - parseInt(blockInfo.startTime)) / 1000).toString();
this.rendezvousBlocks[blockInfo.id] = {
fileName: await this.updateClientPathMap(blockInfo.file, parseInt(blockInfo.lineNumber)),
lineNumber: blockInfo.lineNumber
};
this.parseRendezvousLog(this.rendezvousBlocks[blockInfo.id], duration);
try {
// Get ECP rendezvous data, parse it, and send it to event emitter
let ecpData = await this.getEcpRendezvous();
const items = ecpData?.items ?? [];
if (items.length > 0) {
for (let blockInfo of items) {
let duration = ((parseInt(blockInfo.endTime) - parseInt(blockInfo.startTime)) / 1000).toString();
this.rendezvousBlocks[blockInfo.id] = {
fileName: await this.updateClientPathMap(blockInfo.file, parseInt(blockInfo.lineNumber)),
lineNumber: blockInfo.lineNumber
};
this.parseRendezvousLog(this.rendezvousBlocks[blockInfo.id], duration);
}
this.emit('rendezvous', this.rendezvousHistory);
}
} catch (e) {
//if there was an error pinging rendezvous, log the error but don't bring down the app
console.error('There was an error fetching rendezvous data', e?.stack);
}
this.emit('rendezvous', this.rendezvousHistory);
}

/**
Expand All @@ -132,6 +142,7 @@ export class RendezvousTracker {
private async runSGLogrendezvousCommand(command: 'status' | 'on' | 'off'): Promise<string> {
let sgDebugCommandController = new SceneGraphDebugCommandController(this.deviceInfo.host as string);
try {
this.logger.info(`port 8080 command: logrendezvous ${command}`);
return (await sgDebugCommandController.logrendezvous(command)).result.rawResponse;
} catch (error) {
this.logger.warn(`An error occurred running SG command "${command}"`, error);
Expand All @@ -151,11 +162,13 @@ export class RendezvousTracker {
public async activate(): Promise<boolean> {
//if ECP tracking is supported, turn that on
if (this.doesHostSupportEcpRendezvousTracking) {
this.logger.log('Activating rendezvous tracking');
// Toggle ECP tracking off and on to clear the log and then continue tracking
let untrack = await this.toggleEcpRendezvousTracking('untrack');
let track = await this.toggleEcpRendezvousTracking('track');
const isEcpTrackingEnabled = untrack && track && await this.getIsEcpRendezvousTrackingEnabled();
if (isEcpTrackingEnabled) {
this.logger.info('ECP tracking is enabled');
this.trackingSource = 'ecp';
this.startEcpPingTimer();

Expand All @@ -167,11 +180,15 @@ export class RendezvousTracker {
}
}

this.logger.log('ECP tracking is not supported or had an issue. Trying to use telnet rendezvous tracking');
//ECP tracking is not supported (or had an issue). Try enabling telnet rendezvous tracking (that only works with run_as_process=0, but worth a try...)
await this.runSGLogrendezvousCommand('on');
if (await this.getIsTelnetRendezvousTrackingEnabled()) {
this.logger.log('telnet rendezvous tracking is enabled');
this.trackingSource = 'telnet';
return true;
} else {
this.logger.log('telnet rendezvous tracking is disabled or encountered an issue. rendezvous tracking is now disabled');
}
return false;
}
Expand All @@ -180,14 +197,17 @@ export class RendezvousTracker {
* Get the response from an ECP sgrendezvous request from the Roku
*/
public async getEcpRendezvous(): Promise<EcpRendezvousData> {
const url = `http://${this.deviceInfo.host}:${this.deviceInfo.remotePort}/query/sgrendezvous`;
this.logger.info(`Sending ECP rendezvous request:`, url);
// Send rendezvous query to ECP
const rendezvousQuery = await util.httpGet(`http://${this.deviceInfo.host}:${this.deviceInfo.remotePort}/query/sgrendezvous`);
const rendezvousQuery = await util.httpGet(url);
let rendezvousQueryData = rendezvousQuery.body;
let ecpData: EcpRendezvousData = {
trackingEnabled: false,
items: []
};

this.logger.debug('Parsing rendezvous response', rendezvousQuery);
// Parse rendezvous query data
await new Promise<EcpRendezvousData>((resolve, reject) => {
xml2js.parseString(rendezvousQueryData, (err, result) => {
Expand All @@ -209,6 +229,7 @@ export class RendezvousTracker {
}
});
});
this.logger.debug('Parsed ECP rendezvous data:', ecpData);
return ecpData;
}

Expand All @@ -218,6 +239,7 @@ export class RendezvousTracker {
*/
public async toggleEcpRendezvousTracking(toggle: 'track' | 'untrack'): Promise<boolean> {
try {
this.logger.log(`Sending ecp sgrendezvous request: ${toggle}`);
const response = await util.httpPost(
`http://${this.deviceInfo.host}:${this.deviceInfo.remotePort}/sgrendezvous/${toggle}`,
//not sure if we need this, but it works...so probably better to just leave it here
Expand Down
9 changes: 0 additions & 9 deletions src/adapters/DebugProtocolAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -637,14 +637,6 @@ export class DebugProtocolAdapter {
this.emitter = undefined;
}

// #region Rendezvous Tracker pass though functions
/**
* Passes the debug functions used to locate the client files and lines to the RendezvousTracker
*/
public registerSourceLocator(sourceLocator: (debuggerPath: string, lineNumber: number) => Promise<SourceLocation>) {
this.rendezvousTracker.registerSourceLocator(sourceLocator);
}

/**
* Passes the log level down to the RendezvousTracker and ChanperfTracker
* @param outputLevel the consoleOutput from the launch config
Expand All @@ -667,7 +659,6 @@ export class DebugProtocolAdapter {
public clearChanperfHistory() {
this.chanperfTracker.clearHistory();
}
// #endregion

public async syncBreakpoints() {
//we can't send breakpoints unless we're stopped (or in a protocol version that supports sending them while running).
Expand Down
9 changes: 0 additions & 9 deletions src/adapters/TelnetAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1026,14 +1026,6 @@ export class TelnetAdapter {
return Promise.resolve();
}

// #region Rendezvous Tracker pass though functions
/**
* Passes the debug functions used to locate the client files and lines to the RendezvousTracker
*/
public registerSourceLocator(sourceLocator: (debuggerPath: string, lineNumber: number) => Promise<SourceLocation>) {
this.rendezvousTracker.registerSourceLocator(sourceLocator);
}

/**
* Passes the log level down to the RendezvousTracker and ChanperfTracker
* @param outputLevel the consoleOutput from the launch config
Expand All @@ -1056,7 +1048,6 @@ export class TelnetAdapter {
public clearChanperfHistory() {
this.chanperfTracker.clearHistory();
}
// #endregion

public async syncBreakpoints() {
//we can't send dynamic breakpoints to the server...so just do nothing
Expand Down
10 changes: 5 additions & 5 deletions src/debugSession/BrightScriptDebugSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,11 +306,6 @@ export class BrightScriptDebugSession extends BaseDebugSession {
//press the home button to ensure we're at the home screen
await this.rokuDeploy.pressHomeButton(this.launchConfiguration.host, this.launchConfiguration.remotePort);

//pass the debug functions used to locate the client files and lines thought the adapter to the RendezvousTracker
this.rokuAdapter.registerSourceLocator(async (debuggerPath: string, lineNumber: number) => {
return this.projectManager.getSourceLocation(debuggerPath, lineNumber);
});

//pass the log level down thought the adapter to the RendezvousTracker and ChanperfTracker
this.rokuAdapter.setConsoleOutput(this.launchConfiguration.consoleOutput);

Expand Down Expand Up @@ -442,6 +437,11 @@ export class BrightScriptDebugSession extends BaseDebugSession {
private async _initRendezvousTracking() {
this.rendezvousTracker = new RendezvousTracker(this.deviceInfo);

//pass the debug functions used to locate the client files and lines thought the adapter to the RendezvousTracker
this.rendezvousTracker.registerSourceLocator(async (debuggerPath: string, lineNumber: number) => {
return this.projectManager.getSourceLocation(debuggerPath, lineNumber);
});

// Send rendezvous events to the debug protocol client
this.rendezvousTracker.on('rendezvous', (output) => {
this.sendEvent(new RendezvousEvent(output));
Expand Down

0 comments on commit 02df15f

Please sign in to comment.