refactor(ohos): DeviceBridge 409→296 行(协议类型与帧构造移到 BridgeProtocol)

- 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 无
状态机/回调/重连逻辑改动。
This commit is contained in:
root
2026-09-13 22:28:53 +08:00
parent 31bbde9cdd
commit 8a9fc05451
2 changed files with 186 additions and 127 deletions

View File

@ -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<CapResult>;
// ===== 帧构造 =====
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<string, string> = { 'detail': detail };
const msg: Record<string, Object> = {
'op': 'event',
'device_id': deviceId,
'type': eventType,
'payload': payload,
};
return JSON.stringify(msg);
}
export function bridgeStatusFrame(deviceId: string, status: string): string {
const msg: Record<string, Object> = {
'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;
}

View File

@ -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<CapResult>;
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<string, string> = { 'detail': detail };
const msg: Record<string, Object> = {
'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<string, Object> = {
'op': 'status',
'device_id': this.deviceId,
'status': status,
};
this.send(JSON.stringify(msg));
this.send(bridgeStatusFrame(this.deviceId, status));
}
send(text: string): void {