1/*
2 * Copyright (c) 2021 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#ifndef ASYN_CALL_H
16#define ASYN_CALL_H
17
18#include "cpp/mutex.h"
19#include "global.h"
20#include "js_utils.h"
21#include "ffrt.h"
22#include "napi/native_api.h"
23#include "napi/native_common.h"
24#include "napi/native_node_api.h"
25
26namespace OHOS {
27namespace MiscServices {
28class AsyncCall final {
29public:
30    class Context {
31    public:
32        using InputAction = std::function<napi_status(napi_env, size_t, napi_value *, napi_value)>;
33        using OutputAction = std::function<napi_status(napi_env, napi_value *)>;
34        using ExecAction = std::function<void(Context *)>;
35        Context(InputAction input, OutputAction output) : input_(std::move(input)), output_(std::move(output)){};
36        virtual ~Context(){};
37        void SetAction(InputAction input, OutputAction output = nullptr)
38        {
39            input_ = input;
40            output_ = output;
41        }
42
43        void SetErrorCode(int32_t errorCode)
44        {
45            errorCode_ = errorCode;
46        }
47
48        void SetErrorMessage(const std::string &errMessage)
49        {
50            errMessage_ = errMessage;
51        }
52
53        void SetState(const napi_status &status)
54        {
55            status_ = status;
56        }
57
58        void SetAction(OutputAction output)
59        {
60            SetAction(nullptr, std::move(output));
61        }
62
63        virtual napi_status operator()(napi_env env, size_t argc, napi_value *argv, napi_value self)
64        {
65            if (input_ == nullptr) {
66                return napi_ok;
67            }
68            auto ret = input_(env, argc, argv, self);
69            input_ = nullptr;
70            return ret;
71        }
72
73        virtual napi_status operator()(napi_env env, napi_value *result)
74        {
75            if (output_ == nullptr) {
76                *result = nullptr;
77                return napi_ok;
78            }
79            auto ret = output_(env, result);
80            output_ = nullptr;
81            return ret;
82        }
83
84        virtual void Exec()
85        {
86            if (exec_ == nullptr) {
87                return;
88            }
89            exec_(this);
90            exec_ = nullptr;
91        };
92
93    protected:
94        friend class AsyncCall;
95        InputAction input_ = nullptr;
96        OutputAction output_ = nullptr;
97        ExecAction exec_ = nullptr;
98        napi_status status_ = napi_generic_failure;
99        int32_t errorCode_ = 0;
100        std::string errMessage_;
101    };
102
103    struct InnerTask {
104        InnerTask(napi_env env, napi_async_work work, const char *name);
105        ~InnerTask();
106        napi_env env = nullptr;
107        napi_async_work work = nullptr;
108        const char *name = nullptr;
109        uint64_t startTime = 0;
110    };
111
112    struct TaskQueue {
113        ffrt::mutex queuesMutex_;
114        std::queue<InnerTask> taskQueue_;
115        bool isRunning = false;
116    };
117
118    AsyncCall(napi_env env, napi_callback_info info, std::shared_ptr<Context> context, size_t maxParamCount);
119    ~AsyncCall();
120    napi_value Call(napi_env env, Context::ExecAction exec = nullptr, const std::string &resourceName = "AsyncCall");
121    napi_value Post(napi_env env, Context::ExecAction exec, std::shared_ptr<TaskQueue> queue, const char *func);
122    napi_value SyncCall(napi_env env, Context::ExecAction exec = nullptr);
123
124private:
125    enum Arg : int { ARG_ERROR, ARG_DATA, ARG_BUTT };
126    static void OnExecute(napi_env env, void *data);
127    static void OnExecuteSeq(napi_env env, void *data);
128    static void OnComplete(napi_env env, napi_status status, void *data);
129    struct AsyncContext {
130        std::shared_ptr<Context> ctx = nullptr;
131        napi_ref callback = nullptr;
132        napi_ref self = nullptr;
133        napi_deferred defer = nullptr;
134        napi_async_work work = nullptr;
135        std::shared_ptr<TaskQueue> queue = nullptr;
136    };
137    static void DeleteContext(napi_env env, AsyncContext *context);
138
139    AsyncContext *context_ = nullptr;
140    napi_env env_ = nullptr;
141};
142} // namespace MiscServices
143} // namespace OHOS
144#endif // ASYNC_CALL_H
145