1/*
2 * Copyright (c) 2023 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#include "sequence_runner.h"
16
17#include <cinttypes>
18
19#include "helper/error_helper.h"
20#include "helper/napi_helper.h"
21#include "helper/object_helper.h"
22#include "task_manager.h"
23#include "tools/log.h"
24
25namespace Commonlibrary::Concurrent::TaskPoolModule {
26using namespace Commonlibrary::Concurrent::Common::Helper;
27static constexpr char EXECUTE_STR[] = "execute";
28static constexpr char SEQ_RUNNER_ID_STR[] = "seqRunnerId";
29
30void SequenceRunner::SeqRunnerConstructorInner(napi_env env, napi_value &thisVar, SequenceRunner *seqRunner)
31{
32    // update seqRunner.seqRunnerId
33    uint64_t seqRunnerId = reinterpret_cast<uint64_t>(seqRunner);
34    napi_value napiSeqRunnerId = NapiHelper::CreateUint64(env, seqRunnerId);
35    TaskGroupManager::GetInstance().StoreSequenceRunner(seqRunnerId, seqRunner);
36    napi_property_descriptor properties[] = {
37        DECLARE_NAPI_PROPERTY(SEQ_RUNNER_ID_STR, napiSeqRunnerId),
38        DECLARE_NAPI_FUNCTION(EXECUTE_STR, Execute),
39    };
40    napi_define_properties(env, thisVar, sizeof(properties) / sizeof(properties[0]), properties);
41    HILOG_INFO("taskpool:: construct seqRunner name is %{public}s, seqRunnerid %{public}s.",
42               seqRunner->seqName_.c_str(), std::to_string(seqRunnerId).c_str());
43
44    seqRunner->seqRunnerId_ = seqRunnerId;
45    napi_wrap(env, thisVar, seqRunner, SequenceRunnerDestructor, nullptr, nullptr);
46}
47
48napi_value SequenceRunner::SeqRunnerConstructor(napi_env env, napi_callback_info cbinfo)
49{
50    // get input args out of env and cbinfo
51    size_t argc = 2; // 2: The maximum number of parameters is 2
52    napi_value args[2]; // 2: The maximum number of parameters is 2
53    napi_value thisVar;
54    napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
55
56    uint32_t priority = Priority::DEFAULT;
57    std::string name = "";
58    if (argc == 2) { // 2: The number of parameters is 2, if the first is seqRunner name, the second must be priority
59        if (NapiHelper::IsString(env, args[0]) && NapiHelper::IsNumber(env, args[1])) {
60            name = NapiHelper::GetString(env, args[0]);
61            priority = NapiHelper::GetUint32Value(env, args[1]);
62            if (priority >= Priority::NUMBER) {
63                ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "priority value unvalied.");
64                return nullptr;
65            }
66        } else {
67            ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
68                "the type of first param must be string and the type of second param must be string.");
69            return nullptr;
70        }
71    } else if (argc == 1) {
72        if (NapiHelper::IsString(env, args[0])) {
73            name = NapiHelper::GetString(env, args[0]);
74        } else if (NapiHelper::IsNumber(env, args[0])) {
75            priority = NapiHelper::GetUint32Value(env, args[0]);
76            if (priority >= Priority::NUMBER) {
77                ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "priority value unvalied.");
78                return nullptr;
79            }
80        } else {
81            ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of first param must be string or number.");
82            return nullptr;
83        }
84    }
85
86    SequenceRunner* seqRunner = nullptr;
87    if (name != "") {
88        seqRunner = SequenceRunnerManager::GetInstance().CreateOrGetGlobalRunner(env, thisVar, argc, name, priority);
89        if (seqRunner == nullptr) {
90            HILOG_ERROR("taskpool:: create or get globalRunner failed");
91            return nullptr;
92        }
93    } else {
94        seqRunner = new SequenceRunner();
95        seqRunner->priority_ = static_cast<Priority>(priority);
96        napi_create_reference(env, thisVar, 0, &seqRunner->seqRunnerRef_);
97    }
98
99    SeqRunnerConstructorInner(env, thisVar, seqRunner);
100    return thisVar;
101}
102
103napi_value SequenceRunner::Execute(napi_env env, napi_callback_info cbinfo)
104{
105    size_t argc = 1;
106    napi_value args[1];
107    napi_value thisVar;
108    napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
109    std::string errMessage = "";
110    if (argc < 1) {
111        errMessage = "seqRunner:: number of params at least one";
112        HILOG_ERROR("taskpool:: %{public}s", errMessage.c_str());
113        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the number of param at least one.");
114        return nullptr;
115    }
116    if (!NapiHelper::IsObject(env, args[0]) || !NapiHelper::HasNameProperty(env, args[0], TASKID_STR)) {
117        errMessage = "seqRunner:: first param must be task.";
118        HILOG_ERROR("taskpool:: %{public}s", errMessage.c_str());
119        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of the first param must be task.");
120        return nullptr;
121    }
122    napi_value napiSeqRunnerId = NapiHelper::GetNameProperty(env, thisVar, SEQ_RUNNER_ID_STR);
123    uint64_t seqRunnerId = NapiHelper::GetUint64Value(env, napiSeqRunnerId);
124    SequenceRunner* seqRunner = TaskGroupManager::GetInstance().GetSeqRunner(seqRunnerId);
125    if (seqRunner == nullptr) {
126        return nullptr;
127    }
128    Task* task = nullptr;
129    napi_unwrap(env, args[0], reinterpret_cast<void**>(&task));
130    if (task == nullptr) {
131        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of param must be task.");
132        return nullptr;
133    }
134    if (!task->CanForSequenceRunner(env)) {
135        return nullptr;
136    }
137    task->seqRunnerId_ = seqRunnerId;
138    napi_value promise = task->GetTaskInfoPromise(env, args[0], TaskType::SEQRUNNER_TASK, seqRunner->priority_);
139    if (promise == nullptr) {
140        return nullptr;
141    }
142    napi_reference_ref(env, seqRunner->seqRunnerRef_, nullptr);
143    if (seqRunner->currentTaskId_ == 0) {
144        HILOG_INFO("taskpool:: taskId %{public}s in seqRunner %{public}s immediately.",
145                   std::to_string(task->taskId_).c_str(), std::to_string(seqRunnerId).c_str());
146        seqRunner->currentTaskId_ = task->taskId_;
147        task->IncreaseRefCount();
148        task->taskState_ = ExecuteState::WAITING;
149        ExecuteTaskImmediately(task->taskId_, seqRunner->priority_);
150    } else {
151        HILOG_INFO("taskpool:: add taskId: %{public}s to seqRunner %{public}s.",
152                   std::to_string(task->taskId_).c_str(), std::to_string(seqRunnerId).c_str());
153        TaskGroupManager::GetInstance().AddTaskToSeqRunner(seqRunnerId, task);
154    }
155    return promise;
156}
157
158void SequenceRunner::ExecuteTaskImmediately(uint64_t taskId, Priority priority)
159{
160    TaskManager::GetInstance().EnqueueTaskId(taskId, priority);
161}
162
163void SequenceRunner::SequenceRunnerDestructor(napi_env env, void* data, [[maybe_unused]] void* hint)
164{
165    SequenceRunner* seqRunner = static_cast<SequenceRunner*>(data);
166    if (seqRunner->isGlobalRunner_) {
167        SequenceRunnerManager::GetInstance().GlobalSequenceRunnerDestructor(env, seqRunner);
168    } else {
169        TaskGroupManager::GetInstance().RemoveSequenceRunner(seqRunner->seqRunnerId_);
170        napi_delete_reference(env, seqRunner->seqRunnerRef_);
171        delete seqRunner;
172    }
173}
174} // namespace Commonlibrary::Concurrent::TaskPoolModule