From 8a9fc05451db80fb279d4d94be433e37ba05d370 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 13 Sep 2026 22:28:53 +0800 Subject: [PATCH] =?UTF-8?q?refactor(ohos):=20DeviceBridge=20409=E2=86=9229?= =?UTF-8?q?6=20=E8=A1=8C=EF=BC=88=E5=8D=8F=E8=AE=AE=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E4=B8=8E=E5=B8=A7=E6=9E=84=E9=80=A0=E7=A7=BB=E5=88=B0=20Bridge?= =?UTF-8?q?Protocol=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - common/BridgeProtocol.ets(168):hello/bind/cmd_result/cmd_data_start/ cmd_data_end/event/status 七个消息结构、CHUNK_SIZE、BridgeCmdHandler 回调类型, 以及 bridgeHelloFrame / bridgeBindFrame / bridgeResultFrame / bridgeDataStartFrame / bridgeDataEndFrame / bridgeEventFrame / bridgeStatusFrame / bridgeChunkSlices 八个纯构造/切片函数 - common/DeviceBridge.ets(296):只剩 socket 生命周期、重连代际、绑定状态机 与命令分发 **DeviceBridgeClient 的对外方法名与签名一字未改**(isConnected / getDeviceId / setCmdHandler / setStateListener / connect / updateAuthorized / disconnect / sendResult / sendDataChunked / sendEvent / sendStatus / send), `send*` 仍是"拼帧 + 发出去"两步,拼帧那一步搬走;分块发送的 "start → chunks(失败即 break)→ end"顺序与 `bytes.slice` 语义保持不变。 外部只有 deviceBridge 单例被 import(BridgeRouter / DeviceBridgeSession / DevicePage),无其它符号依赖。 验证:hvigorw assembleHap BUILD SUCCESSFUL;diff 中 DeviceBridge.ets 无 状态机/回调/重连逻辑改动。 --- .../src/main/ets/common/BridgeProtocol.ets | 172 ++++++++++++++++++ .../src/main/ets/common/DeviceBridge.ets | 141 ++------------ 2 files changed, 186 insertions(+), 127 deletions(-) create mode 100644 cmd/ohos/HomeAgent/entry/src/main/ets/common/BridgeProtocol.ets diff --git a/cmd/ohos/HomeAgent/entry/src/main/ets/common/BridgeProtocol.ets b/cmd/ohos/HomeAgent/entry/src/main/ets/common/BridgeProtocol.ets new file mode 100644 index 0000000..e50bbdd --- /dev/null +++ b/cmd/ohos/HomeAgent/entry/src/main/ets/common/BridgeProtocol.ets @@ -0,0 +1,172 @@ +/** + * 设备桥协议:消息结构、帧构造与分块切片。 + * + * 与 homed 的 remotedevice 插件对齐(internal/plugins/remotedevice)。 + * 从 common/DeviceBridge.ets 抽出:这里只有"协议形状"和"帧怎么拼", + * 没有任何 socket、状态机与重连逻辑 —— 那些留在 DeviceBridgeClient 里。 + * + * 注意:DeviceBridgeClient 的对外方法名与语义不因本文件而改变, + * 各 send* 方法仍是"拼帧 + 发出去"两步,只是第一步搬到了这里。 + */ + +import { CapResult } from './BridgeCaps'; + +// ===== 协议消息(与 remotedevice 插件对齐)===== + +export interface HelloDeviceInfo { + hostname: string; + platform: string; + arch: string; + os_release: string; + version: string; + cpus: number; +} + +export interface HelloDevice { + device_id: string; + name: string; + kind: string; + authorized: boolean; + caps: string[]; + info: HelloDeviceInfo; +} + +export interface HelloMessage { + op: string; + device: HelloDevice; +} + +export interface BindMessage { + op: string; + device_id: string; + token: string; +} + +export interface CmdReply { + op: string; // 'cmd_result' + req_id: string; + status: string; + output: string; + error: string; +} + +export interface DataStartMessage { + op: string; + req_id: string; + kind: string; + mime: string; + total: number; + chunk_size: number; +} + +export interface DataEndMessage { + op: string; + req_id: string; + status: string; + total?: number; + error?: string; +} + +export const CHUNK_SIZE: number = 8192; + +// ===== 命令处理器回调 ===== +// 返回 CapResult;二进制大结果通过 dataHandler 分块回传。 +export type BridgeCmdHandler = (reqId: string, command: string) => Promise; + +// ===== 帧构造 ===== + +export function bridgeHelloFrame(deviceId: string, name: string, kind: string, + caps: string[], hostname: string, + authorized: boolean): string { + const info: HelloDeviceInfo = { + hostname: hostname, + platform: 'OpenHarmony', + arch: '', + os_release: '', + version: '1.1.1', + cpus: 0, + }; + const device: HelloDevice = { + device_id: deviceId, + name: name, + kind: kind, + authorized: authorized, + caps: caps, + info: info, + }; + const hello: HelloMessage = { op: 'hello', device: device }; + return JSON.stringify(hello); +} + +export function bridgeBindFrame(deviceId: string, token: string): string { + const bind: BindMessage = { + op: 'bind', + device_id: deviceId, + token: token, + }; + return JSON.stringify(bind); +} + +export function bridgeResultFrame(reqId: string, status: string, + output: string, errMsg: string): string { + const result: CmdReply = { + op: 'cmd_result', + req_id: reqId, + status: status, + output: output, + error: errMsg, + }; + return JSON.stringify(result); +} + +export function bridgeDataStartFrame(reqId: string, kind: string, mime: string, + total: number): string { + const startMsg: DataStartMessage = { + op: 'cmd_data_start', + req_id: reqId, + kind: kind, + mime: mime, + total: total, + chunk_size: CHUNK_SIZE, + }; + return JSON.stringify(startMsg); +} + +export function bridgeDataEndFrame(reqId: string): string { + const endMsg: DataEndMessage = { + op: 'cmd_data_end', + req_id: reqId, + status: 'ok', + }; + return JSON.stringify(endMsg); +} + +export function bridgeEventFrame(deviceId: string, eventType: string, detail: string): string { + const payload: Record = { 'detail': detail }; + const msg: Record = { + 'op': 'event', + 'device_id': deviceId, + 'type': eventType, + 'payload': payload, + }; + return JSON.stringify(msg); +} + +export function bridgeStatusFrame(deviceId: string, status: string): string { + const msg: Record = { + 'op': 'status', + 'device_id': deviceId, + 'status': status, + }; + return JSON.stringify(msg); +} + +/** 按 CHUNK_SIZE 切二进制;切片顺序即发送顺序。 */ +export function bridgeChunkSlices(bytes: Uint8Array): Uint8Array[] { + const out: Uint8Array[] = []; + for (let off: number = 0; off < bytes.byteLength; off += CHUNK_SIZE) { + const end: number = Math.min(off + CHUNK_SIZE, bytes.byteLength); + out.push(bytes.slice(off, end)); + } + return out; +} diff --git a/cmd/ohos/HomeAgent/entry/src/main/ets/common/DeviceBridge.ets b/cmd/ohos/HomeAgent/entry/src/main/ets/common/DeviceBridge.ets index 76c41e3..16d0b4c 100644 --- a/cmd/ohos/HomeAgent/entry/src/main/ets/common/DeviceBridge.ets +++ b/cmd/ohos/HomeAgent/entry/src/main/ets/common/DeviceBridge.ets @@ -1,67 +1,8 @@ import { webSocket } from '@kit.NetworkKit'; import { CapResult } from './BridgeCaps'; - -// ===== 协议消息(与 remotedevice 插件对齐)===== - -interface HelloDeviceInfo { - hostname: string; - platform: string; - arch: string; - os_release: string; - version: string; - cpus: number; -} - -interface HelloDevice { - device_id: string; - name: string; - kind: string; - authorized: boolean; - caps: string[]; - info: HelloDeviceInfo; -} - -interface HelloMessage { - op: string; - device: HelloDevice; -} - -interface BindMessage { - op: string; - device_id: string; - token: string; -} - -export interface CmdReply { - op: string; // 'cmd_result' - req_id: string; - status: string; - output: string; - error: string; -} - -interface DataStartMessage { - op: string; - req_id: string; - kind: string; - mime: string; - total: number; - chunk_size: number; -} - -interface DataEndMessage { - op: string; - req_id: string; - status: string; - total?: number; - error?: string; -} - -const CHUNK_SIZE: number = 8192; - -// ===== 命令处理器回调 ===== -// 返回 CapResult;二进制大结果通过 dataHandler 分块回传。 -export type BridgeCmdHandler = (reqId: string, command: string) => Promise; +import { BridgeCmdHandler, bridgeHelloFrame, bridgeBindFrame, bridgeResultFrame, + bridgeDataStartFrame, bridgeDataEndFrame, bridgeEventFrame, bridgeStatusFrame, + bridgeChunkSlices } from './BridgeProtocol'; export class DeviceBridgeClient { private ws: webSocket.WebSocket = webSocket.createWebSocket(); @@ -247,33 +188,12 @@ export class DeviceBridgeClient { private sendHello(authorized: boolean): void { this.lastAuthorized = authorized; - const info: HelloDeviceInfo = { - hostname: this.hostname, - platform: 'OpenHarmony', - arch: '', - os_release: '', - version: '1.1.1', - cpus: 0, - }; - const device: HelloDevice = { - device_id: this.deviceId, - name: this.name, - kind: this.kind, - authorized: authorized, - caps: this.caps, - info: info, - }; - const hello: HelloMessage = { op: 'hello', device: device }; - this.send(JSON.stringify(hello)); + this.send(bridgeHelloFrame(this.deviceId, this.name, this.kind, this.caps, + this.hostname, authorized)); } private sendBind(): void { - const bind: BindMessage = { - op: 'bind', - device_id: this.deviceId, - token: this.token, - }; - this.send(JSON.stringify(bind)); + this.send(bridgeBindFrame(this.deviceId, this.token)); } // ===== 命令处理 ===== @@ -334,32 +254,16 @@ export class DeviceBridgeClient { } sendResult(reqId: string, status: string, output: string, errMsg: string): void { - const result: CmdReply = { - op: 'cmd_result', - req_id: reqId, - status: status, - output: output, - error: errMsg, - }; - this.send(JSON.stringify(result)); + this.send(bridgeResultFrame(reqId, status, output, errMsg)); } // ===== 二进制分块回传(协议与 GUI 客户端一致)===== sendDataChunked(reqId: string, kind: string, mime: string, bytes: Uint8Array): void { - const startMsg: DataStartMessage = { - op: 'cmd_data_start', - req_id: reqId, - kind: kind, - mime: mime, - total: bytes.byteLength, - chunk_size: CHUNK_SIZE, - }; - this.send(JSON.stringify(startMsg)); - for (let off: number = 0; off < bytes.byteLength; off += CHUNK_SIZE) { - const end: number = Math.min(off + CHUNK_SIZE, bytes.byteLength); - const view: Uint8Array = bytes.slice(off, end); - const ab: ArrayBuffer = view.buffer as ArrayBuffer; + this.send(bridgeDataStartFrame(reqId, kind, mime, bytes.byteLength)); + const chunks: Uint8Array[] = bridgeChunkSlices(bytes); + for (let i = 0; i < chunks.length; i++) { + const ab: ArrayBuffer = chunks[i].buffer as ArrayBuffer; try { this.ws.send(ab).catch(() => { // ignore per-chunk failure; end frame reports error below @@ -368,32 +272,15 @@ export class DeviceBridgeClient { break; } } - const endMsg: DataEndMessage = { - op: 'cmd_data_end', - req_id: reqId, - status: 'ok', - }; - this.send(JSON.stringify(endMsg)); + this.send(bridgeDataEndFrame(reqId)); } sendEvent(eventType: string, detail: string): void { - const payload: Record = { 'detail': detail }; - const msg: Record = { - 'op': 'event', - 'device_id': this.deviceId, - 'type': eventType, - 'payload': payload, - }; - this.send(JSON.stringify(msg)); + this.send(bridgeEventFrame(this.deviceId, eventType, detail)); } sendStatus(status: string): void { - const msg: Record = { - 'op': 'status', - 'device_id': this.deviceId, - 'status': status, - }; - this.send(JSON.stringify(msg)); + this.send(bridgeStatusFrame(this.deviceId, status)); } send(text: string): void {