1 /*
2 * Copyright (c) 2022 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 "websocket_module.h"
17
18 #include "constant.h"
19 #include "netstack_log.h"
20 #include "module_template.h"
21 #include "netstack_common_utils.h"
22 #include "websocket_async_work.h"
23
24 namespace OHOS::NetStack::Websocket {
25 static bool g_appIsAtomicService = false;
26 static std::once_flag g_isAtomicServiceFlag;
27 static std::string g_appBundleName;
28
InitWebSocketModule(napi_env env,napi_value exports)29 napi_value WebSocketModule::InitWebSocketModule(napi_env env, napi_value exports)
30 {
31 DefineWebSocketClass(env, exports);
32 #ifdef NETSTACK_WEBSOCKETSERVER
33 DefineWebSocketServerClass(env, exports);
34 #endif
35 InitWebSocketProperties(env, exports);
36 NapiUtils::SetEnvValid(env);
37 std::call_once(g_isAtomicServiceFlag, []() {
38 g_appIsAtomicService = CommonUtils::IsAtomicService(g_appBundleName);
39 NETSTACK_LOGI("IsAtomicService bundleName is %{public}s, isAtomicService is %{public}d",
40 g_appBundleName.c_str(), g_appIsAtomicService);
41 });
42 auto envWrapper = new (std::nothrow)napi_env;
43 if (envWrapper == nullptr) {
44 return exports;
45 }
46 *envWrapper = env;
47 napi_add_env_cleanup_hook(env, NapiUtils::HookForEnvCleanup, envWrapper);
48 return exports;
49 }
50
CreateWebSocket(napi_env env,napi_callback_info info)51 napi_value WebSocketModule::CreateWebSocket(napi_env env, napi_callback_info info)
52 {
53 return ModuleTemplate::NewInstanceWithSharedManager(env, info, INTERFACE_WEB_SOCKET, FinalizeWebSocketInstance);
54 }
55
CreateWebSocketServer(napi_env env,napi_callback_info info)56 napi_value WebSocketModule::CreateWebSocketServer(napi_env env, napi_callback_info info)
57 {
58 #ifdef NETSTACK_WEBSOCKETSERVER
59 return ModuleTemplate::NewInstanceWithSharedManager(env, info, INTERFACE_WEB_SOCKET_SERVER,
60 FinalizeWebSocketInstance);
61 #else
62 return nullptr;
63 #endif
64 }
65
DefineWebSocketClass(napi_env env,napi_value exports)66 void WebSocketModule::DefineWebSocketClass(napi_env env, napi_value exports)
67 {
68 std::initializer_list<napi_property_descriptor> properties = {
69 DECLARE_NAPI_FUNCTION(WebSocket::FUNCTION_CONNECT, WebSocket::Connect),
70 DECLARE_NAPI_FUNCTION(WebSocket::FUNCTION_SEND, WebSocket::Send),
71 DECLARE_NAPI_FUNCTION(WebSocket::FUNCTION_CLOSE, WebSocket::Close),
72 DECLARE_NAPI_FUNCTION(WebSocket::FUNCTION_ON, WebSocket::On),
73 DECLARE_NAPI_FUNCTION(WebSocket::FUNCTION_OFF, WebSocket::Off),
74 };
75 ModuleTemplate::DefineClass(env, exports, properties, INTERFACE_WEB_SOCKET);
76 }
77
78 #ifdef NETSTACK_WEBSOCKETSERVER
DefineWebSocketServerClass(napi_env env,napi_value exports)79 void WebSocketModule::DefineWebSocketServerClass(napi_env env, napi_value exports)
80 {
81 std::initializer_list<napi_property_descriptor> properties = {
82 DECLARE_NAPI_FUNCTION(WebSocketServer::FUNCTION_START, WebSocketServer::Start),
83 DECLARE_NAPI_FUNCTION(WebSocketServer::FUNCTION_LISTALLCONNECTIONS, WebSocketServer::ListAllConnections),
84 DECLARE_NAPI_FUNCTION(WebSocketServer::FUNCTION_CLOSE, WebSocketServer::Close),
85 DECLARE_NAPI_FUNCTION(WebSocketServer::FUNCTION_ON, WebSocketServer::On),
86 DECLARE_NAPI_FUNCTION(WebSocketServer::FUNCTION_OFF, WebSocketServer::Off),
87 DECLARE_NAPI_FUNCTION(WebSocketServer::FUNCTION_SEND, WebSocketServer::Send),
88 DECLARE_NAPI_FUNCTION(WebSocketServer::FUNCTION_STOP, WebSocketServer::Stop),
89 };
90 ModuleTemplate::DefineClass(env, exports, properties, INTERFACE_WEB_SOCKET_SERVER);
91 }
92 #endif
93
InitWebSocketProperties(napi_env env,napi_value exports)94 void WebSocketModule::InitWebSocketProperties(napi_env env, napi_value exports)
95 {
96 std::initializer_list<napi_property_descriptor> properties = {
97 DECLARE_NAPI_FUNCTION(FUNCTION_CREATE_WEB_SOCKET, CreateWebSocket),
98 DECLARE_NAPI_FUNCTION(FUNCTION_CREATE_WEB_SOCKET_SERVER, CreateWebSocketServer),
99 };
100 NapiUtils::DefineProperties(env, exports, properties);
101 }
102
FinalizeWebSocketInstance(napi_env env,void * data,void * hint)103 void WebSocketModule::FinalizeWebSocketInstance(napi_env env, void *data, void *hint)
104 {
105 NETSTACK_LOGI("websocket handle is finalized");
106 auto sharedManager = reinterpret_cast<std::shared_ptr<EventManager> *>(data);
107 delete sharedManager;
108 }
109
Connect(napi_env env,napi_callback_info info)110 napi_value WebSocketModule::WebSocket::Connect(napi_env env, napi_callback_info info)
111 {
112 return ModuleTemplate::InterfaceWithSharedManager<ConnectContext>(
113 env, info, "WebSocketConnect",
114 [](napi_env, napi_value, ConnectContext *context) -> bool {
115 context->SetAtomicService(g_appIsAtomicService);
116 context->SetBundleName(g_appBundleName);
117 return true;
118 },
119 WebSocketAsyncWork::ExecConnect, WebSocketAsyncWork::ConnectCallback);
120 }
121
Send(napi_env env,napi_callback_info info)122 napi_value WebSocketModule::WebSocket::Send(napi_env env, napi_callback_info info)
123 {
124 return ModuleTemplate::InterfaceWithSharedManager<SendContext>(
125 env, info, "WebSocketSend", nullptr, WebSocketAsyncWork::ExecSend, WebSocketAsyncWork::SendCallback);
126 }
127
Close(napi_env env,napi_callback_info info)128 napi_value WebSocketModule::WebSocket::Close(napi_env env, napi_callback_info info)
129 {
130 return ModuleTemplate::InterfaceWithSharedManager<CloseContext>(
131 env, info, "WebSocketClose", nullptr, WebSocketAsyncWork::ExecClose, WebSocketAsyncWork::CloseCallback);
132 }
133
On(napi_env env,napi_callback_info info)134 napi_value WebSocketModule::WebSocket::On(napi_env env, napi_callback_info info)
135 {
136 ModuleTemplate::OnSharedManager(env, info,
137 {EventName::EVENT_OPEN, EventName::EVENT_MESSAGE, EventName::EVENT_CLOSE}, true);
138 return ModuleTemplate::OnSharedManager(
139 env, info, {EventName::EVENT_ERROR, EventName::EVENT_HEADER_RECEIVE, EventName::EVENT_DATA_END}, false);
140 }
141
Off(napi_env env,napi_callback_info info)142 napi_value WebSocketModule::WebSocket::Off(napi_env env, napi_callback_info info)
143 {
144 return ModuleTemplate::OffSharedManager(env, info,
145 {EventName::EVENT_OPEN, EventName::EVENT_MESSAGE, EventName::EVENT_CLOSE,
146 EventName::EVENT_ERROR, EventName::EVENT_DATA_END,
147 EventName::EVENT_HEADER_RECEIVE});
148 }
149
150 #ifdef NETSTACK_WEBSOCKETSERVER
Start(napi_env env,napi_callback_info info)151 napi_value WebSocketModule::WebSocketServer::Start(napi_env env, napi_callback_info info)
152 {
153 return ModuleTemplate::InterfaceWithSharedManager<ServerStartContext>(
154 env, info, "WebSocketServerStart", nullptr, WebSocketAsyncWork::ExecServerStart,
155 WebSocketAsyncWork::ServerStartCallback);
156 }
157
ListAllConnections(napi_env env,napi_callback_info info)158 napi_value WebSocketModule::WebSocketServer::ListAllConnections(napi_env env, napi_callback_info info)
159 {
160 return ModuleTemplate::InterfaceWithSharedManager<ListAllConnectionsContext>(
161 env, info, "WebSocketServerListAllConnections", nullptr, WebSocketAsyncWork::ExecListAllConnections,
162 WebSocketAsyncWork::ListAllConnectionsCallback);
163 }
164
Close(napi_env env,napi_callback_info info)165 napi_value WebSocketModule::WebSocketServer::Close(napi_env env, napi_callback_info info)
166 {
167 return ModuleTemplate::InterfaceWithSharedManager<ServerCloseContext>(
168 env, info, "WebSocketServerClose", nullptr, WebSocketAsyncWork::ExecServerClose,
169 WebSocketAsyncWork::ServerCloseCallback);
170 }
171
Send(napi_env env,napi_callback_info info)172 napi_value WebSocketModule::WebSocketServer::Send(napi_env env, napi_callback_info info)
173 {
174 return ModuleTemplate::InterfaceWithSharedManager<ServerSendContext>(
175 env, info, "WebSocketServerSend", nullptr, WebSocketAsyncWork::ExecServerSend,
176 WebSocketAsyncWork::ServerSendCallback);
177 }
178
Stop(napi_env env,napi_callback_info info)179 napi_value WebSocketModule::WebSocketServer::Stop(napi_env env, napi_callback_info info)
180 {
181 return ModuleTemplate::InterfaceWithSharedManager<ServerStopContext>(
182 env, info, "WebSocketServerStop", nullptr, WebSocketAsyncWork::ExecServerStop,
183 WebSocketAsyncWork::ServerStopCallback);
184 }
185
On(napi_env env,napi_callback_info info)186 napi_value WebSocketModule::WebSocketServer::On(napi_env env, napi_callback_info info)
187 {
188 return ModuleTemplate::OnSharedManager(env, info,
189 {EventName::EVENT_SERVER_CONNECT, EventName::EVENT_SERVER_MESSAGE_RECEIVE,
190 EventName::EVENT_SERVER_ERROR, EventName::EVENT_SERVER_CLOSE}, false);
191 }
192
Off(napi_env env,napi_callback_info info)193 napi_value WebSocketModule::WebSocketServer::Off(napi_env env, napi_callback_info info)
194 {
195 return ModuleTemplate::OffSharedManager(env, info,
196 {EventName::EVENT_SERVER_ERROR, EventName::EVENT_SERVER_CONNECT,
197 EventName::EVENT_SERVER_CLOSE, EventName::EVENT_SERVER_MESSAGE_RECEIVE});
198 }
199 #endif
200
201 static napi_module g_websocketModule = {
202 .nm_version = 1,
203 .nm_flags = 0,
204 .nm_filename = nullptr,
205 .nm_register_func = WebSocketModule::InitWebSocketModule,
206 .nm_modname = "net.webSocket",
207 .nm_priv = nullptr,
208 .reserved = {nullptr},
209 };
210
RegisterWebSocketModule(void)211 extern "C" __attribute__((constructor)) void RegisterWebSocketModule(void)
212 {
213 napi_module_register(&g_websocketModule);
214 }
215 } // namespace OHOS::NetStack::Websocket
216