1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "ws_server.h"
17
18#include <fstream>
19#include <iostream>
20#include <shared_mutex>
21#include <sys/types.h>
22#include <unistd.h>
23
24#include "common/log_wrapper.h"
25#include "websocket/server/websocket_server.h"
26
27namespace OHOS::ArkCompiler::Toolchain {
28std::shared_mutex g_mutex;
29
30// defined in .cpp file for WebSocketServer forward declaration
31WsServer::WsServer(const DebugInfo& debugInfo, const std::function<void(std::string&&)>& onMessage)
32    : debugInfo_(debugInfo), wsOnMessage_(onMessage)
33{}
34
35WsServer::~WsServer() = default;
36
37void WsServer::RunServer()
38{
39    {
40        std::lock_guard<std::mutex> lock(wsMutex_);
41        if (terminateExecution_) {
42            LOGE("WsServer has been terminated unexpectedly");
43            return;
44        }
45        webSocket_ = std::make_unique<WebSocketServer>();
46#if !defined(OHOS_PLATFORM)
47        LOGI("WsSever Runsever: Init tcp websocket %{public}d", debugInfo_.port);
48        if (!webSocket_->InitTcpWebSocket(debugInfo_.port)) {
49            return;
50        }
51#else
52        int runSeverInOldProcess = -2;
53        if (debugInfo_.socketfd == runSeverInOldProcess) {
54            int appPid = getprocpid();
55            std::string pidStr = std::to_string(appPid);
56            std::string instanceIdStr("");
57
58            if (debugInfo_.instanceId != 0) {
59                instanceIdStr = std::to_string(debugInfo_.instanceId);
60            }
61            std::string sockName = pidStr + instanceIdStr + debugInfo_.componentName;
62            LOGI("WsServer RunServer fport localabstract: %{public}d%{public}s%{public}s",
63                appPid, instanceIdStr.c_str(), debugInfo_.componentName.c_str());
64            if (!webSocket_->InitUnixWebSocket(sockName)) {
65                return;
66            }
67        } else {
68            LOGI("WsServer RunServer fport ark: %{public}d", debugInfo_.socketfd);
69            if (!webSocket_->InitUnixWebSocket(debugInfo_.socketfd)) {
70                return;
71            }
72        }
73#endif
74    }
75    ContinueRunserver();
76}
77void WsServer::ContinueRunserver()
78{
79    while (!terminateExecution_) {
80#if !defined(OHOS_PLATFORM)
81        if (!webSocket_->AcceptNewConnection()) {
82            return;
83        }
84#else
85        int runSeverInOldProcess = -2;
86        if (debugInfo_.socketfd == runSeverInOldProcess) {
87            if (!webSocket_->AcceptNewConnection()) {
88                return;
89            }
90        } else {
91            if (!webSocket_->ConnectUnixWebSocketBySocketpair()) {
92                return;
93            }
94        }
95#endif
96        while (webSocket_->IsConnected()) {
97            std::string message = webSocket_->Decode();
98            if (!message.empty() && webSocket_->IsDecodeDisconnectMsg(message)) {
99                LOGI("WsServer receiving disconnect msg: %{public}s", message.c_str());
100                NotifyDisconnectEvent();
101            } else if (!message.empty()) {
102                LOGI("WsServer OnMessage: %{public}s", message.c_str());
103                wsOnMessage_(std::move(message));
104            }
105        }
106    }
107}
108
109void WsServer::StopServer()
110{
111    LOGI("WsServer StopServer");
112    {
113        std::lock_guard<std::mutex> lock(wsMutex_);
114        terminateExecution_ = true;
115        if (webSocket_ != nullptr) {
116            webSocket_->Close();
117        }
118    }
119    pthread_join(tid_, nullptr);
120    if (webSocket_ != nullptr) {
121        webSocket_.reset();
122    }
123}
124
125void WsServer::SendReply(const std::string& message) const
126{
127    std::unique_lock<std::shared_mutex> lock(g_mutex);
128    if (webSocket_ == nullptr) {
129        LOGE("WsServer SendReply websocket has been closed unexpectedly");
130        return;
131    }
132    LOGI("WsServer SendReply: %{public}s", message.c_str());
133    if (!webSocket_->SendReply(message)) {
134        LOGE("WsServer SendReply send fail");
135        NotifyDisconnectEvent();
136    }
137}
138
139void WsServer::NotifyDisconnectEvent() const
140{
141    std::string message = "{\"id\":0, \"method\":\"Debugger.clientDisconnect\", \"params\":{}}";
142    wsOnMessage_(std::move(message));
143}
144} // namespace OHOS::ArkCompiler::Toolchain
145