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 { DataMessage } from '../message/DataMessage'; 17import { HdcClient } from './HdcClient'; 18import { FormatCommand } from './FormatCommand'; 19import { HdcCommand } from './HdcCommand'; 20import { Utils } from '../common/Utils'; 21import { AsyncQueue } from './AsyncQueue'; 22import { PayloadHead } from '../message/PayloadHead'; 23import { Serialize } from '../common/Serialize'; 24 25export class HdcStream { 26 private dataMessages: AsyncQueue<DataMessage> = new AsyncQueue<DataMessage>(); 27 private readonly channelId: number; 28 private interactiveShellMode: boolean = false; 29 private hdcClient: HdcClient; 30 public fileSize: number = -1; 31 32 constructor(hdcClient: HdcClient, isStopCmd: boolean) { 33 this.hdcClient = hdcClient; 34 this.channelId = Utils.getLocalId(); 35 this.hdcClient.bindStream(this.channelId, this); 36 } 37 38 public async DoCommand(cmd: string): Promise<boolean> { 39 let formatCommand; 40 if (this.interactiveShellMode) { 41 formatCommand = new FormatCommand(HdcCommand.CMD_SHELL_DATA, cmd, false); 42 } else { 43 formatCommand = Utils.formatCommand(cmd); 44 } 45 return this.DoCommandRemote(formatCommand); 46 } 47 48 public async DoCommandRemote(command: FormatCommand): Promise<boolean> { 49 switch (command.cmdFlag) { 50 case HdcCommand.CMD_SHELL_INIT: 51 case HdcCommand.CMD_SHELL_DATA: 52 case HdcCommand.CMD_UNITY_EXECUTE: 53 case HdcCommand.CMD_UNITY_TERMINATE: 54 case HdcCommand.CMD_UNITY_REMOUNT: 55 case HdcCommand.CMD_UNITY_REBOOT: 56 case HdcCommand.CMD_UNITY_RUNMODE: 57 case HdcCommand.CMD_UNITY_HILOG: { 58 let textEncoder = new TextEncoder(); 59 let data = textEncoder.encode(command.parameters); 60 let sendResult = await this.sendToDaemon(command, data, data.length); 61 if (sendResult) { 62 if (HdcCommand.CMD_SHELL_INIT === command.cmdFlag) { 63 this.interactiveShellMode = true; 64 } 65 } 66 break; 67 } 68 case HdcCommand.CMD_FILE_INIT: { 69 await this.FileRecvCommand(command); 70 break; 71 } 72 case HdcCommand.CMD_FILE_FINISH: 73 case HdcCommand.CMD_KERNEL_CHANNEL_CLOSE: { 74 let dataView = new DataView(new ArrayBuffer(1)); 75 if (command.parameters === '0') { 76 dataView.setUint8(0, 0); 77 } else { 78 dataView.setUint8(0, 1); 79 } 80 await this.sendToDaemon(command, new Uint8Array(dataView.buffer), 1); 81 break; 82 } 83 } 84 return false; 85 } 86 87 async FileRecvCommand(command: FormatCommand): Promise<void> { 88 let cmdFlag: string = ''; 89 let sizeCmdFlag: number = 0; 90 if (HdcCommand.CMD_FILE_INIT === command.cmdFlag) { 91 cmdFlag = 'send '; 92 sizeCmdFlag = 5; // 5: cmdFlag send size 93 } 94 if (!(command.parameters.length > cmdFlag.length)) { 95 } else { 96 let textEncoder = new TextEncoder(); 97 let data = textEncoder.encode(command.parameters); 98 let aa = data.slice(5); 99 await this.sendToDaemon(command, aa, aa.length); 100 let fileRecvDataMessage = await this.getMessage(); 101 let fileRecvPlayHeadArray = fileRecvDataMessage.body!.buffer.slice(0, PayloadHead.getPayloadHeadLength()); 102 let fileRecvResultPayloadHead: PayloadHead = PayloadHead.parsePlayHead(new DataView(fileRecvPlayHeadArray)); 103 let fileRecvHeadSize = fileRecvResultPayloadHead.headSize; 104 let resPlayProtectBuffer = fileRecvDataMessage.body!.buffer.slice(11, 11 + fileRecvHeadSize); 105 Serialize.parsePayloadProtect(resPlayProtectBuffer); 106 await this.handleCommandFileCheck(); 107 } 108 } 109 110 private async handleCommandFileCheck(): Promise<void> { 111 let fileCheckDataMessage = await this.getMessage(); 112 let fileCheckPlayHeadArray = fileCheckDataMessage.body!.buffer.slice(0, PayloadHead.getPayloadHeadLength()); 113 let fileCheckResultPayloadHead: PayloadHead = PayloadHead.parsePlayHead(new DataView(fileCheckPlayHeadArray)); 114 let fileCheckHeadSize = fileCheckResultPayloadHead.headSize; 115 let fileCheckDataSize = fileCheckResultPayloadHead.dataSize; 116 let fileCheckResPlayProtectBuffer = fileCheckDataMessage.body!.buffer.slice( 117 PayloadHead.getPayloadHeadLength(), 118 PayloadHead.getPayloadHeadLength() + fileCheckHeadSize 119 ); 120 let fileCheckPayloadProtect = Serialize.parsePayloadProtect(fileCheckResPlayProtectBuffer); 121 if (fileCheckPayloadProtect.commandFlag === HdcCommand.CMD_FILE_CHECK) { 122 if (fileCheckDataSize > 0) { 123 let fileCheckTransferConfigBuffer = fileCheckDataMessage.body!.buffer.slice( 124 PayloadHead.getPayloadHeadLength() + fileCheckHeadSize, 125 PayloadHead.getPayloadHeadLength() + fileCheckHeadSize + fileCheckDataSize 126 ); 127 let fileCheckTransferConfig = Serialize.parseTransferConfig(fileCheckTransferConfigBuffer); 128 this.fileSize = fileCheckTransferConfig.fileSize; 129 } 130 let fileBegin = new FormatCommand(HdcCommand.CMD_FILE_BEGIN, '', false); 131 await this.sendToDaemon(fileBegin, new Uint8Array(0), 0); 132 } 133 } 134 135 async sendToDaemon(command: FormatCommand, payload: Uint8Array, dataLength: number): Promise<boolean> { 136 return await this.hdcClient.readDataProcessing.send( 137 this.hdcClient.sessionId, 138 this.channelId, 139 command.cmdFlag, 140 payload, 141 dataLength 142 ); 143 } 144 145 putMessageInQueue(dataMessage: DataMessage): void { 146 this.dataMessages.enqueue(dataMessage); 147 } 148 149 getMessage(): Promise<DataMessage> { 150 return this.dataMessages.dequeue(); 151 } 152 153 async closeStream(): Promise<void> { 154 this.hdcClient.unbindStream(this.channelId); 155 } 156} 157