1 /*
2  * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development 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 <string>
17 #include "aki/jsbind.h"
18 #include <aki/version.h>
19 #include "napi/native_api.h"
20 
21 // Function
SayHello(std::string msg)22 std::string SayHello(std::string msg)
23 {
24     return msg + " too.";
25 }
26 
AsyncSayHello(std::string msg)27 std::string AsyncSayHello(std::string msg)
28 {
29     // Do something;
30     return msg + " too.";
31 }
32 
33 // Class
34 class TestObject {
35 public:
TestObject()36     TestObject()
37     {
38         value_ = -1;
39         result = -1;
40     };
41 
TestObject(double test)42     explicit TestObject(double test)
43     {
44         value_ = test;
45     }
46 
47     ~TestObject() = default;
48 
MultiplyObject(TestObject obj1, TestObject obj2)49     static double MultiplyObject(TestObject obj1, TestObject obj2)
50     {
51         return obj1.value_ * obj2.value_;
52     }
53 
Multiply(double mult)54     double Multiply(double mult)
55     {
56         value_ *= mult;
57         return value_;
58     }
59 
GetValue() const60     double GetValue() const
61     {
62         return value_;
63     }
64 
SetValue(double value)65     void SetValue(double value)
66     {
67         value_ = value;
68     }
69     double result;
70 private:
71     double value_;
72 }; // TestObject
73 
JSBIND_CLASS(TestObject)74 JSBIND_CLASS(TestObject)
75 {
76     JSBIND_CONSTRUCTOR<>();
77     JSBIND_CONSTRUCTOR<double>();
78     JSBIND_METHOD(MultiplyObject);
79     JSBIND_METHOD(Multiply);
80     JSBIND_FIELD("value", GetValue, SetValue);
81     JSBIND_PROPERTY(result);
82 }
83 
84 // Enum
85 enum TypeFlags {
86     NONE,
87     NUM,
88     STRING,
89     BUTT = -1
90 };
91 
JSBIND_ENUM(TypeFlags)92 JSBIND_ENUM(TypeFlags) {
93     JSBIND_ENUM_VALUE(NONE);
94     JSBIND_ENUM_VALUE(NUM);
95     JSBIND_ENUM_VALUE(STRING);
96 }
97 
Passing(TypeFlags flag)98 TypeFlags Passing(TypeFlags flag)
99 {
100     return flag;
101 }
102 
103 // PostTask
104 
ReturnPromiseResolveLater()105 static aki::Promise ReturnPromiseResolveLater()
106 {
107     aki::Promise promise;
108 
109     std::thread t([promise] () {
110         aki::TaskRunner::PostTask("main", [promise] () {
111             promise.Resolve(1);
112         });
113     });
114     t.detach();
115     return promise;
116 }
117 
118 // arraybuffer
AsyncTaskReturnArrayBufferWithCommit(aki::ArrayBuffer input)119 aki::ArrayBuffer AsyncTaskReturnArrayBufferWithCommit(aki::ArrayBuffer input)
120 {
121     uint8_t temp[4] = {10, 20, 30, 40};
122     aki::ArrayBuffer arrayBufferOne(temp, TypeFlags.NUM);
123     aki::ArrayBuffer arrayBufferTwo(input.GetData(), input.GetLength());
124     arrayBufferOne.Commit();
125     return arrayBufferOne;
126 }
127 
128 // aki-value
GetFromGlobal(aki::Value obj)129 std::string GetFromGlobal(aki::Value obj)
130 {
131     aki::Value jsonObj = aki::Value::FromGlobal("JSON");
132     aki::Value strObj = jsonObj["stringify"](obj);
133     return strObj.As<std::string>();
134 }
135 
ConvertToString(aki::Value obj)136 std::string ConvertToString(aki::Value obj)
137 {
138     if (obj.IsNull()) {
139         return "null value";
140     } else if (obj.IsArray()) {
141         obj.CallMethod("push", "from C++");
142         aki::Value val1 = obj[0];
143         aki::Value strObj = aki::Value::FromGlobal("JSON")["stringify"](obj);
144         return strObj.As<std::string>();
145     } else if (obj.IsBool()) {
146         return obj.As<std::string>();
147     } else if (obj.IsNumber()) {
148         return obj.As<std::string>();
149     } else if (obj.IsString()) {
150         aki::Value val = aki::Value::NewObject();
151         val.Set("name", obj.As<std::string>());
152         aki::Value strObj = aki::Value::FromGlobal("JSON")["stringify"](val);
153         return strObj.As<std::string>();
154     } else {
155         napi_value nvalue = obj.GetHandle();
156         napi_value nage, nname;
157         napi_get_named_property(aki::JSBind::GetScopedEnv(), nvalue, "age", &nage);
158         napi_get_named_property(aki::JSBind::GetScopedEnv(), nvalue, "name", &nname);
159 
160         int age;
161         std::string name;
162         napi_get_value_int32(aki::JSBind::GetScopedEnv(), nage, &age);
163 
164         size_t stringSize = 0;
165         napi_get_value_string_utf8(aki::JSBind::GetScopedEnv(), nname, nullptr, 0, &stringSize); // 获取字符串长度
166         name.resize(stringSize + 1);
167 
168         // 根据长度传换成字符串
169         napi_get_value_string_utf8(aki::JSBind::GetScopedEnv(), nname, &name[0], stringSize + 1, &stringSize);
170         AKI_LOG(INFO) << name << " : " << age;
171     }
172 }
173 
174 
175 // Step 1 注册 AKI 插件
176 JSBIND_ADDON(hello) // 注册 AKI 插件名: 即为编译*.so名称,规则与NAPI一致
177 
178 // Step 2 注册 FFI 特性
JSBIND_GLOBAL()179 JSBIND_GLOBAL() {
180     JSBIND_FUNCTION(SayHello);
181     JSBIND_PFUNCTION(AsyncSayHello);
182     JSBIND_FUNCTION(Passing);
183     JSBIND_FUNCTION(ReturnPromiseResolveLater);
184     JSBIND_PFUNCTION(AsyncTaskReturnArrayBufferWithCommit);
185     JSBIND_FUNCTION(ConvertToString);
186 }