UNPKG

botframework-streaming

Version:

Streaming library for the Microsoft Bot Framework

113 lines (104 loc) 4.64 kB
/** * @module botframework-streaming */ /** * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ import { connect } from 'net'; import { ProtocolAdapter } from '../protocolAdapter'; import { RequestHandler } from '../requestHandler'; import { StreamingRequest } from '../streamingRequest'; import { RequestManager } from '../payloads'; import { PayloadReceiver, PayloadSender } from '../payloadTransport'; import { NamedPipeTransport } from './namedPipeTransport'; import { IStreamingTransportClient, IReceiveResponse } from '../interfaces'; /** * Streaming transport client implementation that uses named pipes for inter-process communication. */ export class NamedPipeClient implements IStreamingTransportClient { private readonly _baseName: string; private readonly _requestHandler: RequestHandler; private readonly _sender: PayloadSender; private readonly _receiver: PayloadReceiver; private readonly _requestManager: RequestManager; private readonly _protocolAdapter: ProtocolAdapter; private readonly _autoReconnect: boolean; private _isDisconnecting: boolean; /** * Creates a new instance of the [NamedPipeClient](xref:botframework-streaming.NamedPipeClient) class. * * @param baseName The named pipe to connect to. * @param requestHandler Optional [RequestHandler](xref:botframework-streaming.RequestHandler) to process incoming messages received by this client. * @param autoReconnect Optional setting to determine if the client sould attempt to reconnect automatically on disconnection events. Defaults to true. */ constructor(baseName: string, requestHandler?: RequestHandler, autoReconnect = true) { this._baseName = baseName; this._requestHandler = requestHandler; this._autoReconnect = autoReconnect; this._requestManager = new RequestManager(); this._sender = new PayloadSender(); this._sender.disconnected = this.onConnectionDisconnected.bind(this); this._receiver = new PayloadReceiver(); this._receiver.disconnected = this.onConnectionDisconnected.bind(this); this._protocolAdapter = new ProtocolAdapter( this._requestHandler, this._requestManager, this._sender, this._receiver, ); } /** * Establish a connection with no custom headers. */ async connect(): Promise<void> { const outgoingPipeName: string = NamedPipeTransport.PipePath + this._baseName + NamedPipeTransport.ServerIncomingPath; const outgoing = connect(outgoingPipeName); const incomingPipeName: string = NamedPipeTransport.PipePath + this._baseName + NamedPipeTransport.ServerOutgoingPath; const incoming = connect(incomingPipeName); this._sender.connect(new NamedPipeTransport(outgoing)); this._receiver.connect(new NamedPipeTransport(incoming)); } /** * Disconnect the client. */ disconnect(): void { this._sender.disconnect(); this._receiver.disconnect(); } /** * Task used to send data over this client connection. * * @param request The [StreamingRequest](xref:botframework-streaming.StreamingRequest) to send. * @returns A promise for an instance of [IReceiveResponse](xref:botframework-streaming.IReceiveResponse) on completion of the send operation. */ async send(request: StreamingRequest): Promise<IReceiveResponse> { return this._protocolAdapter.sendRequest(request); } private onConnectionDisconnected(sender: Record<string, unknown>, args: any): void { if (!this._isDisconnecting) { this._isDisconnecting = true; try { if (this._sender.isConnected) { this._sender.disconnect(); } if (this._receiver.isConnected) { this._receiver.disconnect(); } if (this._autoReconnect) { this.connect() .then((): void => {}) .catch((error): void => { throw new Error( `Failed to reconnect. Reason: ${error.message} Sender: ${sender} Args: ${args}. `, ); }); } } finally { this._isDisconnecting = false; } } } }