• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2022 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import {defer} from '../../base/deferred';
16
17import {
18  ByteStream,
19  OnStreamCloseCallback,
20  OnStreamDataCallback,
21} from './recording_interfaces_v2';
22
23// A HostOsByteStream instantiates a websocket connection to the host OS.
24// It exposes an API to write commands to this websocket and read its output.
25export class HostOsByteStream implements ByteStream {
26  // handshakeSignal will be resolved with the stream when the websocket
27  // connection becomes open.
28  private handshakeSignal = defer<HostOsByteStream>();
29  private _isConnected: boolean = false;
30  private websocket: WebSocket;
31  private onStreamDataCallbacks: OnStreamDataCallback[] = [];
32  private onStreamCloseCallbacks: OnStreamCloseCallback[] = [];
33
34  private constructor(websocketUrl: string) {
35    this.websocket = new WebSocket(websocketUrl);
36    this.websocket.onmessage = this.onMessage.bind(this);
37    this.websocket.onopen = this.onOpen.bind(this);
38  }
39
40  addOnStreamDataCallback(onStreamData: OnStreamDataCallback): void {
41    this.onStreamDataCallbacks.push(onStreamData);
42  }
43
44  addOnStreamCloseCallback(onStreamClose: OnStreamCloseCallback): void {
45    this.onStreamCloseCallbacks.push(onStreamClose);
46  }
47
48  close(): void {
49    this.websocket.close();
50    for (const onStreamClose of this.onStreamCloseCallbacks) {
51      onStreamClose();
52    }
53    this.onStreamDataCallbacks = [];
54    this.onStreamCloseCallbacks = [];
55  }
56
57  async closeAndWaitForTeardown(): Promise<void> {
58    this.close();
59  }
60
61  isConnected(): boolean {
62    return this._isConnected;
63  }
64
65  write(msg: string|Uint8Array): void {
66    this.websocket.send(msg);
67  }
68
69  private async onMessage(evt: MessageEvent) {
70    for (const onStreamData of this.onStreamDataCallbacks) {
71      const arrayBufferResponse = await evt.data.arrayBuffer();
72      onStreamData(new Uint8Array(arrayBufferResponse));
73    }
74  }
75
76  private onOpen() {
77    this._isConnected = true;
78    this.handshakeSignal.resolve(this);
79  }
80
81  static create(websocketUrl: string): Promise<HostOsByteStream> {
82    return (new HostOsByteStream(websocketUrl)).handshakeSignal;
83  }
84}
85