callExperimentalAPI method

Future<V2TimValueCallback<Object>> callExperimentalAPI({
  1. required String api,
  2. Object? param,
})

Implementation

Future<V2TimValueCallback<Object>> callExperimentalAPI({
  required String api,
  Object? param,
}) async {
  Map<String, dynamic> cJsonParam = {};
  if (param is Map<String, dynamic>) {
    cJsonParam = Map<String, dynamic>.from(param);
  }
  cJsonParam['request_internal_operation'] = api;

  // C 层直接通过返回值传递数据,不走回调
  if (api == 'internal_operation_get_login_account_type') {
    Pointer<Char> pCJsonParam = Tools.string2PointerChar(json.encode(cJsonParam));
    Pointer<Void> pUserData = Tools.string2PointerVoid('');
    int accountType = NativeLibraryManager.bindings.DartCallExperimentalAPI(pCJsonParam, pUserData);
    Tools.freePointers([pCJsonParam, pUserData]);
    return V2TimValueCallback<Object>(code: 0, desc: '', data: accountType);
  }

  // C 层同步操作,不会触发回调,直接返回结果
  if (_syncExperimentalAPIs.contains(api)) {
    Pointer<Char> pCJsonParam = Tools.string2PointerChar(json.encode(cJsonParam));
    Pointer<Void> pUserData = Tools.string2PointerVoid('');
    int result = NativeLibraryManager.bindings.DartCallExperimentalAPI(pCJsonParam, pUserData);
    Tools.freePointers([pCJsonParam, pUserData]);
    if (result != TIMResult.TIM_SUCC.value) {
      return V2TimValueCallback<Object>(code: TIMErrCode.ERR_INVALID_PARAMETERS.value, desc: "invalid parameter");
    }
    return V2TimValueCallback<Object>(code: 0, desc: '');
  }

  // C 层异步操作,通过回调返回结果
  String userData = Tools.generateUserData('callExperimentalAPI');
  Completer<V2TimValueCallback<Object>> completer = Completer();
  NativeLibraryManager.addTimValueCallback2Map<Object>(userData, completer);
  completer.future.whenComplete(() => NativeLibraryManager.removeTimCallbackFromMap(userData));

  Pointer<Char> pCJsonParam = Tools.string2PointerChar(json.encode(cJsonParam));
  Pointer<Void> pUserData = Tools.string2PointerVoid(userData);

  int result = NativeLibraryManager.bindings.DartCallExperimentalAPI(pCJsonParam, pUserData);
  if (result != TIMResult.TIM_SUCC.value) {
    completer.complete(V2TimValueCallback<Object>(
        code: TIMErrCode.ERR_INVALID_PARAMETERS.value, desc: "invalid parameter"));
  }

  // 用 Timer + completer.complete 替代 Future.timeout:
  // - 原 Future.timeout 创建的是新 future,原 completer.future 在超时后依然 pending,
  //   会导致上方手挂的 whenComplete 不触发 → map 中 closure 泄漏,且若 native 5s
  //   后真回调还会触发 .then 的 freePointers 二次释放(与 onTimeout 已 free 的指针冲突)。
  // - 改成 Timer 主动 complete 后,所有路径都汇聚到同一个 completer.future:
  //   whenComplete 必触发一次清理,freePointers 也只会执行一次。
  final Timer timeoutTimer = Timer(const Duration(seconds: 5), () {
    if (!completer.isCompleted) {
      completer.complete(V2TimValueCallback<Object>(
          code: TIMErrCode.ERR_INVALID_PARAMETERS.value,
          desc: "callExperimentalAPI timeout, api: $api"));
    }
  });

  return completer.future.then((value) {
    timeoutTimer.cancel();
    Tools.freePointers([pCJsonParam, pUserData]);
    return value;
  });
}