• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
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 */
15
16import { Serialize } from '../common/Serialize';
17import { HdcCommand } from './HdcCommand';
18import { Utils } from '../common/Utils';
19import { HANDSHAKE_MESSAGE } from '../common/ConstantType';
20import { PayloadHead } from '../message/PayloadHead';
21import { TransmissionInterface } from '../transmission/TransmissionInterface';
22import { DataProcessing } from '../transmission/DataProcessing';
23import { DataListener } from './DataListener';
24import { DataMessage } from '../message/DataMessage';
25import { SessionHandShake } from '../message/SessionHandShake';
26import { AuthType } from '../message/AuthType';
27import { debug, log } from '../../log/Log';
28import { HdcStream } from './HdcStream';
29import { toHex16 } from '../common/BaseConversion';
30import { USBHead } from '../message/USBHead';
31
32export class HdcClient implements DataListener {
33  // @ts-ignore
34  usbDevice: USBDevice | undefined;
35  sessionId: number = 0;
36  private transmissionChannel: TransmissionInterface;
37  public readDataProcessing: DataProcessing;
38  private cmdStreams = new Map();
39  private isSuccess: boolean = false;
40  private handBody: DataView | undefined;
41  private message: DataMessage | undefined;
42
43  constructor(
44    transmissionChannel: TransmissionInterface,
45    // @ts-ignore
46    usbDevice: USBDevice | undefined
47  ) {
48    this.transmissionChannel = transmissionChannel;
49    this.usbDevice = usbDevice;
50    this.readDataProcessing = new DataProcessing(this, transmissionChannel);
51  }
52
53  async connectDevice(): Promise<boolean> {
54    debug('start Connect Device');
55    this.sessionId = Utils.getSessionId();
56    log(`sessionId is ${this.sessionId}`);
57    this.isSuccess = false;
58    await this.handShakeConnect(AuthType.AUTH_NONE, '');
59    let timeStamp = new Date().getTime();
60    while (await this.readHandShakeMsg()) {
61      if (new Date().getTime() - timeStamp > 10000) {
62        break;
63      }
64      // 后续daemon修复发送通道关闭信息后,可放开this.message?.channelClose以作判断
65      // 非握手包指令,不予理会
66      if (this.message?.commandFlag !== HdcCommand.CMD_KERNEL_HANDSHAKE) {
67        continue;
68      }
69      let backMessage = Serialize.parseHandshake(new Uint8Array(this.message.resArrayBuffer!));
70      // 后续daemon修复增加sessionId数据判定后,可放开backMessage.sessionId !== this.sessionId以作判断
71      const returnBuf: string = backMessage.buf;
72      const returnAuth: number = backMessage.authType;
73      switch (returnAuth) {
74        case AuthType.AUTH_NONE:
75          continue;
76        case AuthType.AUTH_TOKEN:
77          continue;
78        case AuthType.AUTH_SIGNATURE:
79          const response = await fetch(`${window.location.origin}/application/encryptHdcMsg?message=` + returnBuf);
80          const dataBody = await response.json();
81          const encryptHdcMsg = dataBody.success && dataBody.data.signatures;
82          await this.handShakeConnect(AuthType.AUTH_SIGNATURE, encryptHdcMsg);
83          timeStamp = new Date().getTime();
84          continue;
85        case AuthType.AUTH_PUBLICKEY:
86          const responsePub = await fetch(`${window.location.origin}/application/hdcPublicKey`);
87          const data = await responsePub.json();
88          const publicKey = data.success && (`smartPerf-Host` + String.fromCharCode(12) + data.data.publicKey);
89          await this.handShakeConnect(AuthType.AUTH_PUBLICKEY, publicKey);
90          timeStamp = new Date().getTime();
91          continue;
92        case AuthType.AUTH_OK:
93          if (returnBuf.toLocaleLowerCase().indexOf('unauth') === -1 || returnBuf.includes('SUCCESS')) {
94            this.handShakeSuccess(this.handBody!);
95            this.isSuccess = true;
96            break;
97          } else {
98            continue;
99          }
100        default:
101          continue;
102      }
103    }
104    return this.isSuccess;
105  }
106
107  private async handShakeConnect(authType: number, buf: string): Promise<void> {
108    // @ts-ignore
109    let handShake: SessionHandShake = new SessionHandShake(
110      HANDSHAKE_MESSAGE,
111      authType,
112      this.sessionId,
113      // @ts-ignore
114      this.usbDevice.serialNumber,
115      buf,
116      'Ver: 3.0.0b'
117    );
118    let hs = Serialize.serializeSessionHandShake(handShake);
119    debug('start Connect hs ', hs);
120    await this.readDataProcessing.send(
121      handShake.sessionId,
122      0,
123      HdcCommand.CMD_KERNEL_HANDSHAKE,
124      hs,
125      hs.length
126    );
127  }
128
129  private async readHandShakeMsg(): Promise<boolean> {
130    if (this.isSuccess) {
131      return false;
132    }
133    let handShake = await this.readDataProcessing.readUsbHead();
134    this.handBody = await this.readDataProcessing.readBody(handShake!.dataSize);
135    this.message = new DataMessage(handShake!, this.handBody);
136    return true;
137  }
138
139  private handShakeSuccess(handBody: DataView): void {
140    let playHeadArray = handBody.buffer.slice(0, PayloadHead.getPayloadHeadLength());
141    let resultPayloadHead: PayloadHead = PayloadHead.parsePlayHead(new DataView(playHeadArray));
142    debug('resultPayloadHead is ', resultPayloadHead);
143    let headSize = resultPayloadHead.headSize;
144    let dataSize = resultPayloadHead.dataSize;
145    let resPlayProtectBuffer = handBody.buffer.slice(
146      PayloadHead.getPayloadHeadLength(),
147      PayloadHead.getPayloadHeadLength() + headSize
148    );
149    debug('PlayProtect is ', resPlayProtectBuffer);
150    let resData = handBody.buffer.slice(
151      PayloadHead.getPayloadHeadLength() + headSize,
152      PayloadHead.getPayloadHeadLength() + headSize + dataSize
153    );
154    debug('resData is ', resData);
155    this.readDataProcessing.startReadData().then(() => {});
156  }
157  public async disconnect(): Promise<void> {
158    try {
159      await this.transmissionChannel.close();
160      this.readDataProcessing.stopReadData();
161      this.cmdStreams.forEach((value) => {
162        value.putMessageInQueue(new DataMessage(new USBHead([0, 1], -1, -1, -1)));
163      });
164      this.cmdStreams.clear();
165    } catch (e) {}
166  }
167
168  public bindStream(channel: number, hdcStream: HdcStream): void {
169    this.cmdStreams.set(channel, hdcStream);
170  }
171
172  public unbindStream(channel: number): boolean {
173    this.cmdStreams.delete(channel);
174    return true;
175  }
176
177  public unbindStopStream(channel: number): boolean {
178    this.cmdStreams.delete(channel);
179    return true;
180  }
181
182  createDataMessage(data: DataMessage): void {
183    if (this.cmdStreams.has(data.getChannelId())) {
184      let stream = this.cmdStreams.get(data.getChannelId());
185      if (stream) {
186        stream.putMessageInQueue(data);
187      }
188    }
189  }
190}
191