• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define LOG_TAG "CollaborationEditObject"
16 
17 #include <future>
18 
19 #include "napi_collaboration_edit_object.h"
20 
21 #include "db_store_config.h"
22 #include "db_store_manager.h"
23 #include "napi_edit_unit.h"
24 #include "napi_error_utils.h"
25 #include "napi_parser.h"
26 #include "napi_sync_service.h"
27 #include "napi/native_node_api.h"
28 
29 namespace OHOS::CollaborationEdit {
30 static constexpr const uint8_t BATCH_INSERT_FUNC_INDEX = 0;
31 static constexpr const uint8_t QUERY_FUNC_INDEX = 1;
32 static constexpr const uint8_t DOWNLOAD_ASSET_FUNC_INDEX = 2;
33 static constexpr const uint8_t UPLOAD_ASSET_FUNC_INDEX = 3;
34 static constexpr const uint8_t DELETE_ASSET_FUNC_INDEX = 4;
35 static constexpr const uint8_t DELETE_LOCAL_ASSET_FUNC_INDEX = 5;
36 
37 static constexpr const uint8_t CLOUD_SYNC_PARAM_NUMBER = 2;
38 static const std::map<SyncMode, GRD_SyncModeE> SYNC_MODE_MAP = {
39     {SyncMode::PUSH, GRD_SYNC_MODE_UPLOAD},
40     {SyncMode::PULL, GRD_SYNC_MODE_DOWNLOAD_LOG},
41     {SyncMode::PULL_PUSH, GRD_SYNC_MODE_UP_DOWN_LOG}
42 };
43 
CollaborationEditObject(std::string docName,ContextParam param)44 CollaborationEditObject::CollaborationEditObject(std::string docName, ContextParam param)
45     : docName_(docName), param_(std::make_shared<ContextParam>(std::move(param)))
46 {}
47 
~CollaborationEditObject()48 CollaborationEditObject::~CollaborationEditObject()
49 {}
50 
Initialize(napi_env env,napi_callback_info info)51 napi_value CollaborationEditObject::Initialize(napi_env env, napi_callback_info info)
52 {
53     size_t argc = 2;
54     napi_value argv[2] = {nullptr};
55     napi_value self = nullptr;
56     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
57     ContextParam context;
58     napi_status status = NapiUtils::GetValue(env, argv[0], context);
59     ASSERT_THROW_BASE(env, status == napi_ok, Status::INVALID_ARGUMENT, "read context param go wrong", self);
60     std::string docName;
61     status = NapiUtils::GetNamedProperty(env, argv[1], "name", docName);
62     ASSERT_THROW_BASE(env, status == napi_ok, Status::INVALID_ARGUMENT, "read docName param go wrong", self);
63     ASSERT_THROW_BASE(env, !docName.empty(), Status::INVALID_ARGUMENT, "Param Error: invalid name", self);
64     std::string dbFilePath = context.baseDir + "/" + docName;
65     DBStoreConfig config(dbFilePath, docName);
66     std::shared_ptr<DBStore> dbStore = DBStoreManager::GetInstance().GetDBStore(config);
67     if (dbStore == nullptr) {
68         ThrowNapiError(env, Status::INTERNAL_ERROR, "open doc go wrong");
69         return self;
70     }
71 
72     CollaborationEditObject *editObject = new (std::nothrow) CollaborationEditObject(docName, context);
73     ASSERT_THROW_BASE(env, editObject != nullptr, Status::INTERNAL_ERROR, "Initialize: new editObject go wrong", self);
74     editObject->SetDBStore(dbStore);
75     auto finalize = [](napi_env env, void *data, void *hint) {
76         CollaborationEditObject *editObject = reinterpret_cast<CollaborationEditObject *>(data);
77         delete editObject;
78     };
79     status = napi_wrap(env, self, editObject, finalize, nullptr, nullptr);
80     if (status != napi_ok) {
81         LOG_ERROR("napi_wrap failed. code:%{public}d", status);
82         delete editObject;
83         return nullptr;
84     }
85     return self;
86 }
87 
Constructor(napi_env env)88 napi_value CollaborationEditObject::Constructor(napi_env env)
89 {
90     auto lambda = []() -> std::vector<napi_property_descriptor> {
91         std::vector<napi_property_descriptor> properties = {
92             DECLARE_NAPI_FUNCTION("getEditUnit", GetEditUnit),
93             DECLARE_NAPI_FUNCTION("getUndoRedoManager", GetUndoRedoManager),
94             DECLARE_NAPI_FUNCTION("deleteUndoRedoManager", DeleteUndoRedoManager),
95             DECLARE_NAPI_FUNCTION("getName", GetName),
96             DECLARE_NAPI_FUNCTION("cloudSync", CloudSync),
97             DECLARE_NAPI_FUNCTION("setCloudDB", SetCloudDb),
98             DECLARE_NAPI_FUNCTION("getLocalId", GetLocalId),
99             DECLARE_NAPI_FUNCTION("applyUpdate", ApplyUpdate),
100             DECLARE_NAPI_FUNCTION("writeUpdate", WriteUpdate),
101         };
102         return properties;
103     };
104     return NapiUtils::DefineClass(
105         env, "ohos.data.collaborationEditObject", "CollaborationEditObject", lambda, Initialize);
106 }
107 
NewInstance(napi_env env,napi_callback_info info)108 napi_value CollaborationEditObject::NewInstance(napi_env env, napi_callback_info info)
109 {
110     size_t argc = 2;
111     napi_value argv[2] = {nullptr};
112     napi_value editObject = nullptr;
113     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
114 
115     napi_status status = napi_new_instance(env, Constructor(env), argc, argv, &editObject);
116     if (editObject == nullptr || status != napi_ok) {
117         LOG_ERROR("[NewInstance] new instance go wrong");
118     }
119     return editObject;
120 }
121 
GetEditUnit(napi_env env,napi_callback_info info)122 napi_value CollaborationEditObject::GetEditUnit(napi_env env, napi_callback_info info)
123 {
124     size_t argc = 1;
125     napi_value argv[1] = {nullptr};
126     napi_value self = nullptr;
127     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
128     CollaborationEditObject *editObject = nullptr;
129     NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast<void **>(&editObject)));
130     napi_value napiEditUnit = EditUnit::NewInstance(env, info, self);
131     EditUnit *editUnit = nullptr;
132     napi_status status = napi_unwrap(env, napiEditUnit, reinterpret_cast<void **>(&editUnit));
133     if (status != napi_ok || editUnit == nullptr) {
134         LOG_ERROR("unwrap EditUnit go wrong, status = %{public}d", status);
135         return nullptr;
136     }
137     editUnit->SetDBStore(editObject->GetDBStore());
138     return napiEditUnit;
139 }
140 
GetUndoRedoManager(napi_env env,napi_callback_info info)141 napi_value CollaborationEditObject::GetUndoRedoManager(napi_env env, napi_callback_info info)
142 {
143     size_t argc = 2;
144     napi_value argv[2] = {nullptr};
145     napi_value self = nullptr;
146     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
147     CollaborationEditObject *editObject = nullptr;
148     NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast<void **>(&editObject)));
149     napi_value jsUndoManager = UndoManager::NewInstance(env, info);
150     UndoManager *undoManager = nullptr;
151     napi_status status = napi_unwrap(env, jsUndoManager, reinterpret_cast<void **>(&undoManager));
152     if (status != napi_ok || undoManager == nullptr) {
153         LOG_ERROR("unwrap UndoManager go wrong, status = %{public}d", status);
154         return nullptr;
155     }
156     undoManager->SetDBStore(editObject->GetDBStore());
157     int32_t retCode = undoManager->GetAdapter()->CreateUndoManager(undoManager->GetCaptureTimeout());
158     ASSERT_THROW(env, retCode == SUCCESS, retCode, "create undo manager go wrong.");
159     return jsUndoManager;
160 }
161 
DeleteUndoRedoManager(napi_env env,napi_callback_info info)162 napi_value CollaborationEditObject::DeleteUndoRedoManager(napi_env env, napi_callback_info info)
163 {
164     size_t argc = 1;
165     napi_value argv[1] = {nullptr};
166     napi_value self = nullptr;
167     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
168     CollaborationEditObject *editObject = nullptr;
169     NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast<void **>(&editObject)));
170     std::string editUnitName;
171     napi_status status = NapiUtils::GetValue(env, argv[0], editUnitName);
172     ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "read editUnitName go wrong");
173     std::shared_ptr<RdAdapter> adapter = std::make_shared<RdAdapter>();
174     std::string tableName = std::to_string(LABEL_FRAGMENT) + "_" + editUnitName;
175     adapter->SetTableName(tableName);
176     adapter->SetDBStore(editObject->GetDBStore());
177     int32_t retCode = adapter->CloseUndoManager();
178     ASSERT_THROW(env, retCode == SUCCESS, retCode, "close undo manager go wrong.");
179     LOG_INFO("Close undo manager successfully.");
180     return nullptr;
181 }
182 
GetName(napi_env env,napi_callback_info info)183 napi_value CollaborationEditObject::GetName(napi_env env, napi_callback_info info)
184 {
185     napi_value self = nullptr;
186     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr));
187     CollaborationEditObject *editObject = nullptr;
188     napi_status status = napi_unwrap(env, self, reinterpret_cast<void **>(&editObject));
189     if (status != napi_ok) {
190         ThrowNapiError(env, status, "unwrap object go wrong");
191         return nullptr;
192     }
193     napi_value result;
194     NapiUtils::SetValue(env, editObject->docName_, result);
195     return result;
196 }
197 
SetCloudDb(napi_env env,napi_callback_info info)198 napi_value CollaborationEditObject::SetCloudDb(napi_env env, napi_callback_info info)
199 {
200     size_t argc = 1;
201     napi_value argv[1] = {nullptr};
202     napi_value self = nullptr;
203     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
204 
205     CollaborationEditObject *editObject = nullptr;
206     napi_status status = napi_unwrap(env, self, reinterpret_cast<void **>(&editObject));
207     if (status != napi_ok) {
208         ThrowNapiError(env, Status::INTERNAL_ERROR, "unwrap editObject go wrong.");
209         return nullptr;
210     }
211     std::shared_ptr<DBStore> dbStore = editObject->GetDBStore();
212     if (dbStore == nullptr) {
213         ThrowNapiError(env, Status::INVALID_ARGUMENT, "dbStore is null.");
214         return nullptr;
215     }
216     if (dbStore->GetCloudDB() != nullptr) {
217         LOG_INFO("cloudDB already set");
218         return nullptr;
219     }
220 
221     std::vector<napi_value> cloudDbFunc;
222     int ret = Parser::ParseCloudDbFields(env, argv[0], cloudDbFunc);
223     if (ret != OK) {
224         ThrowNapiError(env, Status::INVALID_ARGUMENT, "parse cloudDb fields go wrong.");
225         return nullptr;
226     }
227     NapiCloudDb *napiCloudDb = new (std::nothrow) NapiCloudDb();
228     ASSERT_THROW(env, napiCloudDb != nullptr, Status::INTERNAL_ERROR, "new cloud db instance go wrong.");
229     status = CollaborationEditObject::CreateHandlerFunc(env, cloudDbFunc, napiCloudDb);
230     if (status != napi_ok) {
231         delete napiCloudDb;
232         ThrowNapiError(env, Status::INTERNAL_ERROR, "create handler func go wrong.");
233         return nullptr;
234     }
235 
236     ret = DBStoreManager::GetInstance().SetCloudDb(dbStore, napiCloudDb);
237     if (ret != 0) {
238         delete napiCloudDb;
239         ThrowNapiError(env, ret, "set cloud db go wrong.");
240     }
241     return nullptr;
242 }
243 
CreateHandlerFunc(napi_env env,std::vector<napi_value> & cloudDbFunc,NapiCloudDb * napiCloudDb)244 napi_status CollaborationEditObject::CreateHandlerFunc(napi_env env, std::vector<napi_value> &cloudDbFunc,
245     NapiCloudDb *napiCloudDb)
246 {
247     napi_value name = nullptr;
248     napi_status status = napi_create_string_utf8(env, "batchInsert", NAPI_AUTO_LENGTH, &name);
249     ASSERT(status == napi_ok, "create batchInsert string wrong", status);
250     status = napi_create_threadsafe_function(env, cloudDbFunc[BATCH_INSERT_FUNC_INDEX], nullptr, name, 0, 1,
251         nullptr, nullptr, nullptr, NapiCloudDb::BatchInsertInner, &napiCloudDb->batchInsertInnerFunc_);
252     ASSERT(status == napi_ok, "create batchInsert func wrong", status);
253 
254     name = nullptr;
255     status = napi_create_string_utf8(env, "query", NAPI_AUTO_LENGTH, &name);
256     ASSERT(status == napi_ok, "create query string wrong", status);
257     status = napi_create_threadsafe_function(env, cloudDbFunc[QUERY_FUNC_INDEX], nullptr, name, 0, 1,
258         nullptr, nullptr, nullptr, NapiCloudDb::QueryInner, &napiCloudDb->queryInnerFunc_);
259     ASSERT(status == napi_ok, "create query func wrong", status);
260 
261     name = nullptr;
262     status = napi_create_string_utf8(env, "downloadAsset", NAPI_AUTO_LENGTH, &name);
263     ASSERT(status == napi_ok, "create downloadAsset string wrong", status);
264     status = napi_create_threadsafe_function(env, cloudDbFunc[DOWNLOAD_ASSET_FUNC_INDEX], nullptr, name, 0, 1,
265         nullptr, nullptr, nullptr, NapiCloudDb::DownloadAssetInner, &napiCloudDb->downloadAssetInnerFunc_);
266     ASSERT(status == napi_ok, "create downloadAsset func wrong", status);
267 
268     name = nullptr;
269     status = napi_create_string_utf8(env, "uploadAsset", NAPI_AUTO_LENGTH, &name);
270     ASSERT(status == napi_ok, "create uploadAsset string wrong", status);
271     status = napi_create_threadsafe_function(env, cloudDbFunc[UPLOAD_ASSET_FUNC_INDEX], nullptr, name, 0, 1,
272         nullptr, nullptr, nullptr, NapiCloudDb::UploadAssetInner, &napiCloudDb->uploadAssetInnerFunc_);
273     ASSERT(status == napi_ok, "create uploadAsset func wrong", status);
274 
275     name = nullptr;
276     status = napi_create_string_utf8(env, "deleteAsset", NAPI_AUTO_LENGTH, &name);
277     ASSERT(status == napi_ok, "create deleteAsset string wrong", status);
278     status = napi_create_threadsafe_function(env, cloudDbFunc[DELETE_ASSET_FUNC_INDEX], nullptr, name, 0, 1,
279         nullptr, nullptr, nullptr, NapiCloudDb::DeleteAssetInner, &napiCloudDb->deleteAssetInnerFunc_);
280     ASSERT(status == napi_ok, "create deleteAsset func wrong", status);
281 
282     name = nullptr;
283     status = napi_create_string_utf8(env, "deleteLocalAsset", NAPI_AUTO_LENGTH, &name);
284     ASSERT(status == napi_ok, "create deleteLocalAsset string wrong", status);
285     status = napi_create_threadsafe_function(env, cloudDbFunc[DELETE_LOCAL_ASSET_FUNC_INDEX], nullptr, name, 0, 1,
286         nullptr, nullptr, nullptr, NapiCloudDb::DeleteLocalAssetInner, &napiCloudDb->deleteLocalAssetInnerFunc_);
287     ASSERT(status == napi_ok, "create deleteLocalAsset func wrong", status);
288     return napi_ok;
289 }
290 
Delete(napi_env env,napi_callback_info info)291 napi_value CollaborationEditObject::Delete(napi_env env, napi_callback_info info)
292 {
293     size_t argc = 2;
294     napi_value argv[2] = {nullptr};
295     napi_value self = nullptr;
296     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
297     ContextParam context;
298     napi_status status = NapiUtils::GetValue(env, argv[0], context);
299     ASSERT_THROW_BASE(env, status == napi_ok, Status::INVALID_ARGUMENT, "read context param go wrong", self);
300     std::string docName;
301     status = NapiUtils::GetNamedProperty(env, argv[1], "name", docName);
302     ASSERT_THROW_BASE(env, status == napi_ok, Status::INVALID_ARGUMENT, "read docName param go wrong", self);
303     ASSERT_THROW_BASE(env, !docName.empty(), Status::INVALID_ARGUMENT, "Param Error: invalid name", self);
304     std::string dbFilePath = context.baseDir + "/" + docName;
305     DBStoreConfig config(dbFilePath, docName);
306     int ret = DBStoreManager::GetInstance().DeleteDBStore(config);
307     if (ret != 0) {
308         ThrowNapiError(env, Status::INTERNAL_ERROR, "remove dir go wrong");
309     }
310     return nullptr;
311 }
312 
ParseCloudSyncMode(const napi_env env,const napi_value arg,std::shared_ptr<SyncContext> context)313 int CollaborationEditObject::ParseCloudSyncMode(const napi_env env, const napi_value arg,
314     std::shared_ptr<SyncContext> context)
315 {
316     int32_t mode = 0;
317     napi_status status = NapiUtils::GetValue(env, arg, mode);
318     if (status != napi_ok || mode < 0 || mode > SyncMode::PULL_PUSH) {
319         LOG_ERROR("CloudSync parse syncMode go wrong, mode: %{public}d", mode);
320         return ERR;
321     }
322     context->syncMode_ = mode;
323     return OK;
324 }
325 
ParseThis(const napi_env & env,const napi_value & self,std::shared_ptr<SyncContext> context)326 int CollaborationEditObject::ParseThis(const napi_env &env, const napi_value &self,
327     std::shared_ptr<SyncContext> context)
328 {
329     CollaborationEditObject *editObject = nullptr;
330     napi_status status = napi_unwrap(env, self, reinterpret_cast<void **>(&editObject));
331     if (status != napi_ok || editObject == nullptr) {
332         LOG_ERROR("CloudSync unwrap object go wrong");
333         return ERR;
334     }
335     context->dbStore_ = editObject->GetDBStore();
336     context->boundObj = editObject;
337     return OK;
338 }
339 
GetCloudSyncInput(std::shared_ptr<SyncContext> context)340 InputAction CollaborationEditObject::GetCloudSyncInput(std::shared_ptr<SyncContext> context)
341 {
342     return [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> int {
343         LOG_DEBUG("get CloudSync input start.");
344         ASSERT(argc == CLOUD_SYNC_PARAM_NUMBER, "CloudSync read param go wrong", ERR);
345         // set params to sync context
346         ASSERT(OK == ParseThis(env, self, context), "CloudSync get editObject go wrong", ERR);
347         ASSERT(OK == ParseCloudSyncMode(env, argv[0], context), "parse syncMode go wrong", ERR);
348 
349         napi_value name = nullptr;
350         ASSERT(napi_ok == napi_create_string_utf8(env, "syncCallback", NAPI_AUTO_LENGTH, &name),
351             "create function name string wrong", ERR);
352         ASSERT(napi_ok == napi_create_threadsafe_function(env, argv[1], nullptr, name, 0, 1, nullptr, nullptr, nullptr,
353             AsyncCall::CloudSyncCallback, &context->callback_), "create syncCallback function wrong", ERR);
354         return OK;
355     };
356 }
357 
GetCloudSyncExec(std::shared_ptr<SyncContext> context)358 ExecuteAction CollaborationEditObject::GetCloudSyncExec(std::shared_ptr<SyncContext> context)
359 {
360     return [context]() -> int {
361         LOG_INFO("CollaborationEditObject::CloudSync Async execute.");
362         auto *editObject = reinterpret_cast<CollaborationEditObject *>(context->boundObj);
363         ASSERT(editObject != nullptr && context->dbStore_ != nullptr, "editObject is null or dbStore is null", ERR);
364 
365         std::shared_ptr<SyncService> syncService = SyncService::GetInstance();
366         uint64_t syncId = syncService->GetSyncId();
367         context->syncId = syncId;
368         syncService->AddSyncContext(syncId, context);
369         int32_t ret = context->dbStore_->Sync(GetGRDSyncMode(context->syncMode_), syncId,
370             CollaborationEditObject::SyncCallbackFunc);
371         if (ret != GRD_OK) {
372             LOG_ERROR("dbStore sync go wrong, errCode: %{public}d", ret);
373             GRD_SyncProcessT process = {};
374             process.status = GRD_SYNC_PROCESS_FINISHED;
375             process.errCode = ret;
376             process.mode = GRD_SYNC_MODE_INVALID;
377             process.cloudDB = nullptr;
378             process.syncId = context->syncId;
379             SyncCallbackFunc(&process);
380             return ERR;
381         }
382         return OK;
383     };
384 }
385 
CloudSync(napi_env env,napi_callback_info info)386 napi_value CollaborationEditObject::CloudSync(napi_env env, napi_callback_info info)
387 {
388     LOG_DEBUG("CloudSync start.");
389     auto context = std::make_shared<SyncContext>();
390     auto input = CollaborationEditObject::GetCloudSyncInput(context);
391     // create cloudSync execute function
392     auto exec = GetCloudSyncExec(context);
393     // create cloudSync output function
394     auto output = [context](napi_env env, napi_value &result) {
395         LOG_DEBUG("CollaborationEditObject::CloudSync output.");
396         if (context->execCode_ != OK) {
397             SyncService::GetInstance()->RemoveSyncContext(context->syncId);
398         }
399     };
400     // parse napi info and register exec/output functions to context
401     int ret = context->SetAll(env, info, input, exec, output);
402     if (ret != OK) {
403         ThrowNapiError(env, Status::INVALID_ARGUMENT, "parse params go wrong");
404         return nullptr;
405     }
406     // register cloudSync task to napi queue
407     ret = AsyncCall::Call(env, context, SYNC_FUNCTION_NAME);
408     if (ret != OK) {
409         if (context->callback_ != nullptr) {
410             napi_release_threadsafe_function(context->callback_, napi_tsfn_release);
411             context->callback_ = nullptr;
412         }
413         context->ReleaseInnerReference();
414         context.reset();
415         ThrowNapiError(env, Status::INTERNAL_ERROR, "register sync task go wrong");
416     }
417     return nullptr;
418 }
419 
GetGRDSyncMode(int32_t mode)420 GRD_SyncModeE CollaborationEditObject::GetGRDSyncMode(int32_t mode)
421 {
422     SyncMode syncMode = static_cast<SyncMode>(mode);
423     auto it = SYNC_MODE_MAP.find(syncMode);
424     if (it == SYNC_MODE_MAP.end()) {
425         return GRD_SYNC_MODE_INVALID;
426     }
427     return it->second;
428 }
429 
GetProgressCode(int32_t errCode)430 ProgressCode CollaborationEditObject::GetProgressCode(int32_t errCode)
431 {
432     switch (errCode) {
433         case GRD_OK:
434             return ProgressCode::CLOUD_SYNC_SUCCESS;
435         case GRD_SYNC_PREREQUISITES_ABNORMAL:
436             return ProgressCode::CLOUD_NOT_SET;
437         case GRD_INNER_ERR:
438             return ProgressCode::SYNC_INTERNAL_ERROR;
439         default:
440             break;
441     }
442     return ProgressCode::SYNC_EXTERNAL_ERROR;
443 }
444 
SyncCallbackFunc(GRD_SyncProcessT * syncProcess)445 void CollaborationEditObject::SyncCallbackFunc(GRD_SyncProcessT *syncProcess)
446 {
447     LOG_INFO("syncId=%{public}" PRIu64 " status=%{public}d, errCode=%{public}d.",
448         syncProcess->syncId, syncProcess->status, syncProcess->errCode);
449 
450     // call arkTs callback
451     std::shared_ptr<SyncService> syncService = SyncService::GetInstance();
452     std::shared_ptr<SyncContext> context = syncService->GetSyncContext(syncProcess->syncId);
453     syncService->RemoveSyncContext(syncProcess->syncId);
454     if (context == nullptr) {
455         LOG_ERROR("context is null");
456         return;
457     }
458     napi_threadsafe_function js_cb = context->callback_;
459     context->callback_ = nullptr;
460     context->ReleaseInnerReference();
461     if (js_cb == nullptr) {
462         LOG_ERROR("callback is null");
463         return;
464     }
465 
466     napi_status ret = napi_acquire_threadsafe_function(js_cb);
467     if (ret != napi_ok) {
468         LOG_ERROR("acquire thread safe function failed, ret: %{public}d", static_cast<int32_t>(ret));
469         napi_release_threadsafe_function(js_cb, napi_tsfn_release);
470         return;
471     }
472     SyncCallbackParamT param = {};
473     param.detail.code = CollaborationEditObject::GetProgressCode(syncProcess->errCode);
474     param.syncContext = context;
475     context.reset();
476 
477     std::future<int> future = param.promise.get_future();
478     ret = napi_call_threadsafe_function(js_cb, &param, napi_tsfn_blocking);
479     if (ret != napi_ok) {
480         LOG_ERROR("call function go wrong, ret=%{public}d", static_cast<int32_t>(ret));
481         napi_release_threadsafe_function(js_cb, napi_tsfn_release);
482         return;
483     }
484     std::future_status fstatus = future.wait_for(std::chrono::duration_cast<std::chrono::seconds>(TIME_THRESHOLD));
485     if (fstatus == std::future_status::ready) {
486         future.get();
487     } else {
488         LOG_ERROR("wait for js callback timeout");
489     }
490 
491     napi_release_threadsafe_function(js_cb, napi_tsfn_release);
492     LOG_INFO("syncCallback end");
493 }
494 
SetDBStore(std::shared_ptr<DBStore> dbStore)495 void CollaborationEditObject::SetDBStore(std::shared_ptr<DBStore> dbStore)
496 {
497     this->dbStore_ = dbStore;
498 }
499 
GetDBStore()500 std::shared_ptr<DBStore> CollaborationEditObject::GetDBStore()
501 {
502     return this->dbStore_;
503 }
504 
GetLocalId(napi_env env,napi_callback_info info)505 napi_value CollaborationEditObject::GetLocalId(napi_env env, napi_callback_info info)
506 {
507     napi_value self = nullptr;
508     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr));
509     CollaborationEditObject *editObject = nullptr;
510     napi_status status = napi_unwrap(env, self, reinterpret_cast<void **>(&editObject));
511     ASSERT_THROW(env, status == napi_ok, status, "unwrap object go wrong");
512     std::string localId = (*editObject->dbStore_).GetLocalId();
513     napi_value result;
514     NapiUtils::SetValue(env, localId, result);
515     return result;
516 }
517 
ApplyUpdate(napi_env env,napi_callback_info info)518 napi_value CollaborationEditObject::ApplyUpdate(napi_env env, napi_callback_info info)
519 {
520     napi_value self = nullptr;
521     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr));
522     CollaborationEditObject *editObject = nullptr;
523     napi_status status = napi_unwrap(env, self, reinterpret_cast<void **>(&editObject));
524     ASSERT_THROW(env, status == napi_ok, status, "unwrap object go wrong");
525 
526     std::string applyInfo;
527     int32_t ret = (*editObject->dbStore_).ApplyUpdate(applyInfo);
528     ASSERT_THROW(env, ret == OK, ret, "ApplyUpdate go wrong");
529     napi_value result;
530     ret = Parser::ParseJsonStrToJsUpdateNode(env, applyInfo, editObject->dbStore_, result);
531     ASSERT_THROW(env, ret == OK, ret, "ParseJsonStrToJsUpdateNode go wrong");
532     return result;
533 }
534 
WriteUpdate(napi_env env,napi_callback_info info)535 napi_value CollaborationEditObject::WriteUpdate(napi_env env, napi_callback_info info)
536 {
537     size_t argc = 3;
538     napi_value argv[3] = {nullptr};
539     napi_value self = nullptr;
540     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
541     CollaborationEditObject *editObject = nullptr;
542     napi_status status = napi_unwrap(env, self, reinterpret_cast<void **>(&editObject));
543     ASSERT_THROW(env, status == napi_ok, status, "unwrap object go wrong");
544 
545     std::string equipId;
546     status = NapiUtils::GetNamedProperty(env, argv[0], "id", equipId);
547     ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "read equipId param go wrong");
548 
549     std::vector<uint8_t> data;
550     status = NapiUtils::GetNamedProperty(env, argv[0], "data", data);
551     ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "read data param go wrong");
552 
553     int64_t watermark;
554     status = NapiUtils::GetNamedProperty(env, argv[0], "cursor", watermark);
555     ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "read cursor param go wrong");
556 
557     int32_t ret =
558         (*editObject->dbStore_).WriteUpdate(equipId.c_str(), data.data(), data.size(), std::to_string(watermark));
559     ASSERT_THROW(env, ret == OK, ret, "WriteUpdate go wrong");
560     return nullptr;
561 }
562 } // namespace OHOS::CollaborationEdit
563