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