-
Notifications
You must be signed in to change notification settings - Fork 281
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Streaming] Add working ws websocket implementation for Node environm…
…ent (#1334) * add working ws websocket impl * remove unused constants
- Loading branch information
Showing
16 changed files
with
307 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
libraries/botframework-streaming/src/webSocket/factories/wsNodeWebSocketFactory.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/** | ||
* @module botframework-streaming | ||
*/ | ||
/** | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. | ||
*/ | ||
|
||
import { IncomingMessage } from 'http'; | ||
import { Socket } from 'net'; | ||
|
||
import { WsNodeWebSocket } from '../wsNodeWebSocket'; | ||
|
||
export class WsNodeWebSocketFactory { | ||
/** | ||
* Creates a WsNodeWebSocket instance. | ||
* @param req | ||
* @param socket | ||
* @param head | ||
*/ | ||
public async createWebSocket(req: IncomingMessage, socket: Socket, head: Buffer): Promise<WsNodeWebSocket> { | ||
const s = new WsNodeWebSocket(); | ||
await s.create(req, socket, head); | ||
|
||
return s; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
139 changes: 139 additions & 0 deletions
139
libraries/botframework-streaming/src/webSocket/wsNodeWebSocket.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/** | ||
* @module botframework-streaming | ||
*/ | ||
/** | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. | ||
*/ | ||
|
||
import { ISocket } from '../interfaces'; | ||
import { IncomingMessage, request } from 'http'; | ||
import { Socket } from 'net'; | ||
import * as WebSocket from 'ws'; | ||
import * as crypto from 'crypto'; | ||
|
||
const WS_SERVER = new WebSocket.Server({ noServer: true }); | ||
|
||
// Taken from watershed, these needs to be investigated. | ||
const NONCE_LENGTH = 16; | ||
|
||
export class WsNodeWebSocket implements ISocket { | ||
private wsSocket: WebSocket; | ||
private connected: boolean; | ||
|
||
/** | ||
* Creates a new instance of the [WsNodeWebSocket](xref:botframework-streaming.WsNodeWebSocket) class. | ||
* | ||
* @param socket The ws socket object to build this connection on. | ||
*/ | ||
public constructor(wsSocket?: WebSocket) { | ||
this.wsSocket = wsSocket; | ||
this.connected = !!wsSocket; | ||
} | ||
|
||
/** | ||
* Create and set a `ws` WebSocket with an HTTP Request, Socket and Buffer. | ||
* @param req IncomingMessage | ||
* @param socket Socket | ||
* @param head Buffer | ||
*/ | ||
public async create(req: IncomingMessage, socket: Socket, head: Buffer): Promise<void> { | ||
return new Promise<void>((resolve, reject) => { | ||
try { | ||
WS_SERVER.handleUpgrade(req, socket, head, (websocket) => { | ||
this.wsSocket = websocket; | ||
this.connected = true; | ||
resolve(); | ||
}); | ||
} catch (err) { | ||
reject(err); | ||
} | ||
}); | ||
} | ||
|
||
/** | ||
* True if the socket is currently connected. | ||
*/ | ||
public get isConnected(): boolean { | ||
return this.connected; | ||
} | ||
|
||
/** | ||
* Writes a buffer to the socket and sends it. | ||
* | ||
* @param buffer The buffer of data to send across the connection. | ||
*/ | ||
public write(buffer: Buffer): void { | ||
this.wsSocket.send(buffer); | ||
} | ||
|
||
/** | ||
* Connects to the supporting socket using WebSocket protocol. | ||
* | ||
* @param serverAddress The address the server is listening on. | ||
* @param port The port the server is listening on, defaults to 8082. | ||
*/ | ||
public async connect(serverAddress, port = 8082): Promise<void> { | ||
// Taken from WaterShed, this needs to be investigated. | ||
const wskey = crypto.randomBytes(NONCE_LENGTH).toString('base64'); | ||
const options = { | ||
port: port, | ||
hostname: serverAddress, | ||
headers: { | ||
connection: 'upgrade', | ||
'Sec-WebSocket-Key': wskey, | ||
'Sec-WebSocket-Version': '13' | ||
} | ||
}; | ||
const req = request(options); | ||
req.end(); | ||
req.on('upgrade', (res, socket, head): void => { | ||
// @types/ws does not contain the signature for completeUpgrade | ||
// https://github.com/websockets/ws/blob/0a612364e69fc07624b8010c6873f7766743a8e3/lib/websocket-server.js#L269 | ||
(WS_SERVER as any).completeUpgrade(wskey, undefined, res, socket, head, (websocket): void => { | ||
this.wsSocket = websocket; | ||
this.connected = true; | ||
}); | ||
}); | ||
|
||
return new Promise<void>((resolve, reject): void => { | ||
req.on('close', resolve); | ||
req.on('error', reject); | ||
}); | ||
} | ||
|
||
/** | ||
* Set the handler for `'data'` and `'message'` events received on the socket. | ||
*/ | ||
public setOnMessageHandler(handler: (x: any) => void): void { | ||
this.wsSocket.on('data', handler); | ||
this.wsSocket.on('message', handler); | ||
} | ||
|
||
/** | ||
* Close the socket. | ||
* @remarks | ||
* Optionally pass in a status code and string explaining why the connection is closing. | ||
* @param code | ||
* @param data | ||
*/ | ||
public close(code?: number, data?: string): void { | ||
this.connected = false; | ||
|
||
return this.wsSocket.close(code, data); | ||
} | ||
|
||
/** | ||
* Set the callback to call when encountering socket closures. | ||
*/ | ||
public setOnCloseHandler(handler: (x: any) => void): void { | ||
this.wsSocket.on('close', handler); | ||
} | ||
|
||
/** | ||
* Set the callback to call when encountering errors. | ||
*/ | ||
public setOnErrorHandler(handler: (x: any) => void): void { | ||
this.wsSocket.on('error', (error): void => { if (error) { handler(error); } }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.