* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm>
#include "taihe/runtime.hpp"
#include "ani_error_utils.h"
#include "dm_error_type.h"
namespace ani_errorutils {
using namespace OHOS::DistributedHardware;
constexpr char CLASS_NAME_BUSINESSERROR[] = "@ohos.base.BusinessError";
const std::string ERR_MESSAGE_NO_PERMISSION = "Permission verify failed.";
const std::string ERR_MESSAGE_NOT_SYSTEM_APP = "The caller is not a system application.";
const std::string ERR_MESSAGE_INVALID_PARAMS = "Input parameter error.";
const std::string ERR_MESSAGE_FAILED = "Failed to execute the function.";
const std::string ERR_MESSAGE_OBTAIN_SERVICE = "Failed to obtain the service.";
const std::string ERR_MESSAGE_AUTHENTICATION_INVALID = "Authentication invalid.";
const std::string ERR_MESSAGE_DISCOVERY_INVALID = "Discovery invalid.";
const std::string ERR_MESSAGE_PUBLISH_INVALID = "Publish invalid.";
const std::string ERR_MESSAGE_FROM_CLOUD_FAILED = "Get data from cloud failed.";
const std::string ERR_MESSAGE_NEED_LOGIN = "A login account is required.";
const std::string ERR_MESSAGE_SCAS_CHECK_FAILED = "The device name contains non-compliant content.";
const std::string ERR_MESSAGE_INVALID_NETWORK_ID = "Invalid network ID.";
void ThrowError(const char* message)
{
if (message == nullptr) {
return;
}
std::string errMsg(message);
taihe::set_error(errMsg);
}
void ThrowError(int32_t code, const char* message)
{
if (message == nullptr) {
return;
}
std::string errMsg(message);
taihe::set_business_error(code, errMsg);
}
ani_object ToBusinessError(ani_env *env, int32_t code, const std::string &message)
{
if (env == nullptr) {
return {};
}
ani_class cls {};
CHECK_AND_RETURN_RET_LOG(env->FindClass(CLASS_NAME_BUSINESSERROR, &cls) == ANI_OK, nullptr,
"find class %{public}s failed", CLASS_NAME_BUSINESSERROR);
ani_method ctor {};
CHECK_AND_RETURN_RET_LOG(env->Class_FindMethod(cls, "<ctor>", ":", &ctor) == ANI_OK, nullptr,
"find method BusinessError constructor failed");
ani_object error {};
CHECK_AND_RETURN_RET_LOG(env->Object_New(cls, ctor, &error) == ANI_OK, nullptr,
"new object %{public}s failed", CLASS_NAME_BUSINESSERROR);
CHECK_AND_RETURN_RET_LOG(
env->Object_SetPropertyByName_Int(error, "code", static_cast<ani_int>(code)) == ANI_OK, nullptr,
"set property BusinessError.code failed");
if (message.size() > 0) {
ani_string messageRef {};
CHECK_AND_RETURN_RET_LOG(env->String_NewUTF8(message.c_str(), message.size(), &messageRef) == ANI_OK, nullptr,
"new message string failed");
CHECK_AND_RETURN_RET_LOG(
env->Object_SetPropertyByName_Ref(error, "message", static_cast<ani_ref>(messageRef)) == ANI_OK, nullptr,
"set property BusinessError.message failed");
}
return error;
}
ani_object CreateErrorForCall(ani_env* env, int32_t code, const std::string &errMsg, bool isAsync)
{
LOGI("code:%{public}d, message:%{public}s", code, errMsg.c_str());
ani_object error = nullptr;
if (isAsync) {
ThrowError(code, errMsg.c_str());
} else {
error = ToBusinessError(env, code, errMsg);
}
return error;
}
ani_object CreateBusinessError(int32_t errCode, bool isAsync)
{
ani_env *env = taihe::get_env();
ani_object error = nullptr;
switch (errCode) {
case ERR_DM_NO_PERMISSION:
error = CreateErrorForCall(env, ERR_NO_PERMISSION, ERR_MESSAGE_NO_PERMISSION, isAsync);
break;
case ERR_DM_DISCOVERY_REPEATED:
error = CreateErrorForCall(env, DM_ERR_DISCOVERY_INVALID, ERR_MESSAGE_DISCOVERY_INVALID, isAsync);
break;
case ERR_DM_PUBLISH_REPEATED:
error = CreateErrorForCall(env, DM_ERR_PUBLISH_INVALID, ERR_MESSAGE_PUBLISH_INVALID, isAsync);
break;
case ERR_DM_AUTH_BUSINESS_BUSY:
error = CreateErrorForCall(env, DM_ERR_AUTHENTICATION_INVALID,
ERR_MESSAGE_AUTHENTICATION_INVALID, isAsync);
break;
case ERR_DM_INPUT_PARA_INVALID:
case ERR_DM_UNSUPPORTED_AUTH_TYPE:
case ERR_DM_CALLBACK_REGISTER_FAILED:
error = CreateErrorForCall(env, ERR_INVALID_PARAMS, ERR_MESSAGE_INVALID_PARAMS, isAsync);
break;
case ERR_DM_INIT_FAILED:
error = CreateErrorForCall(env, DM_ERR_OBTAIN_SERVICE, ERR_MESSAGE_OBTAIN_SERVICE, isAsync);
break;
case ERR_DM_GET_OSTYPE_FAILED:
error = CreateErrorForCall(env, DM_ERR_INVALID_NETWORK_ID, ERR_MESSAGE_INVALID_NETWORK_ID, isAsync);
break;
case ERR_NOT_SYSTEM_APP:
error = CreateErrorForCall(env, ERR_NOT_SYSTEM_APP, ERR_MESSAGE_NOT_SYSTEM_APP, isAsync);
break;
case ERR_DM_HILINKSVC_RSP_PARSE_FAILD:
case ERR_DM_HILINKSVC_REPLY_FAILED:
case ERR_DM_HILINKSVC_ICON_URL_EMPTY:
case ERR_DM_HILINKSVC_DISCONNECT:
error = CreateErrorForCall(env, DM_ERR_FROM_CLOUD_FAILED, ERR_MESSAGE_FROM_CLOUD_FAILED, isAsync);
break;
case ERR_DM_WISE_NEED_LOGIN:
error = CreateErrorForCall(env, DM_ERR_NEED_LOGIN, ERR_MESSAGE_NEED_LOGIN, isAsync);
break;
case ERR_DM_HILINKSVC_SCAS_CHECK_FAILED:
error = CreateErrorForCall(env, DM_ERR_SCAS_CHECK_FAILED, ERR_MESSAGE_SCAS_CHECK_FAILED, isAsync);
break;
default:
error = CreateErrorForCall(env, DM_ERR_FAILED, ERR_MESSAGE_FAILED, isAsync);
break;
}
return error;
}
bool AniPromiseCallback(ani_env* env, ani_resolver deferred, int32_t result, ani_ref resolveResult)
{
ani_status status = ANI_OK;
if (result != DM_OK) {
ani_ref errobj = static_cast<ani_error>(CreateBusinessError(result, false));
if (errobj == nullptr) {
LOGE("ToBusinessError return null");
if ((status = env->GetUndefined(&errobj)) != ANI_OK) {
LOGE("GetUndefined failed");
return false;
}
}
if ((status = env->PromiseResolver_Reject(deferred, static_cast<ani_error>(errobj))) != ANI_OK) {
LOGE("PromiseResolver_Reject failed, status = %{public}d", status);
return false;
}
return true;
}
ani_ref promiseResult = resolveResult;
if (promiseResult == nullptr) {
if ((status = env->GetUndefined(&promiseResult)) != ANI_OK) {
LOGE("get undefined value failed, status = %{public}d", status);
return false;
}
}
if ((status = env->PromiseResolver_Resolve(deferred, promiseResult)) != ANI_OK) {
LOGE("PromiseResolver_Resolve failed, status = %{public}d", status);
return false;
}
return true;
}
}