sussudio
Version:
An unofficial VS Code Internal API
352 lines (351 loc) • 12.8 kB
text/typescript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { VSBuffer } from "../../../common/buffer.mjs";
import { Event } from "../../../common/event.mjs";
import { Disposable, IDisposable } from "../../../common/lifecycle.mjs";
import { IIPCLogger, IMessagePassingProtocol, IPCClient } from "./ipc.mjs";
export declare const enum SocketDiagnosticsEventType {
Created = "created",
Read = "read",
Write = "write",
Open = "open",
Error = "error",
Close = "close",
BrowserWebSocketBlobReceived = "browserWebSocketBlobReceived",
NodeEndReceived = "nodeEndReceived",
NodeEndSent = "nodeEndSent",
NodeDrainBegin = "nodeDrainBegin",
NodeDrainEnd = "nodeDrainEnd",
zlibInflateError = "zlibInflateError",
zlibInflateData = "zlibInflateData",
zlibInflateInitialWrite = "zlibInflateInitialWrite",
zlibInflateInitialFlushFired = "zlibInflateInitialFlushFired",
zlibInflateWrite = "zlibInflateWrite",
zlibInflateFlushFired = "zlibInflateFlushFired",
zlibDeflateError = "zlibDeflateError",
zlibDeflateData = "zlibDeflateData",
zlibDeflateWrite = "zlibDeflateWrite",
zlibDeflateFlushFired = "zlibDeflateFlushFired",
WebSocketNodeSocketWrite = "webSocketNodeSocketWrite",
WebSocketNodeSocketPeekedHeader = "webSocketNodeSocketPeekedHeader",
WebSocketNodeSocketReadHeader = "webSocketNodeSocketReadHeader",
WebSocketNodeSocketReadData = "webSocketNodeSocketReadData",
WebSocketNodeSocketUnmaskedData = "webSocketNodeSocketUnmaskedData",
WebSocketNodeSocketDrainBegin = "webSocketNodeSocketDrainBegin",
WebSocketNodeSocketDrainEnd = "webSocketNodeSocketDrainEnd",
ProtocolHeaderRead = "protocolHeaderRead",
ProtocolMessageRead = "protocolMessageRead",
ProtocolHeaderWrite = "protocolHeaderWrite",
ProtocolMessageWrite = "protocolMessageWrite",
ProtocolWrite = "protocolWrite"
}
export declare namespace SocketDiagnostics {
const enableDiagnostics = false;
interface IRecord {
timestamp: number;
id: string;
label: string;
type: SocketDiagnosticsEventType;
buff?: VSBuffer;
data?: any;
}
const records: IRecord[];
function traceSocketEvent(nativeObject: any, socketDebugLabel: string, type: SocketDiagnosticsEventType, data?: VSBuffer | Uint8Array | ArrayBuffer | ArrayBufferView | any): void;
}
export declare const enum SocketCloseEventType {
NodeSocketCloseEvent = 0,
WebSocketCloseEvent = 1
}
export interface NodeSocketCloseEvent {
/**
* The type of the event
*/
readonly type: SocketCloseEventType.NodeSocketCloseEvent;
/**
* `true` if the socket had a transmission error.
*/
readonly hadError: boolean;
/**
* Underlying error.
*/
readonly error: Error | undefined;
}
export interface WebSocketCloseEvent {
/**
* The type of the event
*/
readonly type: SocketCloseEventType.WebSocketCloseEvent;
/**
* Returns the WebSocket connection close code provided by the server.
*/
readonly code: number;
/**
* Returns the WebSocket connection close reason provided by the server.
*/
readonly reason: string;
/**
* Returns true if the connection closed cleanly; false otherwise.
*/
readonly wasClean: boolean;
/**
* Underlying event.
*/
readonly event: any | undefined;
}
export type SocketCloseEvent = NodeSocketCloseEvent | WebSocketCloseEvent | undefined;
export interface SocketTimeoutEvent {
readonly unacknowledgedMsgCount: number;
readonly timeSinceOldestUnacknowledgedMsg: number;
readonly timeSinceLastReceivedSomeData: number;
}
export interface ISocket extends IDisposable {
onData(listener: (e: VSBuffer) => void): IDisposable;
onClose(listener: (e: SocketCloseEvent) => void): IDisposable;
onEnd(listener: () => void): IDisposable;
write(buffer: VSBuffer): void;
end(): void;
drain(): Promise<void>;
traceSocketEvent(type: SocketDiagnosticsEventType, data?: VSBuffer | Uint8Array | ArrayBuffer | ArrayBufferView | any): void;
}
export declare class ChunkStream {
private _chunks;
private _totalLength;
get byteLength(): number;
constructor();
acceptChunk(buff: VSBuffer): void;
read(byteCount: number): VSBuffer;
peek(byteCount: number): VSBuffer;
private _read;
}
export declare const enum ProtocolConstants {
HeaderLength = 13,
/**
* Send an Acknowledge message at most 2 seconds later...
*/
AcknowledgeTime = 2000,
/**
* If there is a sent message that has been unacknowledged for 20 seconds,
* and we didn't see any incoming server data in the past 20 seconds,
* then consider the connection has timed out.
*/
TimeoutTime = 20000,
/**
* If there is no reconnection within this time-frame, consider the connection permanently closed...
*/
ReconnectionGraceTime = 10800000,
/**
* Maximal grace time between the first and the last reconnection...
*/
ReconnectionShortGraceTime = 300000,
/**
* Send a message every 5 seconds to avoid that the connection is closed by the OS.
*/
KeepAliveSendTime = 5000,
/**
* Measure the latency every 1 minute.
*/
LatencySampleTime = 60000,
/**
* Keep the last 5 samples for latency measurement.
*/
LatencySampleCount = 5,
/**
* A latency over 1s will be considered high.
*/
HighLatencyTimeThreshold = 1000,
/**
* Having 3 or more samples with high latency will trigger a high latency event.
*/
HighLatencySampleThreshold = 3
}
/**
* A message has the following format:
* ```
* /-------------------------------|------\
* | HEADER | |
* |-------------------------------| DATA |
* | TYPE | ID | ACK | DATA_LENGTH | |
* \-------------------------------|------/
* ```
* The header is 9 bytes and consists of:
* - TYPE is 1 byte (ProtocolMessageType) - the message type
* - ID is 4 bytes (u32be) - the message id (can be 0 to indicate to be ignored)
* - ACK is 4 bytes (u32be) - the acknowledged message id (can be 0 to indicate to be ignored)
* - DATA_LENGTH is 4 bytes (u32be) - the length in bytes of DATA
*
* Only Regular messages are counted, other messages are not counted, nor acknowledged.
*/
export declare class Protocol extends Disposable implements IMessagePassingProtocol {
private _socket;
private _socketWriter;
private _socketReader;
private readonly _onMessage;
readonly onMessage: Event<VSBuffer>;
private readonly _onDidDispose;
readonly onDidDispose: Event<void>;
constructor(socket: ISocket);
drain(): Promise<void>;
getSocket(): ISocket;
sendDisconnect(): void;
send(buffer: VSBuffer): void;
}
export declare class Client<TContext = string> extends IPCClient<TContext> {
private protocol;
static fromSocket<TContext = string>(socket: ISocket, id: TContext): Client<TContext>;
get onDidDispose(): Event<void>;
constructor(protocol: Protocol | PersistentProtocol, id: TContext, ipcLogger?: IIPCLogger | null);
dispose(): void;
}
/**
* Will ensure no messages are lost if there are no event listeners.
*/
export declare class BufferedEmitter<T> {
private _emitter;
readonly event: Event<T>;
private _hasListeners;
private _isDeliveringMessages;
private _bufferedMessages;
constructor();
private _deliverMessages;
fire(event: T): void;
flushBuffer(): void;
}
export interface ILoadEstimator {
hasHighLoad(): boolean;
}
export declare const enum ConnectionHealth {
/**
* The connection health is considered good when a certain number of recent round trip time measurements are below a certain threshold.
* @see ProtocolConstants.HighLatencyTimeThreshold @see ProtocolConstants.HighLatencySampleThreshold
*/
Good = 0,
/**
* The connection health is considered poor when a certain number of recent round trip time measurements are above a certain threshold.
* @see ProtocolConstants.HighLatencyTimeThreshold @see ProtocolConstants.HighLatencySampleThreshold
*/
Poor = 1
}
export declare function connectionHealthToString(connectionHealth: ConnectionHealth): 'good' | 'poor';
/**
* An event describing that the connection health has changed.
*/
export declare class ConnectionHealthChangedEvent {
readonly connectionHealth: ConnectionHealth;
constructor(connectionHealth: ConnectionHealth);
}
/**
* An event describing that a round trip time measurement was above a certain threshold.
*/
export declare class HighRoundTripTimeEvent {
/**
* The round trip time in milliseconds.
*/
readonly roundTripTime: number;
/**
* The number of recent round trip time measurements that were above the threshold.
* @see ProtocolConstants.HighLatencyTimeThreshold @see ProtocolConstants.HighLatencySampleThreshold
*/
readonly recentHighRoundTripCount: number;
constructor(
/**
* The round trip time in milliseconds.
*/
roundTripTime: number,
/**
* The number of recent round trip time measurements that were above the threshold.
* @see ProtocolConstants.HighLatencyTimeThreshold @see ProtocolConstants.HighLatencySampleThreshold
*/
recentHighRoundTripCount: number);
}
export interface PersistentProtocolOptions {
/**
* The socket to use.
*/
socket: ISocket;
/**
* The initial chunk of data that has already been received from the socket.
*/
initialChunk?: VSBuffer | null;
/**
* The CPU load estimator to use.
*/
loadEstimator?: ILoadEstimator;
/**
* Whether to measure round trip time. Defaults to false.
*/
measureRoundTripTime?: boolean;
/**
* Whether to send keep alive messages. Defaults to true.
*/
sendKeepAlive?: boolean;
}
/**
* Same as Protocol, but will actually track messages and acks.
* Moreover, it will ensure no messages are lost if there are no event listeners.
*/
export declare class PersistentProtocol implements IMessagePassingProtocol {
private _isReconnecting;
private _outgoingUnackMsg;
private _outgoingMsgId;
private _outgoingAckId;
private _outgoingAckTimeout;
private _incomingMsgId;
private _incomingAckId;
private _incomingMsgLastTime;
private _incomingAckTimeout;
private _keepAliveInterval;
private _lastReplayRequestTime;
private _lastSocketTimeoutTime;
private _socket;
private _socketWriter;
private _socketReader;
private _socketLatencyMonitor;
private _socketDisposables;
private readonly _loadEstimator;
private readonly _measureRoundTripTime;
private readonly _shouldSendKeepAlive;
private readonly _onControlMessage;
readonly onControlMessage: Event<VSBuffer>;
private readonly _onMessage;
readonly onMessage: Event<VSBuffer>;
private readonly _onDidDispose;
readonly onDidDispose: Event<void>;
private readonly _onSocketClose;
readonly onSocketClose: Event<SocketCloseEvent>;
private readonly _onSocketTimeout;
readonly onSocketTimeout: Event<SocketTimeoutEvent>;
private readonly _onHighRoundTripTime;
readonly onHighRoundTripTime: Event<HighRoundTripTimeEvent>;
private readonly _onDidChangeConnectionHealth;
readonly onDidChangeConnectionHealth: Event<ConnectionHealth>;
get unacknowledgedCount(): number;
constructor(opts: PersistentProtocolOptions);
dispose(): void;
drain(): Promise<void>;
sendDisconnect(): void;
sendPause(): void;
sendResume(): void;
pauseSocketWriting(): void;
getSocket(): ISocket;
getMillisSinceLastIncomingData(): number;
beginAcceptReconnection(socket: ISocket, initialDataChunk: VSBuffer | null): void;
endAcceptReconnection(): void;
acceptDisconnect(): void;
private _receiveMessage;
readEntireBuffer(): VSBuffer;
flush(): void;
send(buffer: VSBuffer): void;
/**
* Send a message which will not be part of the regular acknowledge flow.
* Use this for early control messages which are repeated in case of reconnection.
*/
sendControl(buffer: VSBuffer): void;
private _sendAckCheck;
private _recvAckCheck;
private _sendAck;
private _sendKeepAlive;
private _sendLatencyMeasurementRequest;
private _sendLatencyMeasurementResponse;
}