1/*
2 * Copyright (c) 2023 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 "tooling/client/session/session.h"
17
18#include "common/log_wrapper.h"
19#include "tooling/client/manager/message_manager.h"
20#include "tooling/base/pt_json.h"
21#include "tooling/utils/utils.h"
22
23#include <iomanip>
24
25using PtJson = panda::ecmascript::tooling::PtJson;
26using Result = panda::ecmascript::tooling::Result;
27namespace OHOS::ArkCompiler::Toolchain {
28uv_async_t* g_socketSignal;
29void SocketMessageThread(void *arg)
30{
31    int sessionId = *(uint32_t *)arg;
32    Session *session = SessionManager::getInstance().GetSessionById(sessionId);
33
34    session->SocketMessageLoop();
35}
36
37Session::Session(uint32_t sessionId, std::string& sockInfo)
38    : sessionId_(sessionId), sockInfo_(sockInfo), domainManager_(sessionId), breakpoint_(sessionId),
39      stackManager_(sessionId), variableManager_(sessionId), sourceManager_(sessionId), watchManager_(sessionId)
40{
41}
42
43void Session::SocketMessageLoop()
44{
45    while (cliSocket_.IsConnected()) {
46        std::string decMessage = cliSocket_.Decode();
47        uint32_t len = decMessage.length();
48        if (len == 0) {
49            continue;
50        }
51        LOGI("arkdb [%{public}u] message = %{public}s", sessionId_, decMessage.c_str());
52
53        MessageManager::getInstance().MessagePush(sessionId_, decMessage);
54
55        if (uv_is_active(reinterpret_cast<uv_handle_t*>(g_socketSignal))) {
56            uv_async_send(g_socketSignal);
57        }
58    }
59}
60
61int Session::CreateSocket()
62{
63    uint32_t port = 0;
64    if (Utils::StrToUInt(sockInfo_.c_str(), &port)) {
65        if ((port <= 0) || (port >= 65535)) { // 65535: max port
66            LOGE("arkdb:InitToolchainWebSocketForPort the port = %{public}d is wrong.", port);
67            return -1;
68        }
69        if (!cliSocket_.InitToolchainWebSocketForPort(port, 5)) { // 5: five times
70            LOGE("arkdb:InitToolchainWebSocketForPort failed");
71            return -1;
72        }
73    } else {
74        if (!cliSocket_.InitToolchainWebSocketForSockName(sockInfo_)) {
75            LOGE("arkdb:InitToolchainWebSocketForSockName failed");
76            return -1;
77        }
78    }
79
80    if (!cliSocket_.ClientSendWSUpgradeReq()) {
81        LOGE("arkdb:ClientSendWSUpgradeReq failed");
82        return -1;
83    }
84    if (!cliSocket_.ClientRecvWSUpgradeRsp()) {
85        LOGE("arkdb:ClientRecvWSUpgradeRsp failed");
86        return -1;
87    }
88
89    return 0;
90}
91
92int Session::Start()
93{
94    if (CreateSocket()) {
95        return -1;
96    }
97
98    uv_thread_create(&socketTid_, SocketMessageThread, &sessionId_);
99    return 0;
100}
101
102int Session::Stop()
103{
104    cliSocket_.Close();
105    return 0;
106}
107
108int SessionManager::CreateSessionById(uint32_t sessionId, std::string& sockInfo)
109{
110    sessions_[sessionId] = std::make_unique<Session>(sessionId, sockInfo);
111    if (sessions_[sessionId]->Start()) {
112        sessions_[sessionId] = nullptr;
113        return -1;
114    }
115
116    return 0;
117}
118
119int SessionManager::CreateNewSession(std::string& sockInfo)
120{
121    uint32_t sessionId = MAX_SESSION_NUM;
122    for (uint32_t i = 0; i < MAX_SESSION_NUM; ++i) {
123        if (sessions_[i] == nullptr) {
124            if (sessionId == MAX_SESSION_NUM) {
125                sessionId = i;
126            }
127            continue;
128        }
129        if (sessions_[i]->GetSockInfo() == sockInfo) {
130            return -1;
131        }
132    }
133
134    if (sessionId < MAX_SESSION_NUM) {
135        return CreateSessionById(sessionId, sockInfo);
136    }
137
138    return -1;
139}
140
141int SessionManager::CreateDefaultSession(std::string& sockInfo)
142{
143    return CreateSessionById(0, sockInfo);
144}
145
146int SessionManager::DelSessionById(uint32_t sessionId)
147{
148    Session *session = GetSessionById(sessionId);
149    if (session == nullptr) {
150        return -1;
151    }
152    session->Stop();
153    sessions_[sessionId] = nullptr;
154
155    if (sessionId == currentSessionId_) {
156        currentSessionId_ = 0;
157        std::cout << "session switch to 0" << std::endl;
158    }
159
160    return 0;
161}
162
163int SessionManager::SessionList()
164{
165    for (uint32_t i = 0; i < MAX_SESSION_NUM; ++i) {
166        if (sessions_[i] != nullptr) {
167            std::string flag = (i == currentSessionId_) ? "* " : "  ";
168            std::string sockState = sessions_[i]->GetSocketStateString();
169            std::cout << flag << i << ": ";
170            std::cout << std::setw(32) << std::left << sessions_[i]->GetSockInfo(); // 32: max length of socket info
171            std::cout << sockState << std::endl;
172        }
173    }
174    return 0;
175}
176
177int SessionManager::SessionSwitch(uint32_t sessionId)
178{
179    Session *session = GetSessionById(sessionId);
180    if (session == nullptr) {
181        return -1;
182    }
183    currentSessionId_ = sessionId;
184    return 0;
185}
186
187void SessionManager::CmdForAllSessions(CmdForAllCB callback)
188{
189    for (uint32_t sessionId = 0; sessionId < MAX_SESSION_NUM; ++sessionId) {
190        if (sessions_[sessionId] != nullptr) {
191            std::cout << "Executing command in session " << sessionId << ":" << std::endl;
192            callback(sessionId);
193        }
194    }
195}
196
197int SessionManager::CreateTestSession(std::string& sockInfo)
198{
199    uint32_t sessionId = 0;
200    sessions_[sessionId] = std::make_unique<Session>(sessionId, sockInfo);
201    if (sessions_[sessionId]->CreateSocket()) {
202        sessions_[sessionId] = nullptr;
203        return -1;
204    }
205
206    return 0;
207}
208}