nerdbank-streams
Version:
Multiplexing of streams
221 lines (220 loc) • 11.6 kB
TypeScript
import CancellationToken from 'cancellationtoken';
import { Channel, ChannelClass } from './Channel';
import { ChannelOptions } from './ChannelOptions';
import { ControlCode } from './ControlCode';
import { Deferred } from './Deferred';
import { FrameHeader } from './FrameHeader';
import { IChannelOfferEventArgs } from './IChannelOfferEventArgs';
import { IDisposableObservable } from './IDisposableObservable';
import { MultiplexingStreamFormatter } from './MultiplexingStreamFormatters';
import './MultiplexingStreamOptions';
import { MultiplexingStreamOptions } from './MultiplexingStreamOptions';
import { QualifiedChannelId } from './QualifiedChannelId';
export declare abstract class MultiplexingStream implements IDisposableObservable {
protected readonly formatter: MultiplexingStreamFormatter;
private readonly isOdd;
/**
* The maximum length of a frame's payload.
*/
static readonly framePayloadMaxLength: number;
private static readonly recommendedDefaultChannelReceivingWindowSize;
/** The default window size used for new channels that do not specify a value for ChannelOptions.ChannelReceivingWindowSize. */
readonly defaultChannelReceivingWindowSize: number;
protected get disposalToken(): CancellationToken;
/**
* Gets a promise that is resolved or rejected based on how this stream is disposed or fails.
*/
get completion(): Promise<void>;
/**
* Gets a value indicating whether this instance has been disposed.
*/
get isDisposed(): boolean;
/**
* Initializes a new instance of the `MultiplexingStream` class.
* @param stream The duplex stream to read and write to.
* Use `FullDuplexStream.Splice` if you have distinct input/output streams.
* @param options Options to customize the behavior of the stream.
* @param cancellationToken A token whose cancellation aborts the handshake with the remote end.
* @returns The multiplexing stream, once the handshake is complete.
*/
static CreateAsync(stream: NodeJS.ReadWriteStream, options?: MultiplexingStreamOptions, cancellationToken?: CancellationToken): Promise<MultiplexingStream>;
/**
* Initializes a new instance of the `MultiplexingStream` class
* with protocolMajorVersion set to 3.
* @param stream The duplex stream to read and write to.
* Use `FullDuplexStream.Splice` if you have distinct input/output streams.
* @param options Options to customize the behavior of the stream.
* @returns The multiplexing stream.
*/
static Create(stream: NodeJS.ReadWriteStream, options?: MultiplexingStreamOptions): MultiplexingStream;
/**
* The options to use for channels we create in response to incoming offers.
* @description Whatever these settings are, they can be replaced when the channel is accepted.
*/
protected static readonly defaultChannelOptions: ChannelOptions;
/**
* The encoding used for characters in control frames.
*/
static readonly ControlFrameEncoding = "utf-8";
protected readonly _completionSource: Deferred<void>;
/**
* A dictionary of channels that were seeded, keyed by their ID.
*/
protected readonly seededOpenChannels: {
[id: number]: ChannelClass;
};
/**
* A dictionary of channels that were offered locally, keyed by their ID.
*/
protected readonly locallyOfferedOpenChannels: {
[id: number]: ChannelClass;
};
/**
* A dictionary of channels that were offered remotely, keyed by their ID.
*/
protected readonly remotelyOfferedOpenChannels: {
[id: number]: ChannelClass;
};
/**
* The last number assigned to a channel.
* Each use of this should increment by two if isOdd is defined.
* It should never exceed uint32.MaxValue
*/
protected abstract lastOfferedChannelId: number;
/**
* A map of channel names to queues of channels waiting for local acceptance.
*/
protected readonly channelsOfferedByThemByName: {
[name: string]: ChannelClass[];
};
/**
* A map of channel names to queues of Deferred<Channel> from waiting accepters.
*/
protected readonly acceptingChannels: {
[name: string]: Deferred<ChannelClass>[];
};
/** The major version of the protocol being used for this connection. */
protected readonly protocolMajorVersion: number;
private readonly eventEmitter;
private disposalTokenSource;
protected constructor(formatter: MultiplexingStreamFormatter, isOdd: boolean | undefined, options: MultiplexingStreamOptions);
/**
* Creates an anonymous channel that may be accepted by <see cref="AcceptChannel(int, ChannelOptions)"/>.
* Its existance must be communicated by other means (typically another, existing channel) to encourage acceptance.
* @param options A set of options that describe local treatment of this channel.
* @returns The anonymous channel.
* @description Note that while the channel is created immediately, any local write to that channel will be
* buffered locally until the remote party accepts the channel.
*/
createChannel(options?: ChannelOptions): Channel;
/**
* Accepts a channel with a specific ID.
* @param id The id of the channel to accept.
* @param options A set of options that describe local treatment of this channel.
* @description This method can be used to accept anonymous channels created with <see cref="CreateChannel"/>.
* Unlike <see cref="AcceptChannelAsync(string, ChannelOptions, CancellationToken)"/> which will await
* for a channel offer if a matching one has not been made yet, this method only accepts an offer
* for a channel that has already been made.
*/
acceptChannel(id: number, options?: ChannelOptions): Channel;
/**
* Rejects an offer for the channel with a specified ID.
* @param id The ID of the channel whose offer should be rejected.
*/
rejectChannel(id: number): void;
/**
* Offers a new, named channel to the remote party so they may accept it with
* {@link acceptChannelAsync}.
* @param name A name for the channel, which must be accepted on the remote end to complete creation.
* It need not be unique, and may be empty but must not be null.
* Any characters are allowed, and max length is determined by the maximum frame payload (based on UTF-8 encoding).
* @param options A set of options that describe local treatment of this channel.
* @param cancellationToken A cancellation token. Do NOT let this be a long-lived token
* or a memory leak will result since we add continuations to its promise.
* @returns A task that completes with the `Channel` if the offer is accepted on the remote end
* or faults with `MultiplexingProtocolException` if the remote end rejects the channel.
*/
offerChannelAsync(name: string, options?: ChannelOptions, cancellationToken?: CancellationToken): Promise<Channel>;
/**
* Accepts a channel that the remote end has attempted or may attempt to create.
* @param name The name of the channel to accept.
* An empty string will match an offer made via {@link offerChannelAsync} with an empty channel name.
* It will also match an anonymous channel offer made with {@link createChannel}.
* @param options A set of options that describe local treatment of this channel.
* @param cancellationToken A token to indicate lost interest in accepting the channel.
* Do NOT let this be a long-lived token
* or a memory leak will result since we add continuations to its promise.
* @returns The `Channel`, after its offer has been received from the remote party and accepted.
* @description If multiple offers exist with the specified `name`, the first one received will be accepted.
*/
acceptChannelAsync(name: string, options?: ChannelOptions, cancellationToken?: CancellationToken): Promise<Channel>;
/**
* Disposes the stream.
*/
dispose(): void;
protected disposeCore(remoteDisconnect: boolean): void;
on(event: 'channelOffered', listener: (args: IChannelOfferEventArgs) => void): void;
off(event: 'channelOffered', listener: (args: IChannelOfferEventArgs) => void): void;
once(event: 'channelOffered', listener: (args: IChannelOfferEventArgs) => void): void;
protected raiseChannelOffered(id: number, name: string, isAccepted: boolean): void;
protected abstract sendFrameAsync(header: FrameHeader, payload: Buffer, cancellationToken: CancellationToken): Promise<void>;
protected abstract sendFrame(code: ControlCode, channelId: QualifiedChannelId): Promise<void>;
protected acceptChannelOrThrow(channel: ChannelClass, options?: ChannelOptions): void;
/**
* Disposes this instance if the specified promise is rejected.
* @param promise The promise to check for failures.
*/
protected rejectOnFailure<T>(promise: Promise<T>): Promise<void>;
protected removeChannelFromOfferedQueue(channel: ChannelClass): void;
protected getOpenChannel(qualifiedId: QualifiedChannelId): ChannelClass | undefined;
protected setOpenChannel(channel: ChannelClass): void;
protected deleteOpenChannel(qualifiedId: QualifiedChannelId): void;
private getChannelCollection;
/**
* Cancels a prior call to acceptChannelAsync
* @param channel The promise of a channel to be canceled.
* @param name The name of the channel the caller was accepting.
* @param reason The reason for cancellation.
*/
private acceptChannelCanceled;
/**
* Responds to cancellation of a prior call to offerChannelAsync.
* @param channel The channel previously offered.
*/
private offerChannelCanceled;
/**
* Gets a unique number that can be used to represent a channel.
* @description The channel numbers increase by two in order to maintain odd or even numbers,
* since each party is allowed to create only one or the other.
*/
private getUnusedChannelId;
}
export declare class MultiplexingStreamClass extends MultiplexingStream {
protected lastOfferedChannelId: number;
private readonly sendingSemaphore;
constructor(formatter: MultiplexingStreamFormatter, isOdd: boolean | undefined, options: MultiplexingStreamOptions);
get backpressureSupportEnabled(): boolean;
sendFrameAsync(header: FrameHeader, payload?: Buffer, cancellationToken?: CancellationToken): Promise<void>;
/**
* Transmits a frame over the stream.
* @param code The op code for the channel.
* @param channelId The ID of the channel to receive the frame.
* @description The promise returned from this function is always resolved (not rejected)
* since it is anticipated that callers may not be awaiting its result.
*/
sendFrame(code: ControlCode, channelId: QualifiedChannelId): Promise<void>;
onChannelWritingCompleted(channel: ChannelClass): void;
onChannelDisposed(channel: ChannelClass, error: Error | null): Promise<void>;
localContentExamined(channel: ChannelClass, bytesConsumed: number): void;
private readFromStream;
private onOffer;
private onOfferAccepted;
private onContent;
private onContentProcessed;
private onContentWritingCompleted;
/**
* Occurs when the remote party has terminated a channel (including canceling an offer).
* @param channelId The ID of the terminated channel.
*/
private onChannelTerminated;
}