1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ringtone_restore_napi.h"
17 
18 #include "application_context.h"
19 #include "js_native_api.h"
20 #include "ringtone_db_const.h"
21 #include "ringtone_errno.h"
22 #include "ringtone_log.h"
23 #include "ringtone_restore_factory.h"
24 #include "ringtone_restore_type.h"
25 
26 #define MLOG_TAG "Common"
27 
28 namespace OHOS {
29 namespace Media {
30 using namespace std;
31 
32 using RestoreBlock = struct {
33     napi_env env;
34     int32_t sceneCode;
35     std::string baseBackupPath;
36     int32_t resultSet;
37     napi_deferred nativeDeferred;
38 };
39 
Init(napi_env env,napi_value exports)40 napi_value RingtoneRestoreNapi::Init(napi_env env, napi_value exports)
41 {
42     RINGTONE_INFO_LOG("Init");
43     napi_property_descriptor ringtone_restore_properties[] = {
44         DECLARE_NAPI_FUNCTION("startRestore", JSStartRestore)
45     };
46 
47     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(ringtone_restore_properties) /
48         sizeof(ringtone_restore_properties[0]), ringtone_restore_properties));
49     return exports;
50 }
51 
GetIntFromParams(napi_env env,const napi_value args[],size_t index)52 static int32_t GetIntFromParams(napi_env env, const napi_value args[], size_t index)
53 {
54     int32_t result = -1;
55     napi_valuetype valueType = napi_undefined;
56     if (napi_typeof(env, args[index], &valueType) != napi_ok || valueType != napi_number) {
57         // NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
58         RINGTONE_ERR_LOG("GetIntFromParams invalid parameter");
59         return result;
60     }
61     napi_get_value_int32(env, args[index], &result);
62     return result;
63 }
64 
GetStringFromParams(napi_env env,const napi_value args[],size_t index)65 static std::string GetStringFromParams(napi_env env, const napi_value args[], size_t index)
66 {
67     napi_valuetype valueType = napi_undefined;
68     if (napi_typeof(env, args[index], &valueType) != napi_ok || valueType != napi_string) {
69         // NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
70         return "";
71     }
72 
73     size_t resultLength;
74     napi_get_value_string_utf8(env, args[index], nullptr, 0, &resultLength);
75     std::string result(resultLength, '\0');
76     napi_get_value_string_utf8(env, args[index], &result[0], resultLength + 1, &resultLength);
77     return result;
78 }
79 
CheckPermission(void)80 static int32_t CheckPermission(void)
81 {
82     auto context = AbilityRuntime::Context::GetApplicationContext();
83     if (context == nullptr) {
84         RINGTONE_ERR_LOG("CheckPermission context nullptr");
85         return E_FAIL;
86     }
87     std::string bundleName = context->GetBundleName();
88     if (bundleName.compare(RINGTONE_BUNDLE_NAME) != 0) {
89         RINGTONE_ERR_LOG("bundle name is invalid: %{public}s", bundleName.c_str());
90         return E_FAIL;
91     }
92     RINGTONE_INFO_LOG("CheckPermission success");
93     return E_OK;
94 }
95 
RingtoneRestore(std::unique_ptr<RestoreInterface> & restore,string backupPath)96 static int32_t RingtoneRestore(std::unique_ptr<RestoreInterface> &restore, string backupPath)
97 {
98     int32_t ret = E_OK;
99     if ((restore != nullptr) && (restore->Init(backupPath)) == Media::E_OK) {
100         RINGTONE_INFO_LOG("start restore....");
101         ret = restore->StartRestore();
102         RINGTONE_INFO_LOG("restore finished");
103     } else {
104         RINGTONE_ERR_LOG("ringtone-restore failed on init");
105         ret = E_HAS_DB_ERROR;
106     }
107 
108     return ret;
109 }
110 
UvQueueWork(uv_loop_s * loop,uv_work_t * work)111 void RingtoneRestoreNapi::UvQueueWork(uv_loop_s *loop, uv_work_t *work)
112 {
113     if (loop == nullptr) {
114         RINGTONE_ERR_LOG("Failed to uv_loop");
115         return;
116     }
117     if (work == nullptr || work->data == nullptr) {
118         RINGTONE_ERR_LOG("Failed to uv_work");
119         return;
120     }
121     uv_queue_work(loop, work, [](uv_work_t *work) {
122         RestoreBlock *block = reinterpret_cast<RestoreBlock *> (work->data);
123         if (block == nullptr) {
124             RINGTONE_ERR_LOG("Failed to new block");
125             return;
126         }
127         auto restore = RingtoneRestoreFactory::CreateObj(RestoreSceneType(block->sceneCode));
128         if (restore == nullptr) {
129             RINGTONE_ERR_LOG("Failed to new restore");
130             block->resultSet = E_FAIL;
131             return;
132         }
133         block->resultSet = RingtoneRestore(restore, block->baseBackupPath);
134     }, [](uv_work_t *work, int _status) {
135         RestoreBlock *block = reinterpret_cast<RestoreBlock *> (work->data);
136         if (block == nullptr) {
137             RINGTONE_ERR_LOG("Failed to new block");
138             delete work;
139             return;
140         }
141         napi_handle_scope scope = nullptr;
142         napi_open_handle_scope(block->env, &scope);
143         if (scope == nullptr) {
144             RINGTONE_ERR_LOG("Failed to new scope");
145             delete block;
146             delete work;
147             return;
148         }
149         napi_value restoreExResult = nullptr;
150         RINGTONE_INFO_LOG("resultSet, %{public}d", block->resultSet);
151         napi_create_int32(block->env, block->resultSet, &restoreExResult);
152         napi_resolve_deferred(block->env, block->nativeDeferred, restoreExResult);
153         napi_close_handle_scope(block->env, scope);
154         delete block;
155         delete work;
156     });
157 }
158 
JSStartRestore(napi_env env,napi_callback_info info)159 napi_value RingtoneRestoreNapi::JSStartRestore(napi_env env, napi_callback_info info)
160 {
161     napi_value result = nullptr;
162     RINGTONE_INFO_LOG("JSStartRestore start");
163     napi_get_undefined(env, &result);
164     if (CheckPermission() != E_OK) {
165         RINGTONE_ERR_LOG("check permission failed");
166         return result;
167     }
168 
169     size_t argc = 2;
170     napi_value argv[2] = {0};
171     napi_value thisVar = nullptr;
172 
173     void *data;
174     const int32_t param = 2;
175     napi_get_cb_info(env, info, &(argc), argv, &(thisVar), &(data));
176     if (argc != param) {
177         RINGTONE_ERR_LOG("require 2 parameters");
178         return result;
179     }
180     napi_get_undefined(env, &result);
181     int32_t sceneCode = GetIntFromParams(env, argv, 0);
182     std::string baseBackupPath = GetStringFromParams(env, argv, 1);
183     RINGTONE_INFO_LOG("sceneCode: %{public}d, backupPath: %{private}s", sceneCode, baseBackupPath.c_str());
184 
185     uv_loop_s *loop = nullptr;
186     napi_get_uv_event_loop(env, &loop);
187     if (loop == nullptr) {
188         RINGTONE_ERR_LOG("Failed to new uv_loop");
189         return result;
190     }
191     uv_work_t *work = new (std::nothrow) uv_work_t;
192     if (work == nullptr) {
193         RINGTONE_ERR_LOG("Failed to new uv_work");
194         return result;
195     }
196     int32_t resultSet = E_OK;
197     napi_deferred nativeDeferred = nullptr;
198     napi_create_promise(env, &nativeDeferred, &result);
199     RestoreBlock *block = new (std::nothrow) RestoreBlock {
200         env, sceneCode, baseBackupPath, resultSet, nativeDeferred };
201     if (block == nullptr) {
202         RINGTONE_ERR_LOG("Failed to new block");
203         delete work;
204         return result;
205     }
206     work->data = reinterpret_cast<void *>(block);
207     UvQueueWork(loop, work);
208     RINGTONE_INFO_LOG("JSStartRestore end");
209     return result;
210 }
211 } // namespace Media
212 } // namespace OHOS