/** * miniapp 运行时配置(channel_id/token 占位,由用户在设置页或 build env 填) * * 这些值在真实部署前是占位: * - RELAY_HOST:ws/wss 地址,需替换为实际部署的 u-relay 地址 * - CHANNEL_ID:u-relay 配对通道 ID(与桌面端 df-tunnel 共享同键) * - TOKEN:对齐 u-relay 的 U_RELAY_TOKEN(生产建议 per-channel 独立 token,Phase3) */ export interface MiniappConfig { /** relay WS 地址(含协议),如 'ws://192.168.1.100:9180/ws/commander' 或 'wss://relay.example.com/ws/commander' */ relayHost: string /** 配对绑定的通道 ID(u-relay channel_id,与桌面端共享同键配对) */ channelId: string /** 配对 token(对齐 u-relay U_RELAY_TOKEN) */ token: string /** 心跳间隔(ms) */ heartbeatInterval: number /** 重连初始间隔(ms,指数退避) */ reconnectBaseDelay: number /** 重连最大间隔(ms) */ reconnectMaxDelay: number /** file.1216.top 文件服务上传地址(不带路径,上传时拼 /upload) */ fileUploadBaseUrl: string /** 上传 X-Source 头(项目隔离,文件存到 file.1216.top 对应目录) */ fileUploadSource: string } /** * 默认配置(占位值,需替换) * * 真实部署:用户在设置页填 relayHost/channelId/token,或通过 build-time env 注入。 * MVP 阶段留占位让类型自洽,实际连接会失败(token 校验不通过 → relay 关连接, * 这符合预期,提示用户配置)。 */ export const defaultConfig: MiniappConfig = { // u-relay 现行协议 commander 端点:wss://u-work.1216.top → nginx 终止 TLS → u-relay :9180 明文 ws // 微信小程序真机要求 wss + socket 合法域名白名单(微信公众平台→开发设置→服务器域名) relayHost: 'wss://u-work.1216.top/ws/commander', // 配对桌面端 channel_id(查桌面端 KV app_settings:channel_id;填错则握手过但路由无对端) // 当前填本机桌面端 channel_id(联调期硬编码,后续做配对绑定流程) channelId: '1b92cbbd-d03e-4a0c-b226-9fadf8dcf0f0', token: 'devflow-relay-default-token', heartbeatInterval: 30000, reconnectBaseDelay: 1000, reconnectMaxDelay: 30000, fileUploadBaseUrl: 'https://file.1216.top', fileUploadSource: 'devflow', } /** storage key(持久化完整 MiniappConfig JSON) */ const STORAGE_KEY = 'df-miniapp-config' /** 单例配置(null 表示尚未从 storage 加载) */ let _config: MiniappConfig | null = null /** * 旧版字段迁移(df-relay 一代 → u-relay): * storage 里的旧 JSON 含 deviceId 字段,映射为 channelId,避免老用户升级后配置丢失。 */ function migrateLegacyFields(parsed: Record): Partial { const out = { ...parsed } as Record if (out.deviceId !== undefined && out.channelId === undefined) { out.channelId = out.deviceId } delete out.deviceId // 旧 relayHost 指向已下线的 /ws/miniapp 端点,升级后强制重置为新端点 if (typeof out.relayHost === 'string' && out.relayHost.includes('/ws/miniapp')) { out.relayHost = defaultConfig.relayHost } return out as Partial } /** * 从 storage 读取并合并默认配置 * * uni.getStorageSync(key) 未命中时返回 ''(空字符串),命中返回原写入值。 * 容错:读取/解析失败仅 warn,不抛出,回落到 defaultConfig。 */ function loadFromStorage(): MiniappConfig { try { const raw = uni.getStorageSync(STORAGE_KEY) if (!raw) return { ...defaultConfig } const parsed = JSON.parse(raw) as Record // 合并默认值 + 旧字段迁移,避免旧版本字段缺失/更名导致 undefined const migrated = migrateLegacyFields(parsed) return { ...defaultConfig, ...migrated } } catch (e) { console.warn('[df-miniapp] load config from storage failed:', e) return { ...defaultConfig } } } /** * 同步写入 storage(JSON 序列化完整配置) * * 容错:写入失败仅 warn,不影响内存配置。 */ function saveToStorage(config: MiniappConfig): void { try { uni.setStorageSync(STORAGE_KEY, JSON.stringify(config)) } catch (e) { console.warn('[df-miniapp] save config to storage failed:', e) } } export function getConfig(): MiniappConfig { // 首次调用时从 storage 加载并缓存 if (_config === null) { _config = loadFromStorage() } return _config } export function setConfig(patch: Partial): void { // 确保已加载(避免在 getConfig 前调用 setConfig 丢失 storage 旧值) if (_config === null) { _config = loadFromStorage() } _config = { ..._config, ...patch } saveToStorage(_config) } /** * 重置为默认配置并清除 storage 持久化数据 * * 用于用户重新配对或恢复出厂占位值的场景。 */ export function resetConfig(): void { _config = { ...defaultConfig } try { uni.removeStorageSync(STORAGE_KEY) } catch (e) { console.warn('[df-miniapp] remove config from storage failed:', e) } }