From f9aabb22ce2417e09487403c5f780942aa72e574 Mon Sep 17 00:00:00 2001 From: maosiping Date: Tue, 29 Mar 2022 11:50:52 +0800 Subject: [PATCH 01/17] support libwebsockets Signed-off-by: maosiping --- CMakeLists.txt | 3 + .../async_context/include/close_context.h | 44 ++ .../async_context/include/connect_context.h | 50 ++ .../async_context/include/send_context.h | 47 ++ .../async_context/src/close_context.cpp | 78 ++ .../async_context/src/connect_context.cpp | 96 +++ .../async_context/src/send_context.cpp | 99 +++ .../async_work/include/websocket_async_work.h | 41 + .../async_work/src/websocket_async_work.cpp | 50 ++ .../websocket/constant/include/constant.h | 66 ++ .../src/constant.cpp} | 26 +- .../websocket_exec/include/websocket_exec.h | 90 +++ .../websocket_exec/src/websocket_exec.cpp | 712 ++++++++++++++++++ .../include/websocket_module.h | 60 ++ .../websocket_module/src/websocket_module.cpp | 93 +++ test/napi/websocket/CMakeLists.txt | 49 ++ .../napi/websocket/test_napi_exec.cpp | 13 +- .../include/netstack_base_context.h | 2 + .../src/netstack_base_context.cpp | 5 + .../include/netstack_common_utils.h | 2 + .../src/netstack_common_utils.cpp | 21 + .../include/netstack_event_listener.h | 17 + .../include/netstack_event_manager.h | 2 + .../src/netstack_event_listener.cpp | 28 + .../src/netstack_event_manager.cpp | 14 + utils/log/include/netstack_log.h | 9 +- .../napi_utils/include/netstack_napi_utils.h | 11 + utils/napi_utils/src/netstack_napi_utils.cpp | 33 + 28 files changed, 1742 insertions(+), 19 deletions(-) create mode 100644 frameworks/js/napi/websocket/async_context/include/close_context.h create mode 100644 frameworks/js/napi/websocket/async_context/include/connect_context.h create mode 100644 frameworks/js/napi/websocket/async_context/include/send_context.h create mode 100644 frameworks/js/napi/websocket/async_context/src/close_context.cpp create mode 100644 frameworks/js/napi/websocket/async_context/src/connect_context.cpp create mode 100644 frameworks/js/napi/websocket/async_context/src/send_context.cpp create mode 100644 frameworks/js/napi/websocket/async_work/include/websocket_async_work.h create mode 100644 frameworks/js/napi/websocket/async_work/src/websocket_async_work.cpp create mode 100644 frameworks/js/napi/websocket/constant/include/constant.h rename frameworks/js/napi/websocket/{include/websocket_napi.h => constant/src/constant.cpp} (56%) create mode 100644 frameworks/js/napi/websocket/websocket_exec/include/websocket_exec.h create mode 100644 frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp create mode 100644 frameworks/js/napi/websocket/websocket_module/include/websocket_module.h create mode 100644 frameworks/js/napi/websocket/websocket_module/src/websocket_module.cpp create mode 100644 test/napi/websocket/CMakeLists.txt rename frameworks/js/napi/websocket/src/websocket_napi.cpp => test/napi/websocket/test_napi_exec.cpp (75%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3fece9a9f..f6e69e57f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,8 @@ include_directories(utils/base_context/include) include_directories(utils/base_async_work/include) include_directories(utils/module_template/include) +include_directories(../../../for_linux) + include_directories(../../../utils/native/base/include/) include_directories(utils/log/include) @@ -63,4 +65,5 @@ add_subdirectory(utils) add_subdirectory(test/napi/http) add_subdirectory(test/napi/socket) add_subdirectory(test/napi/fetch) +add_subdirectory(test/napi/websocket) add_subdirectory(test/utils/napi_utils/unittest) \ No newline at end of file diff --git a/frameworks/js/napi/websocket/async_context/include/close_context.h b/frameworks/js/napi/websocket/async_context/include/close_context.h new file mode 100644 index 000000000..62c0307ae --- /dev/null +++ b/frameworks/js/napi/websocket/async_context/include/close_context.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef COMMUNICATIONNETSTACK_CLOSE_CONTEXT_H +#define COMMUNICATIONNETSTACK_CLOSE_CONTEXT_H + +#include + +#include "netstack_base_context.h" +#include "noncopyable.h" + +namespace OHOS::NetStack { +class CloseContext final : public BaseContext { +public: + ACE_DISALLOW_COPY_AND_MOVE(CloseContext); + + CloseContext() = delete; + + explicit CloseContext(napi_env env, EventManager *manager); + + void ParseParams(napi_value *params, size_t paramsCount); + + uint32_t code; + + std::string reason; + +private: + bool CheckParamsType(napi_value *params, size_t paramsCount); +}; +} // namespace OHOS::NetStack + +#endif /* COMMUNICATIONNETSTACK_CLOSE_CONTEXT_H */ diff --git a/frameworks/js/napi/websocket/async_context/include/connect_context.h b/frameworks/js/napi/websocket/async_context/include/connect_context.h new file mode 100644 index 000000000..9bfc38e75 --- /dev/null +++ b/frameworks/js/napi/websocket/async_context/include/connect_context.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef COMMUNICATIONNETSTACK_CONNECT_CONTEXT_H +#define COMMUNICATIONNETSTACK_CONNECT_CONTEXT_H + +#include +#include + +#include "netstack_base_context.h" +#include "noncopyable.h" +#include "libwebsockets.h" + +namespace OHOS::NetStack { +class ConnectContext final : public BaseContext { +public: + ACE_DISALLOW_COPY_AND_MOVE(ConnectContext); + + ConnectContext() = delete; + + explicit ConnectContext(napi_env env, EventManager *manager); + + ~ConnectContext() override; + + void ParseParams(napi_value *params, size_t paramsCount); + + std::string url; + + std::map header; + +private: + void ParseHeader(napi_value optionsValue); + + bool CheckParamsType(napi_value *params, size_t paramsCount); +}; +} // namespace OHOS::NetStack + +#endif /* COMMUNICATIONNETSTACK_CONNECT_CONTEXT_H */ diff --git a/frameworks/js/napi/websocket/async_context/include/send_context.h b/frameworks/js/napi/websocket/async_context/include/send_context.h new file mode 100644 index 000000000..d853f9fcc --- /dev/null +++ b/frameworks/js/napi/websocket/async_context/include/send_context.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef COMMUNICATIONNETSTACK_SEND_CONTEXT_H +#define COMMUNICATIONNETSTACK_SEND_CONTEXT_H + +#include + +#include "libwebsockets.h" +#include "netstack_base_context.h" +#include "noncopyable.h" + +namespace OHOS::NetStack { +class SendContext final : public BaseContext { +public: + ACE_DISALLOW_COPY_AND_MOVE(SendContext); + + SendContext() = delete; + + explicit SendContext(napi_env env, EventManager *manager); + + void ParseParams(napi_value *params, size_t paramsCount); + + void *data; + + size_t length; + + lws_write_protocol protocol; + +private: + bool CheckParamsType(napi_value *params, size_t paramsCount); +}; +} // namespace OHOS::NetStack + +#endif /* COMMUNICATIONNETSTACK_SEND_CONTEXT_H */ diff --git a/frameworks/js/napi/websocket/async_context/src/close_context.cpp b/frameworks/js/napi/websocket/async_context/src/close_context.cpp new file mode 100644 index 000000000..6e78e7466 --- /dev/null +++ b/frameworks/js/napi/websocket/async_context/src/close_context.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "close_context.h" + +#include "constant.h" +#include "netstack_common_utils.h" +#include "netstack_log.h" +#include "netstack_napi_utils.h" + +namespace OHOS::NetStack { +CloseContext::CloseContext(napi_env env, EventManager *manager) + : BaseContext(env, manager), code(CLOSE_REASON_NORMAL_CLOSE) +{ +} + +void CloseContext::ParseParams(napi_value *params, size_t paramsCount) +{ + if (!CheckParamsType(params, paramsCount)) { + NETSTACK_LOGE("CloseContext Parse Failed"); + return; + } + + if (paramsCount == FUNCTION_PARAM_ZERO) { + NETSTACK_LOGE("CloseContext Parse OK1"); + return SetParseOK(true); + } + + if (NapiUtils::GetValueType(GetEnv(), params[0]) == napi_function) { + NETSTACK_LOGE("CloseContext Parse OK2"); + return SetParseOK(SetCallback(params[0]) == napi_ok); + } + + uint32_t closeCode = NapiUtils::GetUint32Property(GetEnv(), params[0], ContextKey::CODE); + if (closeCode >= CLOSE_REASON_NORMAL_CLOSE && closeCode <= CLOSE_REASON_RESERVED12) { + code = closeCode; + } + reason = NapiUtils::GetStringPropertyUtf8(GetEnv(), params[0], ContextKey::REASON); + + if (paramsCount == FUNCTION_PARAM_TWO) { + NETSTACK_LOGE("CloseContext Parse OK3"); + return SetParseOK(SetCallback(params[1]) == napi_ok); + } + NETSTACK_LOGE("CloseContext Parse OK4"); + return SetParseOK(true); +} + +bool CloseContext::CheckParamsType(napi_value *params, size_t paramsCount) +{ + if (paramsCount == FUNCTION_PARAM_ZERO) { + return true; + } + + if (paramsCount == FUNCTION_PARAM_ONE) { + return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_object || + NapiUtils::GetValueType(GetEnv(), params[0]) == napi_function; + } + + if (paramsCount == FUNCTION_PARAM_TWO) { + return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_object && + NapiUtils::GetValueType(GetEnv(), params[1]) == napi_function; + } + + return false; +} +} // namespace OHOS::NetStack \ No newline at end of file diff --git a/frameworks/js/napi/websocket/async_context/src/connect_context.cpp b/frameworks/js/napi/websocket/async_context/src/connect_context.cpp new file mode 100644 index 000000000..92ab32c93 --- /dev/null +++ b/frameworks/js/napi/websocket/async_context/src/connect_context.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "connect_context.h" + +#include "constant.h" +#include "netstack_common_utils.h" +#include "netstack_log.h" +#include "netstack_napi_utils.h" +#include "securec.h" + +namespace OHOS::NetStack { +ConnectContext::ConnectContext(napi_env env, EventManager *manager) : BaseContext(env, manager) {} + +ConnectContext::~ConnectContext() = default; + +void ConnectContext::ParseParams(napi_value *params, size_t paramsCount) +{ + if (!CheckParamsType(params, paramsCount)) { + NETSTACK_LOGE("ConnectContext Parse Failed"); + return; + } + + url = NapiUtils::GetStringFromValueUtf8(GetEnv(), params[0]); + if (paramsCount == FUNCTION_PARAM_ONE) { + NETSTACK_LOGI("ConnectContext paramsCount == FUNCTION_PARAM_ONE"); + return SetParseOK(true); + } + + if (NapiUtils::GetValueType(GetEnv(), params[1]) == napi_function) { + NETSTACK_LOGI("ConnectContext NapiUtils::GetValueType(GetEnv(), params[1]) == napi_function"); + return SetParseOK(SetCallback(params[1]) == napi_ok); + } + + NETSTACK_LOGI("ConnectContext NapiUtils::GetValueType(GetEnv(), params[1]) == napi_object"); + ParseHeader(params[1]); + + if (paramsCount == FUNCTION_PARAM_THREE) { + NETSTACK_LOGI("ConnectContext paramsCount == FUNCTION_PARAM_THREE"); + return SetParseOK(SetCallback(params[2]) == napi_ok); + } + return SetParseOK(true); +} + +void ConnectContext::ParseHeader(napi_value optionsValue) +{ + if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, ContextKey::HEADER)) { + return; + } + napi_value jsHeader = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, ContextKey::HEADER); + if (NapiUtils::GetValueType(GetEnv(), jsHeader) != napi_object) { + return; + } + auto names = NapiUtils::GetPropertyNames(GetEnv(), jsHeader); + std::for_each(names.begin(), names.end(), [jsHeader, this](const std::string &name) { + auto value = NapiUtils::GetStringPropertyUtf8(GetEnv(), jsHeader, name); + if (!value.empty()) { + // header key ignores key but value not + header[CommonUtils::ToLower(name)] = value; + } + }); +} + +bool ConnectContext::CheckParamsType(napi_value *params, size_t paramsCount) +{ + if (paramsCount == FUNCTION_PARAM_ONE) { + return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string; + } + + if (paramsCount == FUNCTION_PARAM_TWO) { + return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string && + (NapiUtils::GetValueType(GetEnv(), params[1]) == napi_function || + NapiUtils::GetValueType(GetEnv(), params[1]) == napi_object); + } + + if (paramsCount == FUNCTION_PARAM_THREE) { + return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string && + NapiUtils::GetValueType(GetEnv(), params[1]) == napi_object && + NapiUtils::GetValueType(GetEnv(), params[2]) == napi_function; + } + + return false; +} +} // namespace OHOS::NetStack diff --git a/frameworks/js/napi/websocket/async_context/src/send_context.cpp b/frameworks/js/napi/websocket/async_context/src/send_context.cpp new file mode 100644 index 000000000..c1227a80a --- /dev/null +++ b/frameworks/js/napi/websocket/async_context/src/send_context.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "send_context.h" + +#include "constant.h" +#include "netstack_common_utils.h" +#include "netstack_log.h" +#include "netstack_napi_utils.h" + +namespace OHOS::NetStack { +SendContext::SendContext(napi_env env, EventManager *manager) + : BaseContext(env, manager), data(nullptr), protocol(LWS_WRITE_TEXT), length(0) +{ +} + +void SendContext::ParseParams(napi_value *params, size_t paramsCount) +{ + if (!CheckParamsType(params, paramsCount)) { + NETSTACK_LOGE("SendContext Parse Failed"); + return; + } + + if (NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string) { + NETSTACK_LOGI("SendContext NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string"); + std::string str = NapiUtils::GetStringFromValueUtf8(GetEnv(), params[0]); + // must have PRE and POST + data = malloc(LWS_SEND_BUFFER_PRE_PADDING + str.length() + LWS_SEND_BUFFER_POST_PADDING); + if (data == nullptr) { + NETSTACK_LOGE("no memory"); + return; + } + if (memcpy_s(reinterpret_cast(reinterpret_cast(data) + LWS_SEND_BUFFER_PRE_PADDING), + str.length(), str.c_str(), str.length()) < 0) { + NETSTACK_LOGE("copy failed"); + return; + } + length = str.length(); + protocol = LWS_WRITE_TEXT; + } else { + NETSTACK_LOGI("SendContext data is ArrayBuffer"); + size_t len = 0; + void *mem = NapiUtils::GetInfoFromArrayBufferValue(GetEnv(), params[0], &len); + if (mem == nullptr || len == 0) { + NETSTACK_LOGE("no memory"); + return; + } + // must have PRE and POST + data = malloc(LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING); + if (data == nullptr) { + NETSTACK_LOGE("no memory"); + return; + } + if (memcpy_s(reinterpret_cast(reinterpret_cast(data) + LWS_SEND_BUFFER_PRE_PADDING), len, + mem, len) < 0) { + NETSTACK_LOGE("copy failed"); + return; + } + length = len; + protocol = LWS_WRITE_BINARY; + } + + if (NapiUtils::GetValueType(GetEnv(), params[1]) == napi_function) { + NETSTACK_LOGI("SendContext NapiUtils::GetValueType(GetEnv(), params[1]) == napi_function"); + return SetParseOK(SetCallback(params[1]) == napi_ok); + } + + NETSTACK_LOGI("SendContext SetParseOK"); + return SetParseOK(true); +} + +bool SendContext::CheckParamsType(napi_value *params, size_t paramsCount) +{ + if (paramsCount == FUNCTION_PARAM_ONE) { + return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string || + NapiUtils::ValueIsArrayBuffer(GetEnv(), params[0]); + } + + if (paramsCount == FUNCTION_PARAM_TWO) { + return (NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string || + NapiUtils::ValueIsArrayBuffer(GetEnv(), params[0])) && + NapiUtils::GetValueType(GetEnv(), params[1]) == napi_function; + } + + return false; +} +} // namespace OHOS::NetStack \ No newline at end of file diff --git a/frameworks/js/napi/websocket/async_work/include/websocket_async_work.h b/frameworks/js/napi/websocket/async_work/include/websocket_async_work.h new file mode 100644 index 000000000..ad86b4390 --- /dev/null +++ b/frameworks/js/napi/websocket/async_work/include/websocket_async_work.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef COMMUNICATIONNETSTACK_WEBSOCKET_ASYNC_WORK_H +#define COMMUNICATIONNETSTACK_WEBSOCKET_ASYNC_WORK_H + +#include "websocket_exec.h" + +namespace OHOS::NetStack { +class WebSocketAsyncWork final { +public: + ACE_DISALLOW_COPY_AND_MOVE(WebSocketAsyncWork); + + /* executor */ + static void ExecConnect(napi_env env, void *data); + + static void ExecSend(napi_env env, void *data); + + static void ExecClose(napi_env env, void *data); + + /* callback */ + static void ConnectCallback(napi_env env, napi_status status, void *data); + + static void SendCallback(napi_env env, napi_status status, void *data); + + static void CloseCallback(napi_env env, napi_status status, void *data); +}; +} // namespace OHOS::NetStack +#endif /* COMMUNICATIONNETSTACK_WEBSOCKET_ASYNC_WORK_H */ diff --git a/frameworks/js/napi/websocket/async_work/src/websocket_async_work.cpp b/frameworks/js/napi/websocket/async_work/src/websocket_async_work.cpp new file mode 100644 index 000000000..7162eb49e --- /dev/null +++ b/frameworks/js/napi/websocket/async_work/src/websocket_async_work.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "websocket_async_work.h" + +#include "netstack_base_async_work.h" + +namespace OHOS::NetStack { +void WebSocketAsyncWork::ExecConnect(napi_env env, void *data) +{ + BaseAsyncWork::ExecAsyncWork(env, data); +} + +void WebSocketAsyncWork::ExecSend(napi_env env, void *data) +{ + BaseAsyncWork::ExecAsyncWork(env, data); +} + +void WebSocketAsyncWork::ExecClose(napi_env env, void *data) +{ + BaseAsyncWork::ExecAsyncWork(env, data); +} + +void WebSocketAsyncWork::ConnectCallback(napi_env env, napi_status status, void *data) +{ + BaseAsyncWork::AsyncWorkCallback(env, status, data); +} + +void WebSocketAsyncWork::SendCallback(napi_env env, napi_status status, void *data) +{ + BaseAsyncWork::AsyncWorkCallback(env, status, data); +} + +void WebSocketAsyncWork::CloseCallback(napi_env env, napi_status status, void *data) +{ + BaseAsyncWork::AsyncWorkCallback(env, status, data); +} +} // namespace OHOS::NetStack diff --git a/frameworks/js/napi/websocket/constant/include/constant.h b/frameworks/js/napi/websocket/constant/include/constant.h new file mode 100644 index 000000000..ddf8cda33 --- /dev/null +++ b/frameworks/js/napi/websocket/constant/include/constant.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef COMMUNICATIONNETSTACK_CONSTANT_H +#define COMMUNICATIONNETSTACK_CONSTANT_H + +namespace OHOS::NetStack { +enum { + FUNCTION_PARAM_ZERO = 0, + FUNCTION_PARAM_ONE = 1, + FUNCTION_PARAM_TWO = 2, + FUNCTION_PARAM_THREE = 3, +}; + +enum { + CLOSE_REASON_NORMAL_CLOSE [[maybe_unused]] = 1000, + CLOSE_REASON_SERVER_CLOSED [[maybe_unused]] = 1001, + CLOSE_REASON_PROTOCOL_ERROR [[maybe_unused]] = 1002, + CLOSE_REASON_UNSUPPORT_DATA_TYPE [[maybe_unused]] = 1003, + CLOSE_REASON_RESERVED1 [[maybe_unused]], + CLOSE_REASON_RESERVED2 [[maybe_unused]], + CLOSE_REASON_RESERVED3 [[maybe_unused]], + CLOSE_REASON_RESERVED4 [[maybe_unused]], + CLOSE_REASON_RESERVED5 [[maybe_unused]], + CLOSE_REASON_RESERVED6 [[maybe_unused]], + CLOSE_REASON_RESERVED7 [[maybe_unused]], + CLOSE_REASON_RESERVED8 [[maybe_unused]], + CLOSE_REASON_RESERVED9 [[maybe_unused]], + CLOSE_REASON_RESERVED10 [[maybe_unused]], + CLOSE_REASON_RESERVED11 [[maybe_unused]], + CLOSE_REASON_RESERVED12 [[maybe_unused]], +}; + +class ContextKey final { +public: + static const char *HEADER; + + static const char *CODE; + + static const char *REASON; +}; + +class EventName final { +public: + static const char *EVENT_OPEN; + + static const char *EVENT_MESSAGE; + + static const char *EVENT_CLOSE; + + static const char *EVENT_ERROR; +}; +} // namespace OHOS::NetStack +#endif /* COMMUNICATIONNETSTACK_CONSTANT_H */ diff --git a/frameworks/js/napi/websocket/include/websocket_napi.h b/frameworks/js/napi/websocket/constant/src/constant.cpp similarity index 56% rename from frameworks/js/napi/websocket/include/websocket_napi.h rename to frameworks/js/napi/websocket/constant/src/constant.cpp index 1864d7172..e72a8f1ca 100644 --- a/frameworks/js/napi/websocket/include/websocket_napi.h +++ b/frameworks/js/napi/websocket/constant/src/constant.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,14 +13,20 @@ * limitations under the License. */ -#ifndef WEBSOCKET_NAPI_H -#define WEBSOCKET_NAPI_H +#include "constant.h" -#include "napi/native_api.h" -#include "napi/native_common.h" +namespace OHOS::NetStack { +const char *ContextKey::HEADER = "header"; -namespace OHOS { -namespace NetStack { -} // namespace NetStack -} // namespace OHOS -#endif // WEBSOCKET_NAPI_H +const char *ContextKey::CODE = "code"; + +const char *ContextKey::REASON = "reason"; + +const char *EventName::EVENT_OPEN = "open"; + +const char *EventName::EVENT_MESSAGE = "message"; + +const char *EventName::EVENT_CLOSE = "close"; + +const char *EventName::EVENT_ERROR = "error"; +} // namespace OHOS::NetStack \ No newline at end of file diff --git a/frameworks/js/napi/websocket/websocket_exec/include/websocket_exec.h b/frameworks/js/napi/websocket/websocket_exec/include/websocket_exec.h new file mode 100644 index 000000000..b2b47371c --- /dev/null +++ b/frameworks/js/napi/websocket/websocket_exec/include/websocket_exec.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef COMMUNICATIONNETSTACK_WEBSOCKET_EXEC_H +#define COMMUNICATIONNETSTACK_WEBSOCKET_EXEC_H + +#include "close_context.h" +#include "connect_context.h" +#include "send_context.h" + +namespace OHOS::NetStack { +class WebSocketExec final { +public: + /* async work execute */ + static bool ExecConnect(ConnectContext *context); + + static bool ExecSend(SendContext *context); + + static bool ExecClose(CloseContext *context); + + /* async work callback */ + static napi_value ConnectCallback(ConnectContext *context); + + static napi_value SendCallback(SendContext *context); + + static napi_value CloseCallback(CloseContext *context); + + static int LwsCallback(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); + +private: + static bool ParseUrl(ConnectContext *context, + char *prefix, + size_t prefixLen, + char *address, + size_t addressLen, + char *path, + size_t pathLen, + int *port); + + static void RunService(EventManager *manager); + + static int RaiseError(EventManager *manager); + + static int HttpDummy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); + + static int + LwsCallbackClientAppendHandshakeHeader(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); + + static int LwsCallbackWsPeerInitiatedClose(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); + + static int LwsCallbackClientWritable(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); + + static int + LwsCallbackClientConnectionError(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); + + static int LwsCallbackClientReceive(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); + + static int + LwsCallbackClientFilterPreEstablish(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); + + static int LwsCallbackClientEstablished(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); + + static int LwsCallbackClientClosed(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); + + static int LwsCallbackWsiDestroy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); + + static int LwsCallbackProtocolDestroy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); + + static void OnOpen(EventManager *manager, uint32_t status, const std::string &message); + + static void OnError(EventManager *manager, int32_t code); + + static void OnMessage(EventManager *manager, void *data, size_t length, bool isBinary); + + static void OnClose(EventManager *manager, lws_close_status closeStatus, const std::string &closeReason); +}; +} // namespace OHOS::NetStack +#endif /* COMMUNICATIONNETSTACK_WEBSOCKET_EXEC_H */ diff --git a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp new file mode 100644 index 000000000..5bc33aa89 --- /dev/null +++ b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp @@ -0,0 +1,712 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "websocket_exec.h" + +#include +#include +#include + +#include "constant.h" +#include "netstack_common_utils.h" +#include "netstack_log.h" +#include "netstack_napi_utils.h" + +// TODO: 调用libwebsockets的API实现 +// TODO: 需要实现缓冲区机制 + +static constexpr const char *PATH_START = "/"; + +static constexpr const char *NAME_END = ":"; + +static constexpr const char *STATUS_LINE_SEP = " "; + +static constexpr const size_t STATUS_LINE_ELEM_NUM = 2; + +static constexpr const char *PREFIX_HTTPS = "https"; + +static constexpr const char *PREFIX_WSS = "wss"; + +static constexpr const int MAX_URI_LENGTH = 1024; + +static constexpr const int FD_LIMIT_PER_THREAD = 1 + 1 + 1; + +static constexpr const int COMMON_ERROR_CODE = 200; + +static constexpr const char *EVENT_KEY_CODE = "code"; + +static constexpr const char *EVENT_KEY_STATUS = "status"; + +static constexpr const char *EVENT_KEY_REASON = "reason"; + +static constexpr const char *EVENT_KEY_MESSAGE = "message"; + +char *lws_hdr_simple_ptr(lws *wsi, lws_token_indexes index); + +namespace OHOS::NetStack { +static const lws_protocols LWS_PROTOCOLS[] = { + {"lws-minimal-client", WebSocketExec::LwsCallback, 0, 0}, + {nullptr, nullptr, 0, 0}, // this line is needed +}; + +static const lws_retry_bo_t RETRY = { + .secs_since_valid_ping = 0, + .secs_since_valid_hangup = 10, + .jitter_percent = 20, +}; + +struct CallbackDispatcher { + lws_callback_reasons reason; + int (*callback)(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); +}; + +struct OnOpenClosePara { + OnOpenClosePara() : status(0) {} + uint32_t status; + std::string message; +}; + +struct OnMessagePara { + OnMessagePara() : data(nullptr), isBinary(false), length(0) {} + ~OnMessagePara() + { + if (data != nullptr) { + free(data); + } + } + void *data; + size_t length; + bool isBinary; +}; + +class UserData { +public: + struct SendData { + SendData(void *paraData, size_t paraLength, lws_write_protocol paraProtocol) + : data(paraData), length(paraLength), protocol(paraProtocol) + { + } + + SendData() = delete; + + ~SendData() = default; + + void *data; + size_t length; + lws_write_protocol protocol; + }; + + explicit UserData(lws_context *context) + : closed_(false), context_(context), closeStatus(LWS_CLOSE_STATUS_NOSTATUS), openStatus(0) + { + } + + bool IsClosed() + { + std::lock_guard lock(mutex_); + return closed_; + } + + void Close(lws_close_status status, const std::string &reason) + { + std::lock_guard lock(mutex_); + closeStatus = status; + closeReason = reason; + closed_ = true; + } + + void Push(void *data, size_t length, lws_write_protocol protocol) + { + std::lock_guard lock(mutex_); + dataQueue_.push(SendData(data, length, protocol)); + } + + SendData Pop() + { + std::lock_guard lock(mutex_); + if (dataQueue_.empty()) { + return {nullptr, 0, LWS_WRITE_TEXT}; + } + SendData data = dataQueue_.front(); + dataQueue_.pop(); + return data; + } + + void SetContext(lws_context *context) + { + context_ = context; + } + + lws_context *GetContext() + { + return context_; + } + + std::map header; + + lws_close_status closeStatus; + + std::string closeReason; + + uint32_t openStatus; + + std::string openMessage; + +private: + volatile bool closed_; + + std::mutex mutex_; + + lws_context *context_; + + std::queue dataQueue_; +}; + +template static void CallbackTemplate(uv_work_t *work, int status) +{ + (void)status; + + auto workWrapper = static_cast(work->data); + napi_env env = workWrapper->env; + auto closeScope = [env](napi_handle_scope scope) { NapiUtils::CloseScope(env, scope); }; + std::unique_ptr scope(NapiUtils::OpenScope(env), closeScope); + + napi_value obj = MakeJsValue(env, workWrapper->data); + + napi_value callback = NapiUtils::GetReference(env, workWrapper->callbackRef); + napi_value argv[1] = {obj}; + if (NapiUtils::GetValueType(env, callback) == napi_function) { + (void)NapiUtils::CallFunction(env, NapiUtils::GetUndefined(env), callback, 1, argv); + } + + delete workWrapper; + delete work; +} + +bool WebSocketExec::ParseUrl(ConnectContext *context, + char *prefix, + size_t prefixLen, + char *address, + size_t addressLen, + char *path, + size_t pathLen, + int *port) +{ + char uri[MAX_URI_LENGTH] = {0}; + if (strcpy_s(uri, MAX_URI_LENGTH, context->url.c_str()) < 0) { + NETSTACK_LOGE("strcpy_s failed"); + return false; + } + const char *tempPrefix = nullptr; + const char *tempAddress = nullptr; + const char *tempPath = nullptr; + (void)lws_parse_uri(uri, &tempPrefix, &tempAddress, port, &tempPath); + if (strcpy_s(prefix, prefixLen, tempPrefix) < 0) { + NETSTACK_LOGE("strcpy_s failed"); + return false; + } + if (strcpy_s(address, addressLen, tempAddress) < 0) { + NETSTACK_LOGE("strcpy_s failed"); + return false; + } + if (strcpy_s(path, pathLen, tempPath) < 0) { + NETSTACK_LOGE("strcpy_s failed"); + return false; + } + return true; +} + +void WebSocketExec::RunService(EventManager *manager) +{ + if (manager == nullptr || manager->GetData() == nullptr) { + NETSTACK_LOGE("RunService para error"); + return; + } + auto userData = reinterpret_cast(manager->GetData()); + lws_context *context = userData->GetContext(); + if (context == nullptr) { + NETSTACK_LOGE("context is null"); + return; + } + while (lws_service(context, 0) >= 0) { + } + lws_context_destroy(context); + userData->SetContext(nullptr); + delete userData; + manager->SetData(nullptr); + NETSTACK_LOGI("websocket end run service"); +} + +int WebSocketExec::RaiseError(EventManager *manager) +{ + OnError(manager, COMMON_ERROR_CODE); + return -1; +} + +int WebSocketExec::HttpDummy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len) +{ + int ret = lws_callback_http_dummy(wsi, reason, user, in, len); + if (ret < 0) { + OnError(reinterpret_cast(user), COMMON_ERROR_CODE); + } + return ret; +} + +int WebSocketExec::LwsCallbackClientAppendHandshakeHeader(lws *wsi, + lws_callback_reasons reason, + void *user, + void *in, + size_t len) +{ + NETSTACK_LOGI("LwsCallbackClientAppendHandshakeHeader"); + auto manager = reinterpret_cast(user); + if (manager->GetData() == nullptr) { + NETSTACK_LOGE("user data is null"); + return RaiseError(manager); + } + auto userData = reinterpret_cast(manager->GetData()); + + auto payload = reinterpret_cast(in); + if (payload == nullptr || (*payload) == nullptr || len == 0) { + NETSTACK_LOGE("header payload is null, do not append header"); + return RaiseError(manager); + } + auto payloadEnd = (*payload) + len; + for (const auto &pair : userData->header) { + std::string name = pair.first + NAME_END; + if (lws_add_http_header_by_name(wsi, reinterpret_cast(name.c_str()), + reinterpret_cast(pair.second.c_str()), + static_cast(strlen(pair.second.c_str())), payload, payloadEnd)) { + NETSTACK_LOGE("add header failed"); + return RaiseError(manager); + } + } + NETSTACK_LOGI("add header OK"); + return HttpDummy(wsi, reason, user, in, len); +} + +int WebSocketExec::LwsCallbackWsPeerInitiatedClose(lws *wsi, + lws_callback_reasons reason, + void *user, + void *in, + size_t len) +{ + NETSTACK_LOGI("LwsCallbackWsPeerInitiatedClose"); + auto manager = reinterpret_cast(user); + if (manager->GetData() == nullptr) { + NETSTACK_LOGE("user data is null"); + return RaiseError(manager); + } + auto userData = reinterpret_cast(manager->GetData()); + + if (in == nullptr || len < sizeof(uint16_t)) { + NETSTACK_LOGI("No close reason"); + userData->Close(LWS_CLOSE_STATUS_NORMAL, ""); + return HttpDummy(wsi, reason, user, in, len); + } + + uint16_t closeStatus = ntohs(*reinterpret_cast(in)); + std::string closeReason; + closeReason.append(reinterpret_cast(in) + sizeof(uint16_t), len - sizeof(uint16_t)); + userData->Close(static_cast(closeStatus), closeReason); + return HttpDummy(wsi, reason, user, in, len); +} + +int WebSocketExec::LwsCallbackClientWritable(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len) +{ + auto manager = reinterpret_cast(user); + if (manager->GetData() == nullptr) { + NETSTACK_LOGE("user data is null"); + return RaiseError(manager); + } + auto userData = reinterpret_cast(manager->GetData()); + + if (userData->IsClosed()) { + NETSTACK_LOGI("need to close"); + lws_close_reason(wsi, userData->closeStatus, + reinterpret_cast(const_cast(userData->closeReason.c_str())), + strlen(userData->closeReason.c_str())); + // here do not emit error, because we close it + return -1; + } + + auto sendData = userData->Pop(); + if (sendData.data == nullptr || sendData.length == 0) { + return HttpDummy(wsi, reason, user, in, len); + } + int sendLength = lws_write(wsi, reinterpret_cast(sendData.data) + LWS_SEND_BUFFER_PRE_PADDING, + sendData.length, sendData.protocol); + free(sendData.data); + NETSTACK_LOGI("send data length = %{public}d", sendLength); + return HttpDummy(wsi, reason, user, in, len); +} + +int WebSocketExec::LwsCallbackClientConnectionError(lws *wsi, + lws_callback_reasons reason, + void *user, + void *in, + size_t len) +{ + NETSTACK_LOGI("LwsCallbackClientConnectionError %{public}s", in == nullptr ? reinterpret_cast(in) : "null"); + return HttpDummy(wsi, reason, user, in, len); +} + +int WebSocketExec::LwsCallbackClientReceive(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len) +{ + + NETSTACK_LOGI("LwsCallbackClientReceive"); + OnMessage(reinterpret_cast(user), in, len, lws_frame_is_binary(wsi)); + return HttpDummy(wsi, reason, user, in, len); +} + +int WebSocketExec::LwsCallbackClientFilterPreEstablish(lws *wsi, + lws_callback_reasons reason, + void *user, + void *in, + size_t len) +{ + NETSTACK_LOGI("LwsCallbackClientFilterPreEstablish"); + auto manager = reinterpret_cast(user); + if (manager->GetData() == nullptr) { + NETSTACK_LOGE("user data is null"); + return RaiseError(manager); + } + auto userData = reinterpret_cast(manager->GetData()); + + userData->openStatus = lws_http_client_http_response(wsi); + char *statusLine = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP); + if (statusLine == nullptr || strlen(statusLine) == 0) { + return HttpDummy(wsi, reason, user, in, len); + } + + auto vec = CommonUtils::Split(statusLine, STATUS_LINE_SEP, STATUS_LINE_ELEM_NUM); + if (vec.size() >= 2) { + userData->openMessage = vec[1]; + } + + return HttpDummy(wsi, reason, user, in, len); +} + +int WebSocketExec::LwsCallbackClientEstablished(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len) +{ + NETSTACK_LOGI("LwsCallbackClientEstablished"); + auto manager = reinterpret_cast(user); + if (manager->GetData() == nullptr) { + NETSTACK_LOGE("user data is null"); + return RaiseError(manager); + } + auto userData = reinterpret_cast(manager->GetData()); + + OnOpen(reinterpret_cast(user), userData->openStatus, userData->openMessage); + return HttpDummy(wsi, reason, user, in, len); +} + +int WebSocketExec::LwsCallbackClientClosed(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len) +{ + NETSTACK_LOGI("LwsCallbackClientClosed"); + auto manager = reinterpret_cast(user); + if (manager->GetData() == nullptr) { + NETSTACK_LOGE("user data is null"); + return RaiseError(manager); + } + auto userData = reinterpret_cast(manager->GetData()); + + OnClose(reinterpret_cast(user), userData->closeStatus, userData->closeReason); + return HttpDummy(wsi, reason, user, in, len); +} + +int WebSocketExec::LwsCallbackWsiDestroy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len) +{ + NETSTACK_LOGI("LwsCallbackWsiDestroy"); + lws_context_destroy(lws_get_context(wsi)); + return HttpDummy(wsi, reason, user, in, len); +} + +int WebSocketExec::LwsCallbackProtocolDestroy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len) +{ + NETSTACK_LOGI("LwsCallbackProtocolDestroy"); + return HttpDummy(wsi, reason, user, in, len); +} + +int WebSocketExec::LwsCallback(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len) +{ + CallbackDispatcher dispatchers[] = { + {LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, LwsCallbackClientAppendHandshakeHeader}, + {LWS_CALLBACK_WS_PEER_INITIATED_CLOSE, LwsCallbackWsPeerInitiatedClose}, + {LWS_CALLBACK_CLIENT_WRITEABLE, LwsCallbackClientWritable}, + {LWS_CALLBACK_CLIENT_CONNECTION_ERROR, LwsCallbackClientConnectionError}, + {LWS_CALLBACK_CLIENT_RECEIVE, LwsCallbackClientReceive}, + {LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH, LwsCallbackClientFilterPreEstablish}, + {LWS_CALLBACK_CLIENT_ESTABLISHED, LwsCallbackClientEstablished}, + {LWS_CALLBACK_CLIENT_CLOSED, LwsCallbackClientClosed}, + {LWS_CALLBACK_WSI_DESTROY, LwsCallbackWsiDestroy}, + {LWS_CALLBACK_PROTOCOL_DESTROY, LwsCallbackProtocolDestroy}, + }; + + for (const auto dispatcher : dispatchers) { + if (dispatcher.reason == reason) { + return dispatcher.callback(wsi, reason, user, in, len); + } + } + + NETSTACK_LOGI("callback reason %{public}d", reason); + return HttpDummy(wsi, reason, user, in, len); +} + +bool WebSocketExec::ExecConnect(ConnectContext *context) +{ + NETSTACK_LOGI("begin connect, parse url"); + char prefix[MAX_URI_LENGTH] = {0}; + char address[MAX_URI_LENGTH] = {0}; + char pathWithoutStart[MAX_URI_LENGTH] = {0}; + std::string path; + if (strlen(pathWithoutStart) != 0) { + path = PATH_START + std::string(pathWithoutStart); + } + int port = 0; + if (!ParseUrl(context, prefix, MAX_URI_LENGTH, address, MAX_URI_LENGTH, pathWithoutStart, MAX_URI_LENGTH, &port)) { + NETSTACK_LOGE("ParseUrl failed"); + return false; + } + + NETSTACK_LOGI("create lws_context_creation_info"); + lws_context_creation_info info = {0}; + info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; + info.port = CONTEXT_PORT_NO_LISTEN; + info.protocols = LWS_PROTOCOLS; + info.fd_limit_per_thread = FD_LIMIT_PER_THREAD; + + NETSTACK_LOGI("create lws_context"); + lws_context *lwsContext = lws_create_context(&info); + if (lwsContext == nullptr) { + NETSTACK_LOGE("no memory"); + return false; + } + + NETSTACK_LOGI("create connectInfo"); + lws_client_connect_info connectInfo = {nullptr}; + connectInfo.context = lwsContext; + connectInfo.port = port; + connectInfo.address = address; + connectInfo.path = path.c_str(); + connectInfo.host = address; + connectInfo.origin = address; + if (strcmp(prefix, PREFIX_HTTPS) == 0 || strcmp(prefix, PREFIX_WSS) == 0) { + connectInfo.ssl_connection = LCCSCF_USE_SSL | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK; + } + lws *wsi = nullptr; + connectInfo.pwsi = &wsi; + connectInfo.retry_and_idle_policy = &RETRY; + auto userData = new UserData(lwsContext); + userData->header = context->header; + auto manager = context->GetManager(); + manager->SetData(userData); + connectInfo.userdata = reinterpret_cast(manager); + if (lws_client_connect_via_info(&connectInfo) == nullptr) { + NETSTACK_LOGI("ExecConnect websocket connect failed"); + context->SetErrorCode(-1); + // here return true, means that connection failed but no error happened during exec + lws_context_destroy(lwsContext); + return true; + } + + NETSTACK_LOGI("start service"); + std::thread serviceThread(RunService, manager); + serviceThread.detach(); + return true; +} + +napi_value WebSocketExec::ConnectCallback(ConnectContext *context) +{ + if (context->GetErrorCode() < 0) { + NETSTACK_LOGI("ConnectCallback connect failed"); + return NapiUtils::GetBoolean(context->GetEnv(), false); + } + NETSTACK_LOGI("ConnectCallback connect success"); + return NapiUtils::GetBoolean(context->GetEnv(), true); +} + +bool WebSocketExec::ExecSend(SendContext *context) +{ + if (context == nullptr || context->GetManager() == nullptr) { + NETSTACK_LOGE("context is null"); + return false; + } + + auto manager = context->GetManager(); + auto userData = reinterpret_cast(manager->GetData()); + if (userData == nullptr) { + NETSTACK_LOGE("user data is null"); + return false; + } + + userData->Push(context->data, context->length, context->protocol); + NETSTACK_LOGI("ExecSend OK"); + return true; +} + +napi_value WebSocketExec::SendCallback(SendContext *context) +{ + NETSTACK_LOGI("SendCallback success"); + return NapiUtils::GetBoolean(context->GetEnv(), true); +} + +bool WebSocketExec::ExecClose(CloseContext *context) +{ + if (context == nullptr || context->GetManager() == nullptr) { + NETSTACK_LOGE("context is null"); + return false; + } + + auto manager = context->GetManager(); + auto userData = reinterpret_cast(manager->GetData()); + if (userData == nullptr) { + NETSTACK_LOGE("user data is null"); + return false; + } + + userData->Close(static_cast(context->code), context->reason); + NETSTACK_LOGI("ExecClose OK"); + return true; +} + +napi_value WebSocketExec::CloseCallback(CloseContext *context) +{ + NETSTACK_LOGI("CloseCallback success"); + return NapiUtils::GetBoolean(context->GetEnv(), true); +} + +static napi_value CreateError(napi_env env, void *callbackPara) +{ + auto code = reinterpret_cast(callbackPara); + auto deleter = [](const int32_t *p) { delete p; }; + std::unique_ptr handler(code, deleter); + napi_value err = NapiUtils::CreateObject(env); + if (NapiUtils::GetValueType(env, err) != napi_object) { + return NapiUtils::GetUndefined(env); + } + NapiUtils::SetInt32Property(env, err, EVENT_KEY_CODE, *code); + return err; +} + +static napi_value CreateOpenPara(napi_env env, void *callbackPara) +{ + auto para = reinterpret_cast(callbackPara); + auto deleter = [](const OnOpenClosePara *p) { delete p; }; + std::unique_ptr handler(para, deleter); + napi_value obj = NapiUtils::CreateObject(env); + if (NapiUtils::GetValueType(env, obj) != napi_object) { + return NapiUtils::GetUndefined(env); + } + NapiUtils::SetUint32Property(env, obj, EVENT_KEY_STATUS, para->status); + NapiUtils::SetStringPropertyUtf8(env, obj, EVENT_KEY_MESSAGE, para->message); + return obj; +} + +static napi_value CreateClosePara(napi_env env, void *callbackPara) +{ + auto para = reinterpret_cast(callbackPara); + auto deleter = [](const OnOpenClosePara *p) { delete p; }; + std::unique_ptr handler(para, deleter); + napi_value obj = NapiUtils::CreateObject(env); + if (NapiUtils::GetValueType(env, obj) != napi_object) { + return NapiUtils::GetUndefined(env); + } + NapiUtils::SetUint32Property(env, obj, EVENT_KEY_CODE, para->status); + NapiUtils::SetStringPropertyUtf8(env, obj, EVENT_KEY_REASON, para->message); + return obj; +} + +static napi_value CreateMessagePara(napi_env env, void *callbackPara) +{ + auto para = reinterpret_cast(callbackPara); + auto deleter = [](const OnMessagePara *p) { delete p; }; + std::unique_ptr handler(para, deleter); + if (!para->isBinary) { + std::string str; + str.append(reinterpret_cast(para->data), para->length); + return NapiUtils::CreateStringUtf8(env, str); + } + + void *data = nullptr; + napi_value arrayBuffer = NapiUtils::CreateArrayBuffer(env, para->length, &data); + if (data != nullptr && NapiUtils::ValueIsArrayBuffer(env, arrayBuffer) && + memcpy_s(data, para->length, para->data, para->length) >= 0) { + return arrayBuffer; + } + return NapiUtils::GetUndefined(env); +} + +void WebSocketExec::OnError(EventManager *manager, int32_t code) +{ + NETSTACK_LOGI("OnError %{public}d", code); + if (manager == nullptr) { + NETSTACK_LOGE("manager is null"); + return; + } + manager->EmitByUv(EventName::EVENT_ERROR, new int32_t(code), CallbackTemplate); +} + +void WebSocketExec::OnOpen(EventManager *manager, uint32_t status, const std::string &message) +{ + NETSTACK_LOGI("OnOpen %{public}u %{public}s", status, message.c_str()); + if (manager == nullptr) { + NETSTACK_LOGE("manager is null"); + return; + } + auto para = new OnOpenClosePara; + para->status = status; + para->message = message; + manager->EmitByUv(EventName::EVENT_OPEN, para, CallbackTemplate); +} + +void WebSocketExec::OnClose(EventManager *manager, lws_close_status closeStatus, const std::string &closeReason) +{ + NETSTACK_LOGI("OnClose %{public}u %{public}s", closeStatus, closeReason.c_str()); + if (manager == nullptr) { + NETSTACK_LOGE("manager is null"); + return; + } + auto para = new OnOpenClosePara; + para->status = closeStatus; + para->message = closeReason; + manager->EmitByUv(EventName::EVENT_CLOSE, para, CallbackTemplate); +} + +void WebSocketExec::OnMessage(EventManager *manager, void *data, size_t length, bool isBinary) +{ + NETSTACK_LOGI("OnMessage %{public}d", isBinary); + if (manager == nullptr) { + NETSTACK_LOGE("manager is null"); + return; + } + auto para = new OnMessagePara; + para->data = malloc(length); + if (para->data == nullptr) { + delete para; + NETSTACK_LOGE("no memory"); + return; + } + if (memcpy_s(para->data, length, data, length) < 0) { + delete para; + NETSTACK_LOGE("mem copy failed"); + return; + } + para->length = length; + para->isBinary = isBinary; + manager->EmitByUv(EventName::EVENT_MESSAGE, para, CallbackTemplate); +} + +} // namespace OHOS::NetStack \ No newline at end of file diff --git a/frameworks/js/napi/websocket/websocket_module/include/websocket_module.h b/frameworks/js/napi/websocket/websocket_module/include/websocket_module.h new file mode 100644 index 000000000..91cda240e --- /dev/null +++ b/frameworks/js/napi/websocket/websocket_module/include/websocket_module.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef COMMUNICATIONNETSTACK_WEBSOCKET_MODULE_H +#define COMMUNICATIONNETSTACK_WEBSOCKET_MODULE_H + +#include "napi/native_api.h" + +namespace OHOS::NetStack { +class WebSocketModule final { +public: + class WebSocket { + public: + static constexpr const char *FUNCTION_CONNECT = "connect"; + static constexpr const char *FUNCTION_SEND = "send"; + static constexpr const char *FUNCTION_CLOSE = "close"; + static constexpr const char *FUNCTION_ON = "on"; + static constexpr const char *FUNCTION_OFF = "off"; + + static napi_value Connect(napi_env env, napi_callback_info info); + + static napi_value Send(napi_env env, napi_callback_info info); + + static napi_value Close(napi_env env, napi_callback_info info); + + static napi_value On(napi_env env, napi_callback_info info); + + static napi_value Off(napi_env env, napi_callback_info info); + }; + + static constexpr const char *FUNCTION_CREATE_WEB_SOCKET = "createWebSocket"; + static constexpr const char *INTERFACE_WEB_SOCKET = "WebSocket"; + + static napi_value InitWebSocketModule(napi_env env, napi_value exports); + +private: + static napi_value CreateWebSocket(napi_env env, napi_callback_info info); + + static void DefineWebSocketClass(napi_env env, napi_value exports); + + static void FinalizeWebSocketInstance(napi_env env, void *data, void *hint); + + static void InitWebSocketProperties(napi_env env, napi_value exports); +}; + +} // namespace OHOS::NetStack + +#endif /* COMMUNICATIONNETSTACK_WEBSOCKET_MODULE_H */ diff --git a/frameworks/js/napi/websocket/websocket_module/src/websocket_module.cpp b/frameworks/js/napi/websocket/websocket_module/src/websocket_module.cpp new file mode 100644 index 000000000..7b67eacd9 --- /dev/null +++ b/frameworks/js/napi/websocket/websocket_module/src/websocket_module.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "websocket_module.h" + +#include "constant.h" +#include "netstack_log.h" +#include "netstack_module_template.h" +#include "websocket_async_work.h" + +namespace OHOS::NetStack { +napi_value WebSocketModule::InitWebSocketModule(napi_env env, napi_value exports) +{ + DefineWebSocketClass(env, exports); + InitWebSocketProperties(env, exports); + + return exports; +} + +napi_value WebSocketModule::CreateWebSocket(napi_env env, napi_callback_info info) +{ + return ModuleTemplate::NewInstance(env, info, INTERFACE_WEB_SOCKET, FinalizeWebSocketInstance); +} + +void WebSocketModule::DefineWebSocketClass(napi_env env, napi_value exports) +{ + std::initializer_list properties = { + DECLARE_NAPI_FUNCTION(WebSocket::FUNCTION_CONNECT, WebSocket::Connect), + DECLARE_NAPI_FUNCTION(WebSocket::FUNCTION_SEND, WebSocket::Send), + DECLARE_NAPI_FUNCTION(WebSocket::FUNCTION_CLOSE, WebSocket::Close), + DECLARE_NAPI_FUNCTION(WebSocket::FUNCTION_ON, WebSocket::On), + DECLARE_NAPI_FUNCTION(WebSocket::FUNCTION_OFF, WebSocket::Off), + }; + ModuleTemplate::DefineClass(env, exports, properties, INTERFACE_WEB_SOCKET); +} + +void WebSocketModule::InitWebSocketProperties(napi_env env, napi_value exports) +{ + std::initializer_list properties = { + DECLARE_NAPI_FUNCTION(FUNCTION_CREATE_WEB_SOCKET, CreateWebSocket), + }; + NapiUtils::DefineProperties(env, exports, properties); +} + +void WebSocketModule::FinalizeWebSocketInstance(napi_env env, void *data, void *hint) +{ + // TODO: 实现WebSocket对象的析构 +} + +napi_value WebSocketModule::WebSocket::Connect(napi_env env, napi_callback_info info) +{ + return ModuleTemplate::Interface( + env, info, "WebSocketConnect", nullptr, WebSocketAsyncWork::ExecConnect, WebSocketAsyncWork::ConnectCallback); +} + +napi_value WebSocketModule::WebSocket::Send(napi_env env, napi_callback_info info) +{ + return ModuleTemplate::Interface(env, info, "WebSocketSend", nullptr, WebSocketAsyncWork::ExecSend, + WebSocketAsyncWork::SendCallback); +} + +napi_value WebSocketModule::WebSocket::Close(napi_env env, napi_callback_info info) +{ + return ModuleTemplate::Interface(env, info, "WebSocketClose", nullptr, WebSocketAsyncWork::ExecClose, + WebSocketAsyncWork::CloseCallback); +} + +napi_value WebSocketModule::WebSocket::On(napi_env env, napi_callback_info info) +{ + ModuleTemplate::On(env, info, {EventName::EVENT_OPEN, EventName::EVENT_MESSAGE, EventName::EVENT_CLOSE}, true); + return ModuleTemplate::On(env, info, {EventName::EVENT_ERROR}, false); +} + +napi_value WebSocketModule::WebSocket::Off(napi_env env, napi_callback_info info) +{ + return ModuleTemplate::Off( + env, info, {EventName::EVENT_OPEN, EventName::EVENT_MESSAGE, EventName::EVENT_CLOSE, EventName::EVENT_ERROR}); +} + +NAPI_MODULE(webSocket, WebSocketModule::InitWebSocketModule) +} // namespace OHOS::NetStack \ No newline at end of file diff --git a/test/napi/websocket/CMakeLists.txt b/test/napi/websocket/CMakeLists.txt new file mode 100644 index 000000000..bc0fba0e0 --- /dev/null +++ b/test/napi/websocket/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2022 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +include_directories(../../../frameworks/js/napi/websocket/async_context/include) +include_directories(../../../frameworks/js/napi/websocket/async_work/include) +include_directories(../../../frameworks/js/napi/websocket/constant/include) +include_directories(../../../frameworks/js/napi/websocket/websocket_exec/include) +include_directories(../../../frameworks/js/napi/websocket/websocket_module/include) +include_directories(../../../../../../third_party/libwebsockets/include) + +link_directories(../../../../../../../third_party/libwebsockets/cmake-build-debug/lib) + +add_executable( + test_napi_websocket_exec + test_napi_exec.cpp + ../../../frameworks/js/napi/websocket/async_context/src/connect_context.cpp + ../../../frameworks/js/napi/websocket/async_context/src/send_context.cpp + ../../../frameworks/js/napi/websocket/async_context/src/close_context.cpp + ../../../frameworks/js/napi/websocket/websocket_module/src/websocket_module.cpp + ../../../frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp + ../../../frameworks/js/napi/websocket/async_work/src/websocket_async_work.cpp + ../../../frameworks/js/napi/websocket/constant/src/constant.cpp +) + +target_link_libraries(test_napi_websocket_exec websockets) +target_link_libraries(test_napi_websocket_exec ace_napi_quickjs) +target_link_libraries(test_napi_websocket_exec quickjs) +target_link_libraries(test_napi_websocket_exec uv) +target_link_libraries(test_napi_websocket_exec securec) +target_link_libraries(test_napi_websocket_exec gtestd) +target_link_libraries(test_napi_websocket_exec gmockd) +target_link_libraries(test_napi_websocket_exec gtest_maind) +target_link_libraries(test_napi_websocket_exec gmock_maind) +target_link_libraries(test_napi_websocket_exec pthread) +target_link_libraries(test_napi_websocket_exec dl) +target_link_libraries(test_napi_websocket_exec nghttp2) +target_link_libraries(test_napi_websocket_exec netstack_utils) + +set(CMAKE_CXX_FLAGS -g) diff --git a/frameworks/js/napi/websocket/src/websocket_napi.cpp b/test/napi/websocket/test_napi_exec.cpp similarity index 75% rename from frameworks/js/napi/websocket/src/websocket_napi.cpp rename to test/napi/websocket/test_napi_exec.cpp index b7327a76f..6898b33db 100644 --- a/frameworks/js/napi/websocket/src/websocket_napi.cpp +++ b/test/napi/websocket/test_napi_exec.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,10 +13,9 @@ * limitations under the License. */ -#include "websocket_napi.h" -#include "netstack_log.h" +#include "test_common.h" -namespace OHOS { -namespace NetStack { -} // namespace NetStack -} // namespace OHOS +int main(int argc, char **argv) +{ + return 0; +} \ No newline at end of file diff --git a/utils/base_context/include/netstack_base_context.h b/utils/base_context/include/netstack_base_context.h index 84f11eb87..4d05cfc47 100644 --- a/utils/base_context/include/netstack_base_context.h +++ b/utils/base_context/include/netstack_base_context.h @@ -74,6 +74,8 @@ public: [[nodiscard]] bool IsNeedPromise() const; + EventManager *GetManager() const; + protected: EventManager *manager_; diff --git a/utils/base_context/src/netstack_base_context.cpp b/utils/base_context/src/netstack_base_context.cpp index b5f999e97..20162d603 100644 --- a/utils/base_context/src/netstack_base_context.cpp +++ b/utils/base_context/src/netstack_base_context.cpp @@ -151,4 +151,9 @@ bool BaseContext::IsNeedPromise() const { return needPromise_; } + +EventManager *BaseContext::GetManager() const +{ + return manager_; +} } // namespace OHOS::NetStack \ No newline at end of file diff --git a/utils/common_utils/include/netstack_common_utils.h b/utils/common_utils/include/netstack_common_utils.h index 353fe6092..7fe078f73 100644 --- a/utils/common_utils/include/netstack_common_utils.h +++ b/utils/common_utils/include/netstack_common_utils.h @@ -22,6 +22,8 @@ namespace OHOS::NetStack::CommonUtils { std::vector Split(const std::string &str, const std::string &sep); +std::vector Split(const std::string &str, const std::string &sep, size_t size); + std::string Strip(const std::string &str, char ch = ' '); std::string ToLower(const std::string &s); diff --git a/utils/common_utils/src/netstack_common_utils.cpp b/utils/common_utils/src/netstack_common_utils.cpp index 8ffe3746d..5e589c41d 100644 --- a/utils/common_utils/src/netstack_common_utils.cpp +++ b/utils/common_utils/src/netstack_common_utils.cpp @@ -34,6 +34,27 @@ std::vector Split(const std::string &str, const std::string &sep) return res; } +std::vector Split(const std::string &str, const std::string &sep, size_t size) +{ + std::string s = str; + std::vector res; + while (!s.empty()) { + if (res.size() + 1 == size) { + res.emplace_back(s); + break; + } + + size_t pos = s.find(sep); + if (pos == std::string::npos) { + res.emplace_back(s); + break; + } + res.emplace_back(s.substr(0, pos)); + s = s.substr(pos + sep.size()); + } + return res; +} + std::string Strip(const std::string &str, char ch) { int64_t i = 0; diff --git a/utils/event_manager/include/netstack_event_listener.h b/utils/event_manager/include/netstack_event_listener.h index 2e929f690..4fed2ea13 100644 --- a/utils/event_manager/include/netstack_event_listener.h +++ b/utils/event_manager/include/netstack_event_listener.h @@ -20,6 +20,7 @@ #include "napi/native_api.h" #include "noncopyable.h" +#include "uv.h" namespace OHOS::NetStack { class EventListener { @@ -42,6 +43,12 @@ public: [[nodiscard]] bool IsAsyncCallback() const; + void EmitByUv(const std::string &type, void *data, void(Handler)(uv_work_t *, int status)) const; + + [[nodiscard]] napi_env GetEnv() const; + + [[nodiscard]] napi_ref GetCallbackRef() const; + private: napi_env env_; @@ -53,6 +60,16 @@ private: bool asyncCallback_; }; + +struct UvWorkWrapper { + UvWorkWrapper() = delete; + + explicit UvWorkWrapper(void *theData, napi_env theEnv, napi_ref theCallbackRef); + + void *data; + napi_env env; + napi_ref callbackRef; +}; } // namespace OHOS::NetStack #endif /* COMMUNICATIONNETSTACK_EVENT_LISTENER_H */ diff --git a/utils/event_manager/include/netstack_event_manager.h b/utils/event_manager/include/netstack_event_manager.h index 51568acdc..fdd55924b 100644 --- a/utils/event_manager/include/netstack_event_manager.h +++ b/utils/event_manager/include/netstack_event_manager.h @@ -36,6 +36,8 @@ public: [[nodiscard]] void *GetData(); + void EmitByUv(const std::string &type, void *data, void(Handler)(uv_work_t *, int status)); + private: std::mutex mutex_; diff --git a/utils/event_manager/src/netstack_event_listener.cpp b/utils/event_manager/src/netstack_event_listener.cpp index 96d738e24..81ea4b691 100644 --- a/utils/event_manager/src/netstack_event_listener.cpp +++ b/utils/event_manager/src/netstack_event_listener.cpp @@ -105,4 +105,32 @@ bool EventListener::IsAsyncCallback() const { return asyncCallback_; } + +void EventListener::EmitByUv(const std::string &type, void *data, void(Handler)(uv_work_t *, int status)) const +{ + if (type_ != type) { + return; + } + + if (callbackRef_ == nullptr) { + return; + } + + NapiUtils::CreateUvQueueWork(env_, data, Handler); +} + +napi_env EventListener::GetEnv() const +{ + return env_; +} + +napi_ref EventListener::GetCallbackRef() const +{ + return callbackRef_; +} + +UvWorkWrapper::UvWorkWrapper(void *theData, napi_env theEnv, napi_ref theCallbackRef) + : data(theData), env(theEnv), callbackRef(theCallbackRef) +{ +} } // namespace OHOS::NetStack diff --git a/utils/event_manager/src/netstack_event_manager.cpp b/utils/event_manager/src/netstack_event_manager.cpp index f531ea66a..21db6fd81 100644 --- a/utils/event_manager/src/netstack_event_manager.cpp +++ b/utils/event_manager/src/netstack_event_manager.cpp @@ -75,4 +75,18 @@ void *EventManager::GetData() std::lock_guard lock(mutex_); return data_; } + +void EventManager::EmitByUv(const std::string &type, void *data, void(Handler)(uv_work_t *, int status)) +{ + std::lock_guard lock(mutex_); + + std::for_each(listeners_.begin(), listeners_.end(), [type, data, Handler](const EventListener &listener) { + auto workWrapper = new UvWorkWrapper(data, listener.GetEnv(), listener.GetCallbackRef()); + listener.EmitByUv(type, workWrapper, Handler); + }); + + auto it = std::remove_if(listeners_.begin(), listeners_.end(), + [type](const EventListener &listener) -> bool { return listener.MatchOnce(type); }); + listeners_.erase(it, listeners_.end()); +} } // namespace OHOS::NetStack \ No newline at end of file diff --git a/utils/log/include/netstack_log.h b/utils/log/include/netstack_log.h index 3d20358cb..4353ff3bc 100644 --- a/utils/log/include/netstack_log.h +++ b/utils/log/include/netstack_log.h @@ -37,8 +37,13 @@ static constexpr OHOS::HiviewDFX::HiLogLabel NETSTACK_LOG_LABEL = {LOG_CORE, NET #else -#include -#include +#ifdef _WIN32 +#undef MAKE_FILE_NAME +#define MAKE_FILE_NAME (strrchr(__FILE__, '\\') + 1) +#endif /* _WIN32 */ + +#include +#include #include "securec.h" diff --git a/utils/napi_utils/include/netstack_napi_utils.h b/utils/napi_utils/include/netstack_napi_utils.h index d8a2beb1c..720eae306 100644 --- a/utils/napi_utils/include/netstack_napi_utils.h +++ b/utils/napi_utils/include/netstack_napi_utils.h @@ -21,6 +21,7 @@ #include "napi/native_api.h" #include "napi/native_common.h" +#include "uv.h" namespace OHOS::NetStack::NapiUtils { napi_valuetype GetValueType(napi_env env, napi_value value); @@ -91,6 +92,8 @@ bool GetBooleanProperty(napi_env env, napi_value object, const std::string &prop void SetBooleanProperty(napi_env env, napi_value object, const std::string &name, bool value); +napi_value GetBoolean(napi_env env, bool value); + /* define properties */ void DefineProperties(napi_env env, napi_value object, @@ -100,6 +103,14 @@ void DefineProperties(napi_env env, napi_value JsonStringify(napi_env env, napi_value object); napi_value JsonParse(napi_env env, napi_value str); + +/* libuv */ +void CreateUvQueueWork(napi_env env, void *data, void(Handler)(uv_work_t *, int status)); + +/* scope */ +napi_handle_scope OpenScope(napi_env env); + +void CloseScope(napi_env env, napi_handle_scope scope); } // namespace OHOS::NetStack::NapiUtils #endif /* COMMUNICATIONNETSTACK_NETSTACK_NAPI_UTILS_H */ diff --git a/utils/napi_utils/src/netstack_napi_utils.cpp b/utils/napi_utils/src/netstack_napi_utils.cpp index cd25ccba4..171c66c53 100644 --- a/utils/napi_utils/src/netstack_napi_utils.cpp +++ b/utils/napi_utils/src/netstack_napi_utils.cpp @@ -298,6 +298,13 @@ void SetBooleanProperty(napi_env env, napi_value object, const std::string &name napi_set_named_property(env, object, name.c_str(), jsValue); } +napi_value GetBoolean(napi_env env, bool value) +{ + napi_value jsValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, value, &jsValue)); + return jsValue; +} + /* define properties */ void DefineProperties(napi_env env, napi_value object, @@ -357,4 +364,30 @@ napi_value JsonParse(napi_env env, napi_value str) NAPI_CALL_BASE(env, napi_call_function(env, json, parse, 1, argv, &res), undefined); return res; } + +/* libuv */ +void CreateUvQueueWork(napi_env env, void *data, void(Handler)(uv_work_t *, int status)) +{ + uv_loop_s *loop = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_get_uv_event_loop(env, &loop)); + + auto work = new uv_work_t; + work->data = data; + + (void)uv_queue_work( + loop, work, [](uv_work_t *) {}, Handler); +} + +/* scope */ +napi_handle_scope OpenScope(napi_env env) +{ + napi_handle_scope scope = nullptr; + NAPI_CALL(env, napi_open_handle_scope(env, &scope)); + return scope; +} + +void CloseScope(napi_env env, napi_handle_scope scope) +{ + (void)napi_close_handle_scope(env, scope); +} } // namespace OHOS::NetStack::NapiUtils \ No newline at end of file -- Gitee From 81e199c11a553690e6a2b2f6515404bc3daed1dc Mon Sep 17 00:00:00 2001 From: maosiping Date: Tue, 29 Mar 2022 13:52:20 +0800 Subject: [PATCH 02/17] support websockets Signed-off-by: maosiping --- test/napi/http/test_napi_exec.cpp | 7 +++- test/napi/websocket/test_napi_exec.cpp | 45 ++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/test/napi/http/test_napi_exec.cpp b/test/napi/http/test_napi_exec.cpp index 97f7cfbe0..2a52751c0 100644 --- a/test/napi/http/test_napi_exec.cpp +++ b/test/napi/http/test_napi_exec.cpp @@ -511,6 +511,10 @@ DEFINE_TEST_BEGIN(TestHttpModuleMethodPostExtraDataArrayBuffer, true) NapiUtils::SetStringPropertyUtf8(env, header, std::string(HttpConstant::HTTP_CONTENT_TYPE), "mine-png"); FILE *fp = fopen("for-post.png", "rb"); + if (fp == nullptr) { + NETSTACK_LOGI("no image to post"); + return; + } fseek(fp, 0L, SEEK_END); long size = ftell(fp); void *buffer = malloc(size); @@ -633,7 +637,8 @@ int main(int argc, char **argv) js_std_add_helpers(ctx, 0, nullptr); - g_nativeEngine = new QuickJSNativeEngine(rt, ctx, nullptr); // default instance id 0 + g_nativeEngine = + reinterpret_cast(new QuickJSNativeEngine(rt, ctx, nullptr)); // default instance id 0 int ret = RUN_ALL_TESTS(); (void)ret; diff --git a/test/napi/websocket/test_napi_exec.cpp b/test/napi/websocket/test_napi_exec.cpp index 6898b33db..439dc1e35 100644 --- a/test/napi/websocket/test_napi_exec.cpp +++ b/test/napi/websocket/test_napi_exec.cpp @@ -15,7 +15,52 @@ #include "test_common.h" +#include "constant.h" +#include "securec.h" +#include "websocket_module.h" + +namespace OHOS::NetStack { +[[maybe_unused]] HWTEST_F(NativeEngineTest, name, testing::ext::TestSize.Level0) +{ + + auto env = (napi_env)engine_; + + napi_value exports = NapiUtils::CreateObject(env); + + WebSocketModule::InitWebSocketModule(env, exports); + napi_value createWebsocket = NapiUtils::GetNamedProperty(env, exports, WebSocketModule::FUNCTION_CREATE_WEB_SOCKET); + + napi_value websocket = NapiUtils::CallFunction(env, exports, createWebsocket, 0, nullptr); + + ASSERT_TRUE(NapiUtils::GetValueType(env, websocket) == napi_object); +} +} // namespace OHOS::NetStack + int main(int argc, char **argv) { + testing::GTEST_FLAG(output) = "xml:./"; + testing::InitGoogleTest(&argc, argv); + + JSRuntime *rt = JS_NewRuntime(); + + if (rt == nullptr) { + return 0; + } + + JSContext *ctx = JS_NewContext(rt); + if (ctx == nullptr) { + return 0; + } + + js_std_add_helpers(ctx, 0, nullptr); + + g_nativeEngine = + reinterpret_cast(new QuickJSNativeEngine(rt, ctx, nullptr)); // default instance id 0 + + int ret = RUN_ALL_TESTS(); + (void)ret; + + g_nativeEngine->Loop(LOOP_DEFAULT); + return 0; } \ No newline at end of file -- Gitee From 350946b133ef698a4ebe966f64e93ebe0ab6e061 Mon Sep 17 00:00:00 2001 From: maosiping Date: Tue, 29 Mar 2022 14:25:46 +0800 Subject: [PATCH 03/17] support websockets Signed-off-by: maosiping --- .../js/napi/websocket/async_context/src/connect_context.cpp | 2 ++ .../js/napi/websocket/async_context/src/send_context.cpp | 2 +- .../js/napi/websocket/websocket_exec/src/websocket_exec.cpp | 5 ++++- test/napi/websocket/CMakeLists.txt | 5 ++++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/frameworks/js/napi/websocket/async_context/src/connect_context.cpp b/frameworks/js/napi/websocket/async_context/src/connect_context.cpp index 92ab32c93..0634be08a 100644 --- a/frameworks/js/napi/websocket/async_context/src/connect_context.cpp +++ b/frameworks/js/napi/websocket/async_context/src/connect_context.cpp @@ -15,6 +15,8 @@ #include "connect_context.h" +#include + #include "constant.h" #include "netstack_common_utils.h" #include "netstack_log.h" diff --git a/frameworks/js/napi/websocket/async_context/src/send_context.cpp b/frameworks/js/napi/websocket/async_context/src/send_context.cpp index c1227a80a..704e2f6ab 100644 --- a/frameworks/js/napi/websocket/async_context/src/send_context.cpp +++ b/frameworks/js/napi/websocket/async_context/src/send_context.cpp @@ -16,9 +16,9 @@ #include "send_context.h" #include "constant.h" -#include "netstack_common_utils.h" #include "netstack_log.h" #include "netstack_napi_utils.h" +#include "securec.h" namespace OHOS::NetStack { SendContext::SendContext(napi_env env, EventManager *manager) diff --git a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp index 5bc33aa89..bbac40941 100644 --- a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp +++ b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp @@ -23,6 +23,7 @@ #include "netstack_common_utils.h" #include "netstack_log.h" #include "netstack_napi_utils.h" +#include "securec.h" // TODO: 调用libwebsockets的API实现 // TODO: 需要实现缓冲区机制 @@ -53,7 +54,9 @@ static constexpr const char *EVENT_KEY_REASON = "reason"; static constexpr const char *EVENT_KEY_MESSAGE = "message"; -char *lws_hdr_simple_ptr(lws *wsi, lws_token_indexes index); +extern "C" { +LWS_VISIBLE LWS_EXTERN char *LWS_WARN_UNUSED_RESULT lws_hdr_simple_ptr(lws *wsi, lws_token_indexes index); +} namespace OHOS::NetStack { static const lws_protocols LWS_PROTOCOLS[] = { diff --git a/test/napi/websocket/CMakeLists.txt b/test/napi/websocket/CMakeLists.txt index bc0fba0e0..2e9877d6b 100644 --- a/test/napi/websocket/CMakeLists.txt +++ b/test/napi/websocket/CMakeLists.txt @@ -17,8 +17,9 @@ include_directories(../../../frameworks/js/napi/websocket/constant/include) include_directories(../../../frameworks/js/napi/websocket/websocket_exec/include) include_directories(../../../frameworks/js/napi/websocket/websocket_module/include) include_directories(../../../../../../third_party/libwebsockets/include) +include_directories(../../../../../../third_party/libwebsockets/cmake-build-debug) -link_directories(../../../../../../../third_party/libwebsockets/cmake-build-debug/lib) +link_directories(../../../../../../third_party/libwebsockets/cmake-build-debug/lib) add_executable( test_napi_websocket_exec @@ -33,6 +34,8 @@ add_executable( ) target_link_libraries(test_napi_websocket_exec websockets) +target_link_libraries(test_napi_websocket_exec crypto) +target_link_libraries(test_napi_websocket_exec ssl) target_link_libraries(test_napi_websocket_exec ace_napi_quickjs) target_link_libraries(test_napi_websocket_exec quickjs) target_link_libraries(test_napi_websocket_exec uv) -- Gitee From 2effb3348bcd0861e20fc9389ce5a2886507c232 Mon Sep 17 00:00:00 2001 From: maosiping Date: Tue, 29 Mar 2022 14:57:55 +0800 Subject: [PATCH 04/17] support websockets Signed-off-by: maosiping --- test/napi/websocket/test_napi_exec.cpp | 93 +++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 2 deletions(-) diff --git a/test/napi/websocket/test_napi_exec.cpp b/test/napi/websocket/test_napi_exec.cpp index 439dc1e35..dbe6d2026 100644 --- a/test/napi/websocket/test_napi_exec.cpp +++ b/test/napi/websocket/test_napi_exec.cpp @@ -20,6 +20,71 @@ #include "websocket_module.h" namespace OHOS::NetStack { +napi_value WEBSOCKET_HANDLE = nullptr; + +int MESSAGE_NUM = 0; + +napi_value ConnectCallback(napi_env env, napi_callback_info info) +{ + napi_value thisVal = nullptr; + size_t paramsCount = 1; + napi_value params[1] = {nullptr}; + NAPI_CALL(env, napi_get_cb_info(env, info, ¶msCount, params, &thisVal, nullptr)); + + bool connected = false; + NAPI_CALL(env, napi_get_value_bool(env, params[0], &connected)); + NETSTACK_LOGI("connected: ? %{public}d", connected); + return NapiUtils::GetUndefined(env); +} + +napi_value SendCallback(napi_env env, napi_callback_info info) +{ + NETSTACK_LOGI("Send OK"); + return NapiUtils::GetUndefined(env); +} + +napi_value OnOpen(napi_env env, napi_callback_info info) +{ + napi_value thisVal = nullptr; + size_t paramsCount = 1; + napi_value params[1] = {nullptr}; + NAPI_CALL(env, napi_get_cb_info(env, info, ¶msCount, params, &thisVal, nullptr)); + + NETSTACK_LOGI("status: %{public}u,", NapiUtils::GetUint32Property(env, params[0], "status")); + NETSTACK_LOGI("message: %{public}s", NapiUtils::GetStringPropertyUtf8(env, params[0], "message").c_str()); + + napi_value send = NapiUtils::GetNamedProperty(env, WEBSOCKET_HANDLE, WebSocketModule::WebSocket::FUNCTION_SEND); + napi_value param[2] = { + NapiUtils::CreateStringUtf8(env, "Hello World"), + NapiUtils::CreateFunction(env, "SendCallback", SendCallback, nullptr), + }; + NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, send, 2, param); + return NapiUtils::GetUndefined(env); +} + +napi_value OnMessage(napi_env env, napi_callback_info info) +{ + napi_value thisVal = nullptr; + size_t paramsCount = 1; + napi_value params[1] = {nullptr}; + NAPI_CALL(env, napi_get_cb_info(env, info, ¶msCount, params, &thisVal, nullptr)); + + ++MESSAGE_NUM; + NETSTACK_LOGI("message: %{public}s", NapiUtils::GetStringFromValueUtf8(env, params[0]).c_str()); + + if (MESSAGE_NUM <= 10) { + return NapiUtils::GetUndefined(env); + } + + napi_value close = NapiUtils::GetNamedProperty(env, WEBSOCKET_HANDLE, WebSocketModule::WebSocket::FUNCTION_CLOSE); + napi_value param[2] = { + NapiUtils::CreateUint32(env, 1000), + NapiUtils::CreateStringUtf8(env, "CLOSE_NORMAL"), + }; + NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, close, 2, param); + return NapiUtils::GetUndefined(env); +} + [[maybe_unused]] HWTEST_F(NativeEngineTest, name, testing::ext::TestSize.Level0) { @@ -30,9 +95,33 @@ namespace OHOS::NetStack { WebSocketModule::InitWebSocketModule(env, exports); napi_value createWebsocket = NapiUtils::GetNamedProperty(env, exports, WebSocketModule::FUNCTION_CREATE_WEB_SOCKET); - napi_value websocket = NapiUtils::CallFunction(env, exports, createWebsocket, 0, nullptr); + if (WEBSOCKET_HANDLE == nullptr) { + WEBSOCKET_HANDLE = NapiUtils::CallFunction(env, exports, createWebsocket, 0, nullptr); + } - ASSERT_TRUE(NapiUtils::GetValueType(env, websocket) == napi_object); + ASSERT_TRUE(NapiUtils::GetValueType(env, WEBSOCKET_HANDLE) == napi_object); + + napi_value connect = + NapiUtils::GetNamedProperty(env, WEBSOCKET_HANDLE, WebSocketModule::WebSocket::FUNCTION_CONNECT); + napi_value param[2] = { + NapiUtils::CreateStringUtf8(env, "wss://x.x.x.x:443/socket"), + NapiUtils::CreateFunction(env, "ConnectCallback", ConnectCallback, nullptr), + }; + NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, connect, 2, param); + + napi_value on = NapiUtils::GetNamedProperty(env, WEBSOCKET_HANDLE, WebSocketModule::WebSocket::FUNCTION_ON); + napi_value onOpenParam[2] = { + NapiUtils::CreateStringUtf8(env, "open"), + NapiUtils::CreateFunction(env, "OnOpen", OnOpen, nullptr), + }; + NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, on, 2, onOpenParam); + + napi_value onMessageParam[2] = { + NapiUtils::CreateStringUtf8(env, "message"), + NapiUtils::CreateFunction(env, "OnMessage", OnMessage, nullptr), + }; + NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, on, 2, onOpenParam); + NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, on, 2, onMessageParam); } } // namespace OHOS::NetStack -- Gitee From 66e03d252ad15011a1dd178e9c8b7b34c7df9ab5 Mon Sep 17 00:00:00 2001 From: maosiping Date: Tue, 29 Mar 2022 18:03:08 +0800 Subject: [PATCH 05/17] support websockets Signed-off-by: maosiping --- .../async_context/src/close_context.cpp | 8 ++--- .../websocket_exec/src/websocket_exec.cpp | 9 +++--- test/napi/log/test_hilog.cpp | 32 ++++++++++--------- test/napi/websocket/CMakeLists.txt | 19 +++++------ test/napi/websocket/test_napi_exec.cpp | 26 +++++++++++---- .../include/netstack_event_listener.h | 2 ++ .../src/netstack_event_listener.cpp | 5 +++ .../src/netstack_event_manager.cpp | 4 +++ .../include/netstack_module_template.h | 4 ++- 9 files changed, 69 insertions(+), 40 deletions(-) diff --git a/frameworks/js/napi/websocket/async_context/src/close_context.cpp b/frameworks/js/napi/websocket/async_context/src/close_context.cpp index 6e78e7466..e3e8c7c3f 100644 --- a/frameworks/js/napi/websocket/async_context/src/close_context.cpp +++ b/frameworks/js/napi/websocket/async_context/src/close_context.cpp @@ -34,12 +34,12 @@ void CloseContext::ParseParams(napi_value *params, size_t paramsCount) } if (paramsCount == FUNCTION_PARAM_ZERO) { - NETSTACK_LOGE("CloseContext Parse OK1"); + NETSTACK_LOGI("CloseContext Parse OK1"); return SetParseOK(true); } if (NapiUtils::GetValueType(GetEnv(), params[0]) == napi_function) { - NETSTACK_LOGE("CloseContext Parse OK2"); + NETSTACK_LOGI("CloseContext Parse OK2"); return SetParseOK(SetCallback(params[0]) == napi_ok); } @@ -50,10 +50,10 @@ void CloseContext::ParseParams(napi_value *params, size_t paramsCount) reason = NapiUtils::GetStringPropertyUtf8(GetEnv(), params[0], ContextKey::REASON); if (paramsCount == FUNCTION_PARAM_TWO) { - NETSTACK_LOGE("CloseContext Parse OK3"); + NETSTACK_LOGI("CloseContext Parse OK3"); return SetParseOK(SetCallback(params[1]) == napi_ok); } - NETSTACK_LOGE("CloseContext Parse OK4"); + NETSTACK_LOGI("CloseContext Parse OK4"); return SetParseOK(true); } diff --git a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp index bbac40941..0b82c6b2d 100644 --- a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp +++ b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp @@ -464,7 +464,6 @@ int WebSocketExec::LwsCallback(lws *wsi, lws_callback_reasons reason, void *user } } - NETSTACK_LOGI("callback reason %{public}d", reason); return HttpDummy(wsi, reason, user, in, len); } @@ -474,15 +473,15 @@ bool WebSocketExec::ExecConnect(ConnectContext *context) char prefix[MAX_URI_LENGTH] = {0}; char address[MAX_URI_LENGTH] = {0}; char pathWithoutStart[MAX_URI_LENGTH] = {0}; - std::string path; - if (strlen(pathWithoutStart) != 0) { - path = PATH_START + std::string(pathWithoutStart); - } int port = 0; if (!ParseUrl(context, prefix, MAX_URI_LENGTH, address, MAX_URI_LENGTH, pathWithoutStart, MAX_URI_LENGTH, &port)) { NETSTACK_LOGE("ParseUrl failed"); return false; } + std::string path; + if (strlen(pathWithoutStart) != 0) { + path = PATH_START + std::string(pathWithoutStart); + } NETSTACK_LOGI("create lws_context_creation_info"); lws_context_creation_info info = {0}; diff --git a/test/napi/log/test_hilog.cpp b/test/napi/log/test_hilog.cpp index 58953bcdf..525977e65 100644 --- a/test/napi/log/test_hilog.cpp +++ b/test/napi/log/test_hilog.cpp @@ -14,6 +14,8 @@ */ #include +#include +#include #include "netstack_log.h" @@ -27,21 +29,21 @@ static void StripFormatString(const std::string &prefix, std::string &str) } } -#define PRINT_LOG(LEVEL) \ - do { \ - std::string newFmt(fmt); \ - StripFormatString("{public}", newFmt); \ - StripFormatString("{private}", newFmt); \ - \ - va_list args; \ - va_start(args, fmt); \ - printf(#LEVEL " "); \ - fflush(stdout); \ - vfprintf(stdout, newFmt.c_str(), args); \ - fflush(stdout); \ - printf("\n"); \ - fflush(stdout); \ - va_end(args); \ +#define PRINT_LOG(LEVEL) \ + do { \ + std::string newFmt(fmt); \ + StripFormatString("{public}", newFmt); \ + StripFormatString("{private}", newFmt); \ + \ + va_list args; \ + va_start(args, fmt); \ + printf(#LEVEL " %d %u ", getpid(), std::std::this_thread::get_id()); \ + fflush(stdout); \ + vfprintf(stdout, newFmt.c_str(), args); \ + fflush(stdout); \ + printf("\n"); \ + fflush(stdout); \ + va_end(args); \ } while (0) int HiLog::Debug(const HiLogLabel &label, const char *fmt, ...) diff --git a/test/napi/websocket/CMakeLists.txt b/test/napi/websocket/CMakeLists.txt index 2e9877d6b..f3ff0656a 100644 --- a/test/napi/websocket/CMakeLists.txt +++ b/test/napi/websocket/CMakeLists.txt @@ -22,15 +22,16 @@ include_directories(../../../../../../third_party/libwebsockets/cmake-build-debu link_directories(../../../../../../third_party/libwebsockets/cmake-build-debug/lib) add_executable( - test_napi_websocket_exec - test_napi_exec.cpp - ../../../frameworks/js/napi/websocket/async_context/src/connect_context.cpp - ../../../frameworks/js/napi/websocket/async_context/src/send_context.cpp - ../../../frameworks/js/napi/websocket/async_context/src/close_context.cpp - ../../../frameworks/js/napi/websocket/websocket_module/src/websocket_module.cpp - ../../../frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp - ../../../frameworks/js/napi/websocket/async_work/src/websocket_async_work.cpp - ../../../frameworks/js/napi/websocket/constant/src/constant.cpp + test_napi_websocket_exec + test_napi_exec.cpp + ../log/test_hilog.cpp + ../../../frameworks/js/napi/websocket/async_context/src/connect_context.cpp + ../../../frameworks/js/napi/websocket/async_context/src/send_context.cpp + ../../../frameworks/js/napi/websocket/async_context/src/close_context.cpp + ../../../frameworks/js/napi/websocket/websocket_module/src/websocket_module.cpp + ../../../frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp + ../../../frameworks/js/napi/websocket/async_work/src/websocket_async_work.cpp + ../../../frameworks/js/napi/websocket/constant/src/constant.cpp ) target_link_libraries(test_napi_websocket_exec websockets) diff --git a/test/napi/websocket/test_napi_exec.cpp b/test/napi/websocket/test_napi_exec.cpp index dbe6d2026..82d40f488 100644 --- a/test/napi/websocket/test_napi_exec.cpp +++ b/test/napi/websocket/test_napi_exec.cpp @@ -73,15 +73,21 @@ napi_value OnMessage(napi_env env, napi_callback_info info) NETSTACK_LOGI("message: %{public}s", NapiUtils::GetStringFromValueUtf8(env, params[0]).c_str()); if (MESSAGE_NUM <= 10) { + napi_value send = NapiUtils::GetNamedProperty(env, WEBSOCKET_HANDLE, WebSocketModule::WebSocket::FUNCTION_SEND); + napi_value param[2] = { + NapiUtils::CreateStringUtf8(env, "Hello World"), + NapiUtils::CreateFunction(env, "SendCallback", SendCallback, nullptr), + }; + NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, send, 1, param); return NapiUtils::GetUndefined(env); } napi_value close = NapiUtils::GetNamedProperty(env, WEBSOCKET_HANDLE, WebSocketModule::WebSocket::FUNCTION_CLOSE); - napi_value param[2] = { - NapiUtils::CreateUint32(env, 1000), - NapiUtils::CreateStringUtf8(env, "CLOSE_NORMAL"), - }; - NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, close, 2, param); + napi_value options = NapiUtils::CreateObject(env); + NapiUtils::SetUint32Property(env, options, "code", 1000); + NapiUtils::SetStringPropertyUtf8(env, options, "reason", "CLOSE_NORMAL"); + napi_value param[1] = {options}; + NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, close, 1, param); return NapiUtils::GetUndefined(env); } @@ -103,8 +109,14 @@ napi_value OnMessage(napi_env env, napi_callback_info info) napi_value connect = NapiUtils::GetNamedProperty(env, WEBSOCKET_HANDLE, WebSocketModule::WebSocket::FUNCTION_CONNECT); - napi_value param[2] = { + napi_value header = NapiUtils::CreateObject(env); + NapiUtils::SetStringPropertyUtf8(env, header, "Name1", "Value1"); + NapiUtils::SetStringPropertyUtf8(env, header, "Name2", "Value2"); + napi_value obj = NapiUtils::CreateObject(env); + NapiUtils::SetNamedProperty(env, obj, "header", header); + napi_value param[3] = { NapiUtils::CreateStringUtf8(env, "wss://x.x.x.x:443/socket"), + obj, NapiUtils::CreateFunction(env, "ConnectCallback", ConnectCallback, nullptr), }; NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, connect, 2, param); @@ -120,6 +132,8 @@ napi_value OnMessage(napi_env env, napi_callback_info info) NapiUtils::CreateStringUtf8(env, "message"), NapiUtils::CreateFunction(env, "OnMessage", OnMessage, nullptr), }; + + // call on("open") more times NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, on, 2, onOpenParam); NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, on, 2, onMessageParam); } diff --git a/utils/event_manager/include/netstack_event_listener.h b/utils/event_manager/include/netstack_event_listener.h index 4fed2ea13..b15663611 100644 --- a/utils/event_manager/include/netstack_event_listener.h +++ b/utils/event_manager/include/netstack_event_listener.h @@ -41,6 +41,8 @@ public: [[nodiscard]] bool MatchOnce(const std::string &type) const; + [[nodiscard]] bool MatchType(const std::string &type) const; + [[nodiscard]] bool IsAsyncCallback() const; void EmitByUv(const std::string &type, void *data, void(Handler)(uv_work_t *, int status)) const; diff --git a/utils/event_manager/src/netstack_event_listener.cpp b/utils/event_manager/src/netstack_event_listener.cpp index 81ea4b691..29455f52a 100644 --- a/utils/event_manager/src/netstack_event_listener.cpp +++ b/utils/event_manager/src/netstack_event_listener.cpp @@ -101,6 +101,11 @@ bool EventListener::MatchOnce(const std::string &type) const return once_; } +bool EventListener::MatchType(const std::string &type) const +{ + return type_ == type; +} + bool EventListener::IsAsyncCallback() const { return asyncCallback_; diff --git a/utils/event_manager/src/netstack_event_manager.cpp b/utils/event_manager/src/netstack_event_manager.cpp index 21db6fd81..e318fcec7 100644 --- a/utils/event_manager/src/netstack_event_manager.cpp +++ b/utils/event_manager/src/netstack_event_manager.cpp @@ -30,6 +30,10 @@ void EventManager::AddListener(napi_env env, bool once, bool asyncCallback) { + auto it = std::remove_if(listeners_.begin(), listeners_.end(), + [type](const EventListener &listener) -> bool { return listener.MatchType(type); }); + listeners_.erase(it, listeners_.end()); + listeners_.emplace_back(EventListener(env, type, callback, once, asyncCallback)); } diff --git a/utils/module_template/include/netstack_module_template.h b/utils/module_template/include/netstack_module_template.h index e101508ab..7248dcbef 100644 --- a/utils/module_template/include/netstack_module_template.h +++ b/utils/module_template/include/netstack_module_template.h @@ -20,6 +20,7 @@ #include "netstack_base_async_work.h" #include "netstack_base_context.h" +#include "netstack_log.h" #define MAX_PARAM_NUM 64 @@ -46,7 +47,7 @@ napi_value Interface(napi_env env, auto context = new Context(env, manager); context->ParseParams(params, paramsCount); - NETSTACK_LOGE("js params parse OK ? %{public}d", context->IsParseOK()); + NETSTACK_LOGI("js params parse OK ? %{public}d", context->IsParseOK()); if (Work != nullptr) { if (!Work(env, thisVal, context)) { NETSTACK_LOGE("work failed error code = %{public}d", context->GetErrorCode()); @@ -55,6 +56,7 @@ napi_value Interface(napi_env env, context->CreateAsyncWork(asyncWorkName, executor, callback); if (NapiUtils::GetValueType(env, context->GetCallback()) != napi_function) { + NETSTACK_LOGI("context->CreatePromise()"); return context->CreatePromise(); } return NapiUtils::GetUndefined(env); -- Gitee From 6d8ea2f13bf4ecb8ca9ebe22bc7f83f44e754132 Mon Sep 17 00:00:00 2001 From: maosiping Date: Wed, 30 Mar 2022 11:16:05 +0800 Subject: [PATCH 06/17] add build.gn Signed-off-by: maosiping --- frameworks/js/napi/BUILD.gn | 28 +++++++++++++++-- .../async_context/src/send_context.cpp | 2 +- .../websocket_exec/src/websocket_exec.cpp | 2 +- test/napi/log/test_hilog.cpp | 30 +++++++++---------- 4 files changed, 43 insertions(+), 19 deletions(-) diff --git a/frameworks/js/napi/BUILD.gn b/frameworks/js/napi/BUILD.gn index 2836e3a66..9d5f6828c 100644 --- a/frameworks/js/napi/BUILD.gn +++ b/frameworks/js/napi/BUILD.gn @@ -137,13 +137,37 @@ ohos_shared_library("socket") { } ohos_shared_library("websocket") { - include_dirs = [ "$NETSTACK_NAPI_ROOT/websocket/include" ] + include_dirs = [ + "websocket/async_context/include", + "websocket/async_work/include", + "websocket/constant/include", + "websocket/websocket_exec/include", + "websocket/websocket_module/include", + ] include_dirs += utils_include include_dirs += common_include + include_dirs += [ + "//third_party/libwebsockets/include", + "//third_party/openssl/include", + ] - sources = [ "$NETSTACK_NAPI_ROOT/websocket/src/websocket_napi.cpp" ] + sources = [ + "websocket/async_context/src/close_context.cpp", + "websocket/async_context/src/connect_context.cpp", + "websocket/async_context/src/send_context.cpp", + "websocket/async_work/src/websocket_async_work.cpp", + "websocket/constant/src/constant.cpp", + "websocket/websocket_exec/src/websocket_exec.cpp", + "websocket/websocket_module/src/websocket_module.cpp", + ] deps = common_deps + deps += [ + "//third_party/libwebsockets:websockets", + "//third_party/openssl:libcrypto_static", + "//third_party/openssl:ssl_source", + "//third_party/zlib:libz", + ] external_deps = common_external_deps diff --git a/frameworks/js/napi/websocket/async_context/src/send_context.cpp b/frameworks/js/napi/websocket/async_context/src/send_context.cpp index 704e2f6ab..59e04a604 100644 --- a/frameworks/js/napi/websocket/async_context/src/send_context.cpp +++ b/frameworks/js/napi/websocket/async_context/src/send_context.cpp @@ -22,7 +22,7 @@ namespace OHOS::NetStack { SendContext::SendContext(napi_env env, EventManager *manager) - : BaseContext(env, manager), data(nullptr), protocol(LWS_WRITE_TEXT), length(0) + : BaseContext(env, manager), data(nullptr), length(0), protocol(LWS_WRITE_TEXT) { } diff --git a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp index 0b82c6b2d..bc591872d 100644 --- a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp +++ b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp @@ -82,7 +82,7 @@ struct OnOpenClosePara { }; struct OnMessagePara { - OnMessagePara() : data(nullptr), isBinary(false), length(0) {} + OnMessagePara() : data(nullptr), length(0), isBinary(false) {} ~OnMessagePara() { if (data != nullptr) { diff --git a/test/napi/log/test_hilog.cpp b/test/napi/log/test_hilog.cpp index 525977e65..dcd7faaad 100644 --- a/test/napi/log/test_hilog.cpp +++ b/test/napi/log/test_hilog.cpp @@ -29,21 +29,21 @@ static void StripFormatString(const std::string &prefix, std::string &str) } } -#define PRINT_LOG(LEVEL) \ - do { \ - std::string newFmt(fmt); \ - StripFormatString("{public}", newFmt); \ - StripFormatString("{private}", newFmt); \ - \ - va_list args; \ - va_start(args, fmt); \ - printf(#LEVEL " %d %u ", getpid(), std::std::this_thread::get_id()); \ - fflush(stdout); \ - vfprintf(stdout, newFmt.c_str(), args); \ - fflush(stdout); \ - printf("\n"); \ - fflush(stdout); \ - va_end(args); \ +#define PRINT_LOG(LEVEL) \ + do { \ + std::string newFmt(fmt); \ + StripFormatString("{public}", newFmt); \ + StripFormatString("{private}", newFmt); \ + \ + va_list args; \ + va_start(args, fmt); \ + printf(#LEVEL " %d %u ", getpid(), std::this_thread::get_id()); \ + fflush(stdout); \ + vfprintf(stdout, newFmt.c_str(), args); \ + fflush(stdout); \ + printf("\n"); \ + fflush(stdout); \ + va_end(args); \ } while (0) int HiLog::Debug(const HiLogLabel &label, const char *fmt, ...) -- Gitee From 002e905e24af4668173630e9d3005aceb188fcb2 Mon Sep 17 00:00:00 2001 From: maosiping Date: Wed, 30 Mar 2022 11:22:14 +0800 Subject: [PATCH 07/17] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E9=A1=BA=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: maosiping --- .../js/napi/websocket/websocket_exec/src/websocket_exec.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp index bc591872d..b00cda981 100644 --- a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp +++ b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp @@ -112,7 +112,7 @@ public: }; explicit UserData(lws_context *context) - : closed_(false), context_(context), closeStatus(LWS_CLOSE_STATUS_NOSTATUS), openStatus(0) + : closeStatus(LWS_CLOSE_STATUS_NOSTATUS), openStatus(0), closed_(false), context_(context) { } -- Gitee From a39b86cfbfa2b3aa37e96ad775848f982b095382 Mon Sep 17 00:00:00 2001 From: maosiping Date: Wed, 30 Mar 2022 11:25:41 +0800 Subject: [PATCH 08/17] =?UTF-8?q?=E4=BF=AE=E6=94=B9build.gn?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: maosiping --- frameworks/js/napi/BUILD.gn | 1 + 1 file changed, 1 insertion(+) diff --git a/frameworks/js/napi/BUILD.gn b/frameworks/js/napi/BUILD.gn index 9d5f6828c..abc6345e5 100644 --- a/frameworks/js/napi/BUILD.gn +++ b/frameworks/js/napi/BUILD.gn @@ -160,6 +160,7 @@ ohos_shared_library("websocket") { "websocket/websocket_exec/src/websocket_exec.cpp", "websocket/websocket_module/src/websocket_module.cpp", ] + sources += utils_source deps = common_deps deps += [ -- Gitee From d0d6d7f5aca7e06f9ae1a67a6790da41982b7833 Mon Sep 17 00:00:00 2001 From: maosiping Date: Wed, 30 Mar 2022 15:32:43 +0800 Subject: [PATCH 09/17] fix some problem Signed-off-by: maosiping --- .../js/napi/websocket/websocket_exec/src/websocket_exec.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp index b00cda981..ba838fd82 100644 --- a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp +++ b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp @@ -362,7 +362,8 @@ int WebSocketExec::LwsCallbackClientConnectionError(lws *wsi, void *in, size_t len) { - NETSTACK_LOGI("LwsCallbackClientConnectionError %{public}s", in == nullptr ? reinterpret_cast(in) : "null"); + NETSTACK_LOGI("LwsCallbackClientConnectionError %{public}s", + (in == nullptr) ? "null" : reinterpret_cast(in)); return HttpDummy(wsi, reason, user, in, len); } -- Gitee From 8c5e325f2c614d63d90b51dd23baf5655433f5e5 Mon Sep 17 00:00:00 2001 From: maosiping Date: Thu, 31 Mar 2022 10:00:05 +0800 Subject: [PATCH 10/17] use ssl Signed-off-by: maosiping --- .../js/napi/websocket/websocket_exec/src/websocket_exec.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp index ba838fd82..9e3c03b24 100644 --- a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp +++ b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp @@ -507,7 +507,8 @@ bool WebSocketExec::ExecConnect(ConnectContext *context) connectInfo.host = address; connectInfo.origin = address; if (strcmp(prefix, PREFIX_HTTPS) == 0 || strcmp(prefix, PREFIX_WSS) == 0) { - connectInfo.ssl_connection = LCCSCF_USE_SSL | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK; + connectInfo.ssl_connection = + LCCSCF_USE_SSL | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK | LCCSCF_ALLOW_INSECURE | LCCSCF_ALLOW_SELFSIGNED; } lws *wsi = nullptr; connectInfo.pwsi = &wsi; -- Gitee From 251db560ffee274e6355c6950c4bf6d342dbb6f6 Mon Sep 17 00:00:00 2001 From: maosiping Date: Thu, 31 Mar 2022 10:47:09 +0800 Subject: [PATCH 11/17] =?UTF-8?q?=E8=A7=A6=E5=8F=91=E5=9B=9E=E8=B0=83?= =?UTF-8?q?=E6=97=B6=E5=85=88=E5=88=A4=E6=96=AD=E6=9C=89=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E7=9B=91=E5=90=AC=E8=AF=A5=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: maosiping --- .../websocket_exec/src/websocket_exec.cpp | 16 ++++++++++++++++ .../include/netstack_event_manager.h | 2 ++ .../event_manager/src/netstack_event_manager.cpp | 8 ++++++++ 3 files changed, 26 insertions(+) diff --git a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp index 9e3c03b24..18ec35008 100644 --- a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp +++ b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp @@ -660,6 +660,10 @@ void WebSocketExec::OnError(EventManager *manager, int32_t code) NETSTACK_LOGE("manager is null"); return; } + if (!manager->HasEventListener(EventName::EVENT_ERROR)) { + NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_ERROR); + return; + } manager->EmitByUv(EventName::EVENT_ERROR, new int32_t(code), CallbackTemplate); } @@ -670,6 +674,10 @@ void WebSocketExec::OnOpen(EventManager *manager, uint32_t status, const std::st NETSTACK_LOGE("manager is null"); return; } + if (!manager->HasEventListener(EventName::EVENT_OPEN)) { + NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_OPEN); + return; + } auto para = new OnOpenClosePara; para->status = status; para->message = message; @@ -683,6 +691,10 @@ void WebSocketExec::OnClose(EventManager *manager, lws_close_status closeStatus, NETSTACK_LOGE("manager is null"); return; } + if (!manager->HasEventListener(EventName::EVENT_CLOSE)) { + NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_CLOSE); + return; + } auto para = new OnOpenClosePara; para->status = closeStatus; para->message = closeReason; @@ -696,6 +708,10 @@ void WebSocketExec::OnMessage(EventManager *manager, void *data, size_t length, NETSTACK_LOGE("manager is null"); return; } + if (!manager->HasEventListener(EventName::EVENT_MESSAGE)) { + NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_MESSAGE); + return; + } auto para = new OnMessagePara; para->data = malloc(length); if (para->data == nullptr) { diff --git a/utils/event_manager/include/netstack_event_manager.h b/utils/event_manager/include/netstack_event_manager.h index fdd55924b..c421f5f44 100644 --- a/utils/event_manager/include/netstack_event_manager.h +++ b/utils/event_manager/include/netstack_event_manager.h @@ -38,6 +38,8 @@ public: void EmitByUv(const std::string &type, void *data, void(Handler)(uv_work_t *, int status)); + bool HasEventListener(const std::string &type); + private: std::mutex mutex_; diff --git a/utils/event_manager/src/netstack_event_manager.cpp b/utils/event_manager/src/netstack_event_manager.cpp index e318fcec7..e7f440dbb 100644 --- a/utils/event_manager/src/netstack_event_manager.cpp +++ b/utils/event_manager/src/netstack_event_manager.cpp @@ -93,4 +93,12 @@ void EventManager::EmitByUv(const std::string &type, void *data, void(Handler)(u [type](const EventListener &listener) -> bool { return listener.MatchOnce(type); }); listeners_.erase(it, listeners_.end()); } + +bool EventManager::HasEventListener(const std::string &type) +{ + std::lock_guard lock(mutex_); + + return std::ranges::any_of(listeners_.begin(), listeners_.end(), + [&type](const EventListener &listener) -> bool { return listener.MatchType(type); }); +} } // namespace OHOS::NetStack \ No newline at end of file -- Gitee From 4d098c665bdb83505512d5d4934a259271d1d7cd Mon Sep 17 00:00:00 2001 From: maosiping Date: Thu, 31 Mar 2022 10:52:58 +0800 Subject: [PATCH 12/17] use std::any_of Signed-off-by: maosiping --- utils/event_manager/src/netstack_event_manager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/event_manager/src/netstack_event_manager.cpp b/utils/event_manager/src/netstack_event_manager.cpp index e7f440dbb..e77f85a41 100644 --- a/utils/event_manager/src/netstack_event_manager.cpp +++ b/utils/event_manager/src/netstack_event_manager.cpp @@ -98,7 +98,7 @@ bool EventManager::HasEventListener(const std::string &type) { std::lock_guard lock(mutex_); - return std::ranges::any_of(listeners_.begin(), listeners_.end(), - [&type](const EventListener &listener) -> bool { return listener.MatchType(type); }); + return std::any_of(listeners_.begin(), listeners_.end(), + [&type](const EventListener &listener) -> bool { return listener.MatchType(type); }); } } // namespace OHOS::NetStack \ No newline at end of file -- Gitee From 6ff3375f9073992050def695024da0c1f69a7735 Mon Sep 17 00:00:00 2001 From: maosiping Date: Thu, 31 Mar 2022 12:07:25 +0800 Subject: [PATCH 13/17] =?UTF-8?q?=E8=8E=B7=E5=8F=96=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E5=A4=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: maosiping --- .../websocket/websocket_exec/src/websocket_exec.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp index 18ec35008..c97fd546a 100644 --- a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp +++ b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp @@ -42,6 +42,8 @@ static constexpr const char *PREFIX_WSS = "wss"; static constexpr const int MAX_URI_LENGTH = 1024; +static constexpr const int MAX_HDR_LENGTH = 1024; + static constexpr const int FD_LIMIT_PER_THREAD = 1 + 1 + 1; static constexpr const int COMMON_ERROR_CODE = 200; @@ -54,10 +56,6 @@ static constexpr const char *EVENT_KEY_REASON = "reason"; static constexpr const char *EVENT_KEY_MESSAGE = "message"; -extern "C" { -LWS_VISIBLE LWS_EXTERN char *LWS_WARN_UNUSED_RESULT lws_hdr_simple_ptr(lws *wsi, lws_token_indexes index); -} - namespace OHOS::NetStack { static const lws_protocols LWS_PROTOCOLS[] = { {"lws-minimal-client", WebSocketExec::LwsCallback, 0, 0}, @@ -390,8 +388,8 @@ int WebSocketExec::LwsCallbackClientFilterPreEstablish(lws *wsi, auto userData = reinterpret_cast(manager->GetData()); userData->openStatus = lws_http_client_http_response(wsi); - char *statusLine = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP); - if (statusLine == nullptr || strlen(statusLine) == 0) { + char statusLine[MAX_HDR_LENGTH] = {0}; + if (lws_hdr_copy(wsi, statusLine, MAX_HDR_LENGTH, WSI_TOKEN_HTTP) || strlen(statusLine) == 0) { return HttpDummy(wsi, reason, user, in, len); } -- Gitee From 5350f165303b1da99651ef7c921ea85bbc6129d5 Mon Sep 17 00:00:00 2001 From: maosiping Date: Thu, 31 Mar 2022 14:26:14 +0800 Subject: [PATCH 14/17] fix codex Signed-off-by: maosiping --- .../napi/websocket/async_context/src/connect_context.cpp | 6 ++---- .../napi/websocket/websocket_exec/src/websocket_exec.cpp | 5 +---- .../websocket/websocket_module/include/websocket_module.h | 2 -- test/napi/http/test_napi_exec.cpp | 7 +------ utils/event_manager/src/netstack_event_manager.cpp | 2 -- 5 files changed, 4 insertions(+), 18 deletions(-) diff --git a/frameworks/js/napi/websocket/async_context/src/connect_context.cpp b/frameworks/js/napi/websocket/async_context/src/connect_context.cpp index 0634be08a..4f4c758dd 100644 --- a/frameworks/js/napi/websocket/async_context/src/connect_context.cpp +++ b/frameworks/js/napi/websocket/async_context/src/connect_context.cpp @@ -15,8 +15,6 @@ #include "connect_context.h" -#include - #include "constant.h" #include "netstack_common_utils.h" #include "netstack_log.h" @@ -51,7 +49,7 @@ void ConnectContext::ParseParams(napi_value *params, size_t paramsCount) if (paramsCount == FUNCTION_PARAM_THREE) { NETSTACK_LOGI("ConnectContext paramsCount == FUNCTION_PARAM_THREE"); - return SetParseOK(SetCallback(params[2]) == napi_ok); + return SetParseOK(SetCallback(params[FUNCTION_PARAM_TWO]) == napi_ok); } return SetParseOK(true); } @@ -90,7 +88,7 @@ bool ConnectContext::CheckParamsType(napi_value *params, size_t paramsCount) if (paramsCount == FUNCTION_PARAM_THREE) { return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string && NapiUtils::GetValueType(GetEnv(), params[1]) == napi_object && - NapiUtils::GetValueType(GetEnv(), params[2]) == napi_function; + NapiUtils::GetValueType(GetEnv(), params[FUNCTION_PARAM_TWO]) == napi_function; } return false; diff --git a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp index c97fd546a..d6c5efdc1 100644 --- a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp +++ b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp @@ -333,7 +333,6 @@ int WebSocketExec::LwsCallbackClientWritable(lws *wsi, lws_callback_reasons reas return RaiseError(manager); } auto userData = reinterpret_cast(manager->GetData()); - if (userData->IsClosed()) { NETSTACK_LOGI("need to close"); lws_close_reason(wsi, userData->closeStatus, @@ -367,7 +366,6 @@ int WebSocketExec::LwsCallbackClientConnectionError(lws *wsi, int WebSocketExec::LwsCallbackClientReceive(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len) { - NETSTACK_LOGI("LwsCallbackClientReceive"); OnMessage(reinterpret_cast(user), in, len, lws_frame_is_binary(wsi)); return HttpDummy(wsi, reason, user, in, len); @@ -394,7 +392,7 @@ int WebSocketExec::LwsCallbackClientFilterPreEstablish(lws *wsi, } auto vec = CommonUtils::Split(statusLine, STATUS_LINE_SEP, STATUS_LINE_ELEM_NUM); - if (vec.size() >= 2) { + if (vec.size() >= FUNCTION_PARAM_TWO) { userData->openMessage = vec[1]; } @@ -726,5 +724,4 @@ void WebSocketExec::OnMessage(EventManager *manager, void *data, size_t length, para->isBinary = isBinary; manager->EmitByUv(EventName::EVENT_MESSAGE, para, CallbackTemplate); } - } // namespace OHOS::NetStack \ No newline at end of file diff --git a/frameworks/js/napi/websocket/websocket_module/include/websocket_module.h b/frameworks/js/napi/websocket/websocket_module/include/websocket_module.h index 91cda240e..63484e596 100644 --- a/frameworks/js/napi/websocket/websocket_module/include/websocket_module.h +++ b/frameworks/js/napi/websocket/websocket_module/include/websocket_module.h @@ -54,7 +54,5 @@ private: static void InitWebSocketProperties(napi_env env, napi_value exports); }; - } // namespace OHOS::NetStack - #endif /* COMMUNICATIONNETSTACK_WEBSOCKET_MODULE_H */ diff --git a/test/napi/http/test_napi_exec.cpp b/test/napi/http/test_napi_exec.cpp index 2a52751c0..97f7cfbe0 100644 --- a/test/napi/http/test_napi_exec.cpp +++ b/test/napi/http/test_napi_exec.cpp @@ -511,10 +511,6 @@ DEFINE_TEST_BEGIN(TestHttpModuleMethodPostExtraDataArrayBuffer, true) NapiUtils::SetStringPropertyUtf8(env, header, std::string(HttpConstant::HTTP_CONTENT_TYPE), "mine-png"); FILE *fp = fopen("for-post.png", "rb"); - if (fp == nullptr) { - NETSTACK_LOGI("no image to post"); - return; - } fseek(fp, 0L, SEEK_END); long size = ftell(fp); void *buffer = malloc(size); @@ -637,8 +633,7 @@ int main(int argc, char **argv) js_std_add_helpers(ctx, 0, nullptr); - g_nativeEngine = - reinterpret_cast(new QuickJSNativeEngine(rt, ctx, nullptr)); // default instance id 0 + g_nativeEngine = new QuickJSNativeEngine(rt, ctx, nullptr); // default instance id 0 int ret = RUN_ALL_TESTS(); (void)ret; diff --git a/utils/event_manager/src/netstack_event_manager.cpp b/utils/event_manager/src/netstack_event_manager.cpp index e77f85a41..8c05ef26b 100644 --- a/utils/event_manager/src/netstack_event_manager.cpp +++ b/utils/event_manager/src/netstack_event_manager.cpp @@ -15,8 +15,6 @@ #include "netstack_event_manager.h" -#include - namespace OHOS::NetStack { static constexpr const int CALLBACK_PARAM_NUM = 1; -- Gitee From cd0939f9cc25aa4040556bfd766599037e2b0565 Mon Sep 17 00:00:00 2001 From: maosiping Date: Thu, 31 Mar 2022 14:48:20 +0800 Subject: [PATCH 15/17] fix codex Signed-off-by: maosiping --- .../websocket_exec/src/websocket_exec.cpp | 27 ++++++++++--------- .../websocket_module/src/websocket_module.cpp | 2 +- test/napi/websocket/test_napi_exec.cpp | 24 ++++++++--------- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp index d6c5efdc1..f2af397e6 100644 --- a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp +++ b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp @@ -25,9 +25,6 @@ #include "netstack_napi_utils.h" #include "securec.h" -// TODO: 调用libwebsockets的API实现 -// TODO: 需要实现缓冲区机制 - static constexpr const char *PATH_START = "/"; static constexpr const char *NAME_END = ":"; @@ -464,6 +461,14 @@ int WebSocketExec::LwsCallback(lws *wsi, lws_callback_reasons reason, void *user return HttpDummy(wsi, reason, user, in, len); } +static inline void FillContextInfo(lws_context_creation_info &info) +{ + info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; + info.port = CONTEXT_PORT_NO_LISTEN; + info.protocols = LWS_PROTOCOLS; + info.fd_limit_per_thread = FD_LIMIT_PER_THREAD; +} + bool WebSocketExec::ExecConnect(ConnectContext *context) { NETSTACK_LOGI("begin connect, parse url"); @@ -475,19 +480,11 @@ bool WebSocketExec::ExecConnect(ConnectContext *context) NETSTACK_LOGE("ParseUrl failed"); return false; } - std::string path; - if (strlen(pathWithoutStart) != 0) { - path = PATH_START + std::string(pathWithoutStart); - } + std::string path = PATH_START + std::string(pathWithoutStart); NETSTACK_LOGI("create lws_context_creation_info"); lws_context_creation_info info = {0}; - info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; - info.port = CONTEXT_PORT_NO_LISTEN; - info.protocols = LWS_PROTOCOLS; - info.fd_limit_per_thread = FD_LIMIT_PER_THREAD; - - NETSTACK_LOGI("create lws_context"); + FillContextInfo(info); lws_context *lwsContext = lws_create_context(&info); if (lwsContext == nullptr) { NETSTACK_LOGE("no memory"); @@ -708,6 +705,10 @@ void WebSocketExec::OnMessage(EventManager *manager, void *data, size_t length, NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_MESSAGE); return; } + if (length > INT32_MAX) { + NETSTACK_LOGE("data length too long"); + return; + } auto para = new OnMessagePara; para->data = malloc(length); if (para->data == nullptr) { diff --git a/frameworks/js/napi/websocket/websocket_module/src/websocket_module.cpp b/frameworks/js/napi/websocket/websocket_module/src/websocket_module.cpp index 7b67eacd9..44b153d98 100644 --- a/frameworks/js/napi/websocket/websocket_module/src/websocket_module.cpp +++ b/frameworks/js/napi/websocket/websocket_module/src/websocket_module.cpp @@ -56,7 +56,7 @@ void WebSocketModule::InitWebSocketProperties(napi_env env, napi_value exports) void WebSocketModule::FinalizeWebSocketInstance(napi_env env, void *data, void *hint) { - // TODO: 实现WebSocket对象的析构 + NETSTACK_LOGI("websocket handle is finalized"); } napi_value WebSocketModule::WebSocket::Connect(napi_env env, napi_callback_info info) diff --git a/test/napi/websocket/test_napi_exec.cpp b/test/napi/websocket/test_napi_exec.cpp index 82d40f488..f322170af 100644 --- a/test/napi/websocket/test_napi_exec.cpp +++ b/test/napi/websocket/test_napi_exec.cpp @@ -54,11 +54,11 @@ napi_value OnOpen(napi_env env, napi_callback_info info) NETSTACK_LOGI("message: %{public}s", NapiUtils::GetStringPropertyUtf8(env, params[0], "message").c_str()); napi_value send = NapiUtils::GetNamedProperty(env, WEBSOCKET_HANDLE, WebSocketModule::WebSocket::FUNCTION_SEND); - napi_value param[2] = { + napi_value param[FUNCTION_PARAM_TWO] = { NapiUtils::CreateStringUtf8(env, "Hello World"), NapiUtils::CreateFunction(env, "SendCallback", SendCallback, nullptr), }; - NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, send, 2, param); + NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, send, FUNCTION_PARAM_TWO, param); return NapiUtils::GetUndefined(env); } @@ -74,7 +74,7 @@ napi_value OnMessage(napi_env env, napi_callback_info info) if (MESSAGE_NUM <= 10) { napi_value send = NapiUtils::GetNamedProperty(env, WEBSOCKET_HANDLE, WebSocketModule::WebSocket::FUNCTION_SEND); - napi_value param[2] = { + napi_value param[FUNCTION_PARAM_TWO] = { NapiUtils::CreateStringUtf8(env, "Hello World"), NapiUtils::CreateFunction(env, "SendCallback", SendCallback, nullptr), }; @@ -84,7 +84,7 @@ napi_value OnMessage(napi_env env, napi_callback_info info) napi_value close = NapiUtils::GetNamedProperty(env, WEBSOCKET_HANDLE, WebSocketModule::WebSocket::FUNCTION_CLOSE); napi_value options = NapiUtils::CreateObject(env); - NapiUtils::SetUint32Property(env, options, "code", 1000); + NapiUtils::SetUint32Property(env, options, "code", CLOSE_REASON_NORMAL_CLOSE); NapiUtils::SetStringPropertyUtf8(env, options, "reason", "CLOSE_NORMAL"); napi_value param[1] = {options}; NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, close, 1, param); @@ -93,9 +93,7 @@ napi_value OnMessage(napi_env env, napi_callback_info info) [[maybe_unused]] HWTEST_F(NativeEngineTest, name, testing::ext::TestSize.Level0) { - auto env = (napi_env)engine_; - napi_value exports = NapiUtils::CreateObject(env); WebSocketModule::InitWebSocketModule(env, exports); @@ -114,28 +112,28 @@ napi_value OnMessage(napi_env env, napi_callback_info info) NapiUtils::SetStringPropertyUtf8(env, header, "Name2", "Value2"); napi_value obj = NapiUtils::CreateObject(env); NapiUtils::SetNamedProperty(env, obj, "header", header); - napi_value param[3] = { + napi_value param[FUNCTION_PARAM_THREE] = { NapiUtils::CreateStringUtf8(env, "wss://x.x.x.x:443/socket"), obj, NapiUtils::CreateFunction(env, "ConnectCallback", ConnectCallback, nullptr), }; - NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, connect, 2, param); + NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, connect, FUNCTION_PARAM_TWO, param); napi_value on = NapiUtils::GetNamedProperty(env, WEBSOCKET_HANDLE, WebSocketModule::WebSocket::FUNCTION_ON); - napi_value onOpenParam[2] = { + napi_value onOpenParam[FUNCTION_PARAM_TWO] = { NapiUtils::CreateStringUtf8(env, "open"), NapiUtils::CreateFunction(env, "OnOpen", OnOpen, nullptr), }; - NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, on, 2, onOpenParam); + NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, on, FUNCTION_PARAM_TWO, onOpenParam); - napi_value onMessageParam[2] = { + napi_value onMessageParam[FUNCTION_PARAM_TWO] = { NapiUtils::CreateStringUtf8(env, "message"), NapiUtils::CreateFunction(env, "OnMessage", OnMessage, nullptr), }; // call on("open") more times - NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, on, 2, onOpenParam); - NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, on, 2, onMessageParam); + NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, on, FUNCTION_PARAM_TWO, onOpenParam); + NapiUtils::CallFunction(env, WEBSOCKET_HANDLE, on, FUNCTION_PARAM_TWO, onMessageParam); } } // namespace OHOS::NetStack -- Gitee From 0c1429fd598794b89902a94c0ab08fc88fee09d5 Mon Sep 17 00:00:00 2001 From: maosiping Date: Thu, 31 Mar 2022 15:05:04 +0800 Subject: [PATCH 16/17] fix codex Signed-off-by: maosiping --- test/napi/websocket/test_napi_exec.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/napi/websocket/test_napi_exec.cpp b/test/napi/websocket/test_napi_exec.cpp index f322170af..9f2810ba2 100644 --- a/test/napi/websocket/test_napi_exec.cpp +++ b/test/napi/websocket/test_napi_exec.cpp @@ -62,6 +62,8 @@ napi_value OnOpen(napi_env env, napi_callback_info info) return NapiUtils::GetUndefined(env); } +static constexpr const int MAX_MESSAGE_NUM = 10; + napi_value OnMessage(napi_env env, napi_callback_info info) { napi_value thisVal = nullptr; @@ -72,7 +74,7 @@ napi_value OnMessage(napi_env env, napi_callback_info info) ++MESSAGE_NUM; NETSTACK_LOGI("message: %{public}s", NapiUtils::GetStringFromValueUtf8(env, params[0]).c_str()); - if (MESSAGE_NUM <= 10) { + if (MESSAGE_NUM <= MAX_MESSAGE_NUM) { napi_value send = NapiUtils::GetNamedProperty(env, WEBSOCKET_HANDLE, WebSocketModule::WebSocket::FUNCTION_SEND); napi_value param[FUNCTION_PARAM_TWO] = { NapiUtils::CreateStringUtf8(env, "Hello World"), -- Gitee From 660ab996579d3fb89eb6a949b6b1c30622fea803 Mon Sep 17 00:00:00 2001 From: maosiping Date: Fri, 1 Apr 2022 14:44:59 +0800 Subject: [PATCH 17/17] support json object Signed-off-by: maosiping --- .../napi/http/async_context/src/request_context.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/frameworks/js/napi/http/async_context/src/request_context.cpp b/frameworks/js/napi/http/async_context/src/request_context.cpp index 9958dccc5..7ff2a53d7 100644 --- a/frameworks/js/napi/http/async_context/src/request_context.cpp +++ b/frameworks/js/napi/http/async_context/src/request_context.cpp @@ -212,7 +212,16 @@ bool RequestContext::GetRequestBody(napi_value extraData) return true; } - NETSTACK_LOGE("Body do not support Object, because napi do not support json stringify for now"); + if (type == napi_object) { + std::string body = NapiUtils::GetStringFromValueUtf8(GetEnv(), NapiUtils::JsonStringify(GetEnv(), extraData)); + if (body.empty()) { + return false; + } + options.SetBody(body.c_str(), body.length()); + return true; + } + + NETSTACK_LOGE("only support string arraybuffer and object"); return false; } -- Gitee