Skip to content

XHIM 离线只读与请求取消

离线只读

xhim::storage::OfflineReader 使用独立的 SQLITE_OPEN_READONLY | SQLITE_OPEN_FULLMUTEX 连接,并强制 query_only=ONtrusted_schema=OFF。它只接受当前 Schema v15,绝不建表、 迁移、登录、启动网络或伪造 Ready;打开时还会验证数据库绑定的 account_id。 旧版或新版 Schema 都会拒绝打开,应用必须先让相同版本的在线 SDK 完成升级, 而不是让通知扩展或离线搜索进程迁移数据库。

稳定 C ABI 使用独立的 xhim_v1_offline_reader_t 句柄,不依赖在线 xhim_v1_client_t

c
xhim_v1_offline_reader_config_t config = {0};
config.struct_size = sizeof(config);
config.abi_version = XHIM_V1_ABI_VERSION;
config.database_path = database_path;
config.account_id = canonical_account_id;
config.database_key = key_from_platform_secure_storage;
config.require_database_encryption = 1;

xhim_v1_offline_reader_t *reader = NULL;
int32_t status = xhim_v1_offline_reader_create(&config, &reader);

创建时会同步复制密钥,并在打开结束后清除 Core 内部副本;调用方仍须在自己的 安全内存策略下清理 database_key。密钥存在时长度必须为 32–64 字节; require_database_encryption=1 时密钥不能为空。生产包必须让离线 Reader 和 在线 Client 使用同一个 Keychain/Keystore/DPAPI/HUKS 密钥提供器,禁止把密钥 写进配置文件、日志或业务数据库。

查询 API 包括:

  • list_messagessearch_messageslist_conversations
  • list_friend_requestslist_friendshipslist_blocks
  • list_groupslist_group_memberslist_group_join_requests

list_friendships 保持原有 friendship 数组步长。在线或离线返回该 kind 的 xhim_v1_social_page_t 后,调用 xhim_v1_social_page_get_friendship_remarks(page, &remarks, &count) 可取得 等长的备注平行数组;count == page->item_count,同一 index 的 peer_user_id 必须一致。空备注配合非零 revision 表示已经显式清空;inactive 关系不会出现在活动好友页。返回数组与 page 共用相同借用生命周期,必须和基础 friendship 一起深拷贝,不能在下一次 Reader/Client 查询后继续持有。

消息检索可以按会话、发送者和内容类型过滤,只访问 fallback_text,不会触发 网络。分页 Cursor 是 SDK 生成的不透明二进制值,调用方只能原样保存和回传, 不得解析或跨查询类型复用。limit=0 使用默认 50,显式上限为 200;非法 Cursor、超限、空必填 ID 或账号不匹配会返回稳定错误码。

所有离线查询都是同步磁盘 I/O,不产生 Callback 或 request_id。页面、数组和 嵌套字节视图都由 Reader 借用,只在“同一句柄的下一次 API 调用或 destroy,以先发生者为准”之前有效;平台层必须在返回业务线程前深拷贝。 同一句柄必须由调用方串行使用,重入或并发查询返回 XHIM_V1_STATUS_INVALID_STATE,且失败调用同样会让上一批借用视图失效。 destroy 也必须与查询外部串行,不能用它中断正在执行的 SQLite 调用。

平台 Facade 应把 Reader 放到后台 I/O Executor。在线写连接仍存活时允许使用 另一个离线 Reader 并发读,但调用方必须接受 WAL 快照语义;不要在 UI 线程 共享或阻塞等待同一个 Reader。

通用逐请求取消

每个稳定 C ABI 异步调用在受理后返回非零 request_id。调用 xhim_v1_client_cancel_request(client, request_id) 后:

  • 若原 Completion 尚未派发,原回调恰好一次收到 XHIM_V1_STATUS_CANCELLED / request_cancelled
  • 已经完成、已经派发或不存在的 ID 返回 INVALID_STATE/NOT_FOUND
  • 取消是 Completion 级协作取消,不回滚已经提交的 SQLite 事务、服务端写入或 sendMessage 已生成的 Outbox;
  • 登出/换号仍由账号 Epoch 撤销,不能用逐请求取消代替生命周期收敛。

Swift Task.cancel()、Kotlin 协程取消和 .NET CancellationToken 都调用该 接口。Harmony Promise 在提交时带 requestId 属性,Facade 的可选 XHIMRequestObserver 会立即返回它,再用 cancelRequest() 取消。 xhim_v1_client_set_friend_remark() 也遵循这一合同:取消或账号 Epoch/连接 generation 失效后只完成一次,晚到回包不得覆盖当前好友备注投影。

XHIM 客户端 SDK 与服务端文档