349d94aa8f
- 原生数据面 libwebrtc(PLAN 决策 F):新增 Engine/LibWebRtcEngine.swift(RTCPeerConnection,端口 engine.go/session.go 线协议 + 水位背压 + ack 完成 + 不冲突落盘);NativeTransfer.swift 的 P2PEventsBridge 改 conform P2PEngineDelegate(去 gomobile);EngineController 4 个 p2p RPC 改调新引擎(completion-based + resolveOnMain)。stasel/WebRTC M149 经 SPM(exactVersion 149.0.0)。环回端到端 20MB 逐字节测过(Tests/) - UX 改造(PARITY 残余项 1/2):新增 SendComposeSheet(发送预览=文件名 + 选设备,手动多选与分享共用);分享直入预览 + scenePhase .active 兜底(修“分享后必须重启 app”);重写 MessagesView(按设备会话 + 每设备未读红点 + 删单条 / 删整设备历史);EngineController 加 conversations / unread 模型 - 品牌 logo:新增 Shared/Brand.swift(BrandMark / Wordmark / BrandLockup / BrandHero)+ Brand.xcassets/LogoMark;登录页 / 传输空态 / 设置头 / 控制中心控件接 logo;Theme 加 cdropAmber - 字体(对齐 web,仅主 app):新增 BrandFonts.swift(Orbit Gothic + Maple Mono woff2 运行期 CTFontManager 注册 + UIKit 外观代理 + .oXxx / .maple 助手);Fredoka SemiBold 字标;7 视图 .font sweep。字体不入库——.gitignore 排除 + just ios-fonts 构建前从 CDN / Google Fonts 拉取,见 Sources/Fonts/README.md - 分享引导:新增 Share/ShareGuideView(吉祥物卡 + “打开 Commilitia Drop”);ShareViewController 健壮 staging(文件 / 数据双路)+ 响应链 IMP 唤起宿主 - 全平台平均速度:传输完成态显平均速度(总字节 / 总耗时)而非末次瞬时——web store/slices/transfer.ts + TransferRow.tsx + iOS RootView 卡片 / 详情;i18n 加 transfer.avgRate - 工程:project.yml 接 SPM WebRTC + CDropTests + Fredoka UIAppFonts + Share i18n;Justfile 加 ios-sim-build + ios-fonts / ios-fonts-fredoka 配方 - 文档:ios/PLAN.md(决策 F + §10 UX + §11 品牌/字体 + §12 平均速度)、ios/PARITY.md(字体分叉条目更新 + 2026-06-28 漂移行)
75 lines
3.2 KiB
Swift
75 lines
3.2 KiB
Swift
import Foundation
|
||
|
||
// P2PEventsBridge:libwebrtc 原生数据面引擎(LibWebRtcEngine)的事件宿主。引擎在 libwebrtc 信令
|
||
// 线程(非主线程)触发这些回调,每条都用 DispatchQueue.main.async 跳回主线程再交 EngineController
|
||
// 过桥给无头 JS 引擎(evaluateJavaScript 仅限主线程)。
|
||
//
|
||
// 用 DispatchQueue.main.async 而非 Task { @MainActor }:前者对同源提交保持 FIFO,使
|
||
// connected → completed 等有序状态不被乱序处理(Task 无顺序保证,completed 抢在 connected 前
|
||
// 处理会把终态回退)。assumeIsolated 把主队列闭包桥进 EngineController 的 @MainActor 隔离域。
|
||
//
|
||
// 与桌面 desktop/app.go 的 transferEvents 等价——桌面经 Wails EventsEmit,iOS 经 cdropEngine 桥。
|
||
// 事件契约见 LibWebRtcEngine.swift 的 P2PEngineDelegate;JS 侧消费见
|
||
// web/src/features/transfer/p2pIos.ts(事件名 / payload 形状与桌面 NativeP2PHandlers 同形)。
|
||
final class P2PEventsBridge: P2PEngineDelegate
|
||
{
|
||
weak var controller: EngineController?
|
||
|
||
// 已传字节(发送端=接收端 ack 追平、接收端=已写盘)。
|
||
func engineDidProgress(sessionId: String, bytes: Int64)
|
||
{
|
||
emit("p2pProgress", [ "sessionId": sessionId, "bytes": bytes ])
|
||
}
|
||
|
||
// 会话状态:connected / completed / failed / closed。
|
||
func engineDidChangeState(sessionId: String, state: String)
|
||
{
|
||
emit("p2pState", [ "sessionId": sessionId, "state": state ])
|
||
}
|
||
|
||
// 出站信令(offer/answer/ice):payloadJSON 为信令 JSON 串,JS 侧 POST /api/hub/signal 前
|
||
// 解析(payload 透传字符串再 JSON.parse,与桌面 p2pNative onSignal 同形)。
|
||
func engineDidEmitSignal(sessionId: String, toPeer: String, payloadJSON: String)
|
||
{
|
||
emit("p2pSignal", [
|
||
"sessionId": sessionId,
|
||
"to": toPeer,
|
||
"payload": payloadJSON,
|
||
])
|
||
}
|
||
|
||
// 接收端落盘完成的绝对路径(沙盒 Documents)。落盘提示由原生 transferDone 链路负责,JS 侧
|
||
// p2pIos onSaved 当前为 no-op;事件仍过桥以备用。
|
||
func engineDidSave(sessionId: String, path: String)
|
||
{
|
||
emit("p2pSaved", [ "sessionId": sessionId, "path": path ])
|
||
}
|
||
|
||
// 选中候选对(形如 "host/udp"):填进传输记录的 iceStats 供调试面板展示实际连通路径。
|
||
func engineDidSelectIcePair(sessionId: String, local: String, remote: String)
|
||
{
|
||
emit("p2pIcePair", [
|
||
"sessionId": sessionId,
|
||
"local": local,
|
||
"remote": remote,
|
||
])
|
||
}
|
||
|
||
// 引擎诊断日志(候选 / ICE 态 / 选中对 / 发送停滞):直接进原生日志环形缓冲(#3 日志界面),
|
||
// 不过 JS——诊断由原生侧呈现,便于真机现场排查同内网 mDNS/ICE 时间线。
|
||
func engineDidLog(_ line: String)
|
||
{
|
||
let msg = line
|
||
DispatchQueue.main.async { [weak controller] in
|
||
MainActor.assumeIsolated { controller?.appendNativeLog(msg) }
|
||
}
|
||
}
|
||
|
||
private func emit(_ name: String, _ payload: [String: Any])
|
||
{
|
||
DispatchQueue.main.async { [weak controller] in
|
||
MainActor.assumeIsolated { controller?.sendCommand(name, payload: payload) }
|
||
}
|
||
}
|
||
}
|