| // Copyright (C) 2022 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| import {defer} from '../../base/deferred'; |
| |
| import { |
| ByteStream, |
| OnStreamCloseCallback, |
| OnStreamDataCallback, |
| } from './recording_interfaces_v2'; |
| |
| // A HostOsByteStream instantiates a websocket connection to the host OS. |
| // It exposes an API to write commands to this websocket and read its output. |
| export class HostOsByteStream implements ByteStream { |
| // handshakeSignal will be resolved with the stream when the websocket |
| // connection becomes open. |
| private handshakeSignal = defer<HostOsByteStream>(); |
| private _isConnected: boolean = false; |
| private websocket: WebSocket; |
| private onStreamDataCallbacks: OnStreamDataCallback[] = []; |
| private onStreamCloseCallbacks: OnStreamCloseCallback[] = []; |
| |
| private constructor(websocketUrl: string) { |
| this.websocket = new WebSocket(websocketUrl); |
| this.websocket.onmessage = this.onMessage.bind(this); |
| this.websocket.onopen = this.onOpen.bind(this); |
| } |
| |
| addOnStreamDataCallback(onStreamData: OnStreamDataCallback): void { |
| this.onStreamDataCallbacks.push(onStreamData); |
| } |
| |
| addOnStreamCloseCallback(onStreamClose: OnStreamCloseCallback): void { |
| this.onStreamCloseCallbacks.push(onStreamClose); |
| } |
| |
| close(): void { |
| this.websocket.close(); |
| for (const onStreamClose of this.onStreamCloseCallbacks) { |
| onStreamClose(); |
| } |
| this.onStreamDataCallbacks = []; |
| this.onStreamCloseCallbacks = []; |
| } |
| |
| async closeAndWaitForTeardown(): Promise<void> { |
| this.close(); |
| } |
| |
| isConnected(): boolean { |
| return this._isConnected; |
| } |
| |
| write(msg: string|Uint8Array): void { |
| this.websocket.send(msg); |
| } |
| |
| private async onMessage(evt: MessageEvent) { |
| for (const onStreamData of this.onStreamDataCallbacks) { |
| const arrayBufferResponse = await evt.data.arrayBuffer(); |
| onStreamData(new Uint8Array(arrayBufferResponse)); |
| } |
| } |
| |
| private onOpen() { |
| this._isConnected = true; |
| this.handshakeSignal.resolve(this); |
| } |
| |
| static create(websocketUrl: string): Promise<HostOsByteStream> { |
| return (new HostOsByteStream(websocketUrl)).handshakeSignal; |
| } |
| } |