///
///
import { PROTOCOL_ERROR_CODES, Command } from '../Constants';
import { ExecuteV3Response } from '../events/responses/ExecuteV3Response';
import { ListBreakpointsResponse } from '../events/responses/ListBreakpointsResponse';
import { AddBreakpointsResponse } from '../events/responses/AddBreakpointsResponse';
import { ProtocolCapabilities } from './ProtocolCapabilities';
import { ThreadsRequest } from '../events/requests/ThreadsRequest';
import type { ExceptionBreakpoint } from '../events/requests/SetExceptionBreakpointsRequest';
import type { ProtocolRequest, ProtocolResponse, ProtocolUpdate } from '../events/ProtocolEvent';
import { HandshakeResponse } from '../events/responses/HandshakeResponse';
import { HandshakeV3Response } from '../events/responses/HandshakeV3Response';
import { GenericV3Response } from '../events/responses/GenericV3Response';
import { AllThreadsStoppedUpdate } from '../events/updates/AllThreadsStoppedUpdate';
import { CompileErrorUpdate } from '../events/updates/CompileErrorUpdate';
import { GenericResponse } from '../events/responses/GenericResponse';
import type { StackTraceResponse } from '../events/responses/StackTraceResponse';
import { ThreadsResponse } from '../events/responses/ThreadsResponse';
import { SetExceptionBreakpointsResponse } from '../events/responses/SetExceptionBreakpointsResponse';
import { VariablesResponse } from '../events/responses/VariablesResponse';
import { ThreadAttachedUpdate } from '../events/updates/ThreadAttachedUpdate';
import { StackTraceV3Response } from '../events/responses/StackTraceV3Response';
import type { DebugProtocolClientPlugin } from './DebugProtocolClientPlugin';
import PluginInterface from '../PluginInterface';
import type { VerifiedBreakpoint } from '../events/updates/BreakpointVerifiedUpdate';
export declare class DebugProtocolClient {
logger: import("@rokucommunity/logger").Logger;
supportedVersionRange: string;
constructor(options?: ConstructorOptions);
private addCorePlugin;
static DEBUGGER_MAGIC: string;
scriptTitle: string;
isHandshakeComplete: boolean;
connectedToIoPort: boolean;
/**
* Debug protocol version 3.0.0 introduced a packet_length to all responses. Prior to that, most responses had no packet length at all.
* This field indicates whether we should be looking for packet_length or not in the responses we get from the device
*/
watchPacketLength: boolean;
/**
* Capability flags derived from the negotiated protocol version. Undefined until the
* handshake completes, then assigned a fresh `ProtocolCapabilities` keyed off the version
* the device reported.
*/
capabilities: ProtocolCapabilities | undefined;
/**
* The protocol version negotiated with the device during the handshake. Undefined until
* the handshake has completed.
*/
get protocolVersion(): string | undefined;
primaryThread: number;
stackFrameIndex: number;
/**
* A collection of plugins that can interact with the client at lifecycle points
*/
plugins: PluginInterface;
private emitter;
/**
* The primary socket for this session. It's used to communicate with the debugger by sending commands and receives responses or updates
*/
private controlSocket;
/**
* Promise that is resolved when the control socket is closed
*/
private controlSocketClosed;
/**
* A socket where the debug server will send stdio
*/
private ioSocket;
/**
* Resolves when the ioSocket has closed
*/
private ioSocketClosed;
/**
* The buffer where all unhandled data will be stored until successfully consumed
*/
private buffer;
/**
* Is the debugger currently stopped at a line of code in the program
*/
isStopped: boolean;
private requestIdSequence;
private activeRequests;
private options;
/**
* Get a promise that resolves after an event occurs exactly once
*/
once(eventName: 'app-exit' | 'cannot-continue' | 'close' | 'start'): Promise;
once(eventName: 'breakpoints-verified'): Promise;
once(eventName: 'runtime-error' | 'suspend'): Promise;
once(eventName: 'io-output'): Promise;
once(eventName: 'data'): Promise;
once(eventName: 'response'): Promise;
once(eventName: 'update'): Promise;
once(eventName: 'protocol-version'): Promise;
once(eventName: 'handshake-verified'): Promise;
on(eventName: 'compile-error', handler: (event: CompileErrorUpdate) => void): any;
on(eventName: 'app-exit' | 'cannot-continue' | 'close' | 'start', handler: () => void): any;
on(eventName: 'breakpoints-verified', handler: (event: BreakpointsVerifiedEvent) => void): any;
on(eventName: 'response', handler: (response: ProtocolResponse) => void): any;
on(eventName: 'update', handler: (update: ProtocolUpdate) => void): any;
/**
* The raw data from the server socket. You probably don't need this...
*/
on(eventName: 'data', handler: (data: Buffer) => void): any;
on(eventName: 'runtime-error' | 'suspend', handler: (data: T) => void): any;
on(eventName: 'io-output', handler: (output: string) => void): any;
on(eventName: 'protocol-version', handler: (data: ProtocolVersionDetails) => void): any;
on(eventName: 'handshake-verified', handler: (data: HandshakeResponse) => void): any;
private emit;
/**
* A collection of sockets created when trying to connect to the debug protocol's control socket. We keep these around for quicker tear-down
* whenever there is an early-terminated debug session
*/
private establishControlConnection;
/**
* A queue for processing the incoming buffer, every transmission at a time
*/
private bufferQueue;
/**
* Connect to the debug server.
* @param sendHandshake should the handshake be sent as part of this connect process. If false, `.sendHandshake()` will need to be called before a session can begin
*/
connect(sendHandshake?: boolean): Promise;
/**
* Send the initial handshake request, and wait for the handshake response
*/
sendHandshake(): Promise;
private processHandshakeRequest;
/**
* Write a specific buffer log entry to the logger, which, when file logging is enabled
* can be extracted and processed through the DebugProtocolClientReplaySession
*/
private writeToBufferLog;
continue(): Promise;
private processContinueRequest;
pause(force?: boolean): Promise;
private processStopRequest;
/**
* Send the "exit channel" command, which will tell the debug session to immediately quit
*/
exitChannel(): Promise;
stepIn(threadIndex?: number): Promise;
stepOver(threadIndex?: number): Promise;
stepOut(threadIndex?: number): Promise;
private step;
private processStepRequest;
threads(): Promise;
processThreadsRequest(request: ThreadsRequest): Promise;
setExceptionBreakpoints(filters: ExceptionBreakpoint[]): Promise;
/**
* Get the stackTrace from the device IF currently stopped
*/
getStackTrace(threadIndex?: number): Promise;
private processStackTraceRequest;
/**
* @param variablePathEntries One or more path entries to the variable to be inspected. E.g., m.top.myObj["someKey"] can be accessed with ["m","top","myobj","\"someKey\""].
*
* If no path is specified, the variables accessible from the specified stack frame are returned.
*
* Starting in protocol v3.1.0, The keys for indexed gets (i.e. obj["key"]) should be wrapped in quotes so they can be handled in a case-sensitive fashion (if applicable on device).
* All non-quoted keys (i.e. strings without leading and trailing quotes inside them) will be treated as case-insensitive).
* @param getChildKeys If set, VARIABLES response include the child keys for container types like lists and associative arrays
* @param stackFrameIndex 0 = first function called, nframes-1 = last function. This indexing does not match the order of the frames returned from the STACKTRACE command
* @param threadIndex the index (or perhaps ID?) of the thread to get variables for
*/
getVariables(variablePathEntries?: Array, stackFrameIndex?: number, threadIndex?: number): Promise;
private processVariablesRequest;
executeCommand(sourceCode: string, stackFrameIndex?: number, threadIndex?: number): Promise;
private processExecuteRequest;
addBreakpoints(breakpoints: Array): Promise;
listBreakpoints(): Promise;
/**
* Remove breakpoints having the specified IDs
*/
removeBreakpoints(breakpointIds: number[]): Promise;
private processRemoveBreakpointsRequest;
/**
* Given a request, process it in the proper fashion. This is mostly used for external mocking/testing of
* this client, but it should force the client to flow in the same fashion as a live debug session
*/
processRequest(request: ProtocolRequest): Promise;
/**
* Send a request to the roku device, and get a promise that resolves once we have received the response
*/
private sendRequest;
/**
* Sometimes a request arrives that we don't understand. If that's the case, this function can be used
* to discard that entire response by discarding `packet_length` number of bytes
*/
private discardNextResponseOrUpdate;
/**
* A counter to help give a unique id to each update (mostly just for logging purposes)
*/
private updateSequence;
private logEvent;
private process;
/**
* Given a buffer, try to parse into a specific ProtocolResponse or ProtocolUpdate
*/
getResponseOrUpdate(buffer: Buffer): Promise;
static getResponse(buffer: Buffer, command: Command): ExecuteV3Response | ListBreakpointsResponse | GenericV3Response | StackTraceV3Response | ThreadsResponse | SetExceptionBreakpointsResponse | VariablesResponse;
getUpdate(buffer: Buffer): ProtocolUpdate;
private handleUpdateQueue;
/**
* Handle/process any received updates from the debug protocol
*/
private handleUpdate;
/**
* Verify all the handshake data
*/
private verifyHandshake;
/**
* When the debugger emits the IOPortOpenedUpdate, we need to immediately connect to the IO port to start receiving that data
*/
private connectToIoPort;
/**
* Destroy this instance, shutting down any sockets or other long-running items and cleaning up.
* @param immediate if true, all sockets are immediately closed and do not gracefully shut down
*/
destroy(immediate?: boolean): Promise;
private shutdownPromise;
private shutdown;
private _shutdown;
private isDestroyingControlSocket;
private destroyControlSocket;
private isDestroyingIOSocket;
/**
* @param immediate if true, force close immediately instead of waiting for it to settle
*/
private destroyIOSocket;
}
export interface ProtocolVersionDetails {
message: string;
errorCode: PROTOCOL_ERROR_CODES;
}
export interface BreakpointSpec {
/**
* The path of the source file where the breakpoint is to be inserted.
*/
filePath: string;
/**
* The (1-based) line number in the channel application code where the breakpoint is to be executed.
*/
lineNumber: number;
/**
* The number of times to ignore the breakpoint condition before executing the breakpoint. This number is decremented each time the channel application reaches the breakpoint.
*/
hitCount?: number;
/**
* BrightScript code that evaluates to a boolean value. The expression is compiled and executed in
* the context where the breakpoint is located. If specified, the hitCount is only be
* updated if this evaluates to true.
* @avaiable since protocol version 3.1.0
*/
conditionalExpression?: string;
}
export interface ConstructorOptions {
/**
* The host/ip address of the Roku
*/
host: string;
/**
* The port number used to send all debugger commands. This is static/unchanging for Roku devices,
* but is configurable here to support unit testing or alternate runtimes (i.e. https://www.npmjs.com/package/brs)
*/
controlPort?: number;
/**
* The interval (in milliseconds) for how frequently the `connect`
* call should retry connecting to the control port. At the start of a debug session,
* the protocol debugger will start trying to connect the moment the channel is sideloaded,
* and keep trying until a successful connection is established or the debug session is terminated
* @default 250
*/
controlConnectInterval?: number;
/**
* The maximum time (in milliseconds) the debugger will keep retrying connections.
* This is here to prevent infinitely pinging the Roku device.
*/
controlConnectMaxTime?: number;
/**
* The number of milliseconds that the client should wait during a shutdown request before forcefully terminating the sockets
*/
shutdownTimeout?: number;
/**
* The max time the client will wait for the `exit channel` response before forcefully terminating the sockets
*/
exitChannelTimeout?: number;
}
/**
* Is the event a ProtocolRequest
*/
export declare function isProtocolRequest(event: ProtocolRequest | ProtocolResponse | ProtocolUpdate): event is ProtocolRequest;
/**
* Is the event a ProtocolResponse
*/
export declare function isProtocolResponse(event: ProtocolRequest | ProtocolResponse | ProtocolUpdate): event is ProtocolResponse;
/**
* Is the event a ProtocolUpdate update
*/
export declare function isProtocolUpdate(event: ProtocolRequest | ProtocolResponse | ProtocolUpdate): event is ProtocolUpdate;
export interface BreakpointsVerifiedEvent {
breakpoints: VerifiedBreakpoint[];
}