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/manager/watch_manager.h"
17
18#include "common/log_wrapper.h"
19#include "tooling/client/session/session.h"
20
21using PtJson = panda::ecmascript::tooling::PtJson;
22using Result = panda::ecmascript::tooling::Result;
23namespace OHOS::ArkCompiler::Toolchain {
24WatchManager::WatchManager(uint32_t sessionId)
25    : sessionId_(sessionId), runtimeClient_(sessionId)
26{
27}
28
29void WatchManager::SendRequestWatch(const int32_t &watchInfoIndex, const std::string &callFrameId)
30{
31    Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
32    uint32_t id = session->GetMessageId();
33    watchInfoMap_.emplace(id, watchInfoIndex);
34
35    std::unique_ptr<PtJson> request = PtJson::CreateObject();
36    request->Add("id", id);
37    request->Add("method", "Debugger.evaluateOnCallFrame");
38
39    std::unique_ptr<PtJson> params = PtJson::CreateObject();
40    params->Add("callFrameId", callFrameId.c_str());
41    params->Add("expression", watchInfoList_[watchInfoIndex].c_str());
42    params->Add("objectGroup", "watch-group");
43    params->Add("includeCommandLineAPI", false);
44    params->Add("silent", true);
45    params->Add("returnByValue", false);
46    params->Add("generatePreview", false);
47    params->Add("throwOnSideEffect", false);
48    request->Add("params", params);
49
50    std::string message = request->Stringify();
51    if (session->ClientSendReq(message)) {
52        inputRowFlag_++;
53        session->GetDomainManager().SetDomainById(id, "Debugger");
54    }
55    return;
56}
57
58void WatchManager::GetPropertiesCommand(const int32_t &watchInfoIndex, const std::string &objectId)
59{
60    Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
61    uint32_t id = session->GetMessageId();
62    watchInfoMap_.emplace(id, watchInfoIndex);
63
64    std::unique_ptr<PtJson> request = PtJson::CreateObject();
65    request->Add("id", id);
66    request->Add("method", "Runtime.getProperties");
67
68    std::unique_ptr<PtJson> params = PtJson::CreateObject();
69    params->Add("accessorPropertiesOnly", false);
70    params->Add("generatePreview", true);
71    params->Add("objectId", objectId.c_str());
72    params->Add("ownProperties", true);
73    request->Add("params", params);
74
75    std::string message = request->Stringify();
76    if (session->ClientSendReq(message)) {
77        session->GetDomainManager().SetDomainById(id, "Debugger");
78    }
79    return;
80}
81
82void WatchManager::RequestWatchInfo(const std::unique_ptr<PtJson> &json)
83{
84    Result ret = json->GetString("callFrameId", &callFrameId_);
85    if (ret != Result::SUCCESS) {
86        LOGE("arkdb: find callFrameId error");
87        return;
88    }
89    for (uint i = 0; i < watchInfoList_.size(); i++) {
90        SendRequestWatch(i, callFrameId_);
91    }
92}
93
94std::string WatchManager::GetCallFrameId()
95{
96    return callFrameId_;
97}
98
99int WatchManager::GetWatchInfoSize()
100{
101    return watchInfoList_.size();
102}
103
104void WatchManager::AddWatchInfo(const std::string& watchInfo)
105{
106    watchInfoList_.emplace_back(watchInfo);
107}
108
109bool WatchManager::GetDebugState()
110{
111    return IsDebug_;
112}
113void WatchManager::DebugFalseState()
114{
115    IsDebug_ = false;
116}
117void WatchManager::DebugTrueState()
118{
119    IsDebug_ = true;
120}
121
122void WatchManager::SetWatchInfoMap(const int &id, const int &index)
123{
124    watchInfoMap_.emplace(id, index);
125}
126
127bool WatchManager::HandleWatchResult(const std::unique_ptr<PtJson> &json, int32_t id)
128{
129    Result ret;
130    std::unique_ptr<PtJson> result;
131    ret = json->GetObject("result", &result);
132    if (ret != Result::SUCCESS) {
133        LOGE("json parse result error");
134        return false;
135    }
136    std::unique_ptr<PtJson> watchResult;
137    ret = result->GetObject("result", &watchResult);
138    if (ret != Result::SUCCESS) {
139        ShowWatchResult2(id, std::move(json));
140        LOGE("json parse result error");
141        return false;
142    }
143    if (!ShowWatchResult(std::move(watchResult), id)) {
144        return false;
145    }
146    inputRowFlag_--;
147    if (inputRowFlag_ == 0) {
148        std::cout << ">>> ";
149        fflush(stdout);
150        isShowWatchInfo_ = true;
151    }
152    return true;
153}
154bool WatchManager::ShowWatchResult(const std::unique_ptr<PtJson> &result, int32_t id)
155{
156    std::string type;
157    Result ret = result->GetString("type", &type);
158    if (ret != Result::SUCCESS) {
159        LOGE("json parse type error");
160        return false;
161    }
162    if (inputRowFlag_ == GetWatchInfoSize() && isShowWatchInfo_) {
163        std::cout << "watch info :" << std::endl;
164        isShowWatchInfo_ = false;
165    }
166    if (type == "undefined") {
167        auto it = watchInfoMap_.find(id);
168        if (it == watchInfoMap_.end()) {
169            return false;
170        }
171        std::cout << "    " << watchInfoList_[it->second] << " = undefined" << std::endl;
172    } else if (type == "object") {
173        std::string objectId;
174        ret = result->GetString("objectId", &objectId);
175        if (ret != Result::SUCCESS) {
176            LOGE("json parse object error");
177            return false;
178        }
179        auto it = watchInfoMap_.find(id);
180        if (it == watchInfoMap_.end()) {
181            return false;
182        }
183        GetPropertiesCommand(it->second, objectId);
184        inputRowFlag_++;
185    } else  {
186        auto it = watchInfoMap_.find(id);
187        if (it == watchInfoMap_.end()) {
188            return false;
189        }
190        std::string description;
191        ret = result->GetString("description", &description);
192        if (ret != Result::SUCCESS) {
193            LOGE("json parse description error");
194            return false;
195        }
196        std::cout << "    " << watchInfoList_[it->second] << " = " << description << std::endl;
197    }
198    watchInfoMap_.erase(id);
199    DebugTrueState();
200    return true;
201}
202
203void WatchManager::OutputWatchResult(const std::unique_ptr<PtJson> &watchResult)
204{
205    for (int32_t i = 0; i < watchResult->GetSize(); i++) {
206        std::string name;
207        Result ret = watchResult->Get(i)->GetString("name", &name);
208        if (ret != Result::SUCCESS) {
209            LOGE("json parse name error");
210            continue;
211        }
212        std::unique_ptr<PtJson>  value;
213        ret = watchResult->Get(i)->GetObject("value", &value);
214        if (ret != Result::SUCCESS) {
215            LOGE("json parse value error");
216            continue;
217        }
218        std::string description;
219        ret = value->GetString("description", &description);
220        if (ret != Result::SUCCESS) {
221            LOGE("json parse description error");
222            continue;
223        }
224        std::cout << name << " = " << description;
225        if (i < watchResult->GetSize() - 1) {
226            std::cout << ", ";
227        }
228    }
229    return;
230}
231
232bool WatchManager::ShowWatchResult2(const int &id, const std::unique_ptr<PtJson> &result)
233{
234    std::unique_ptr<PtJson> resultWatch;
235    Result ret = result->GetObject("result", &resultWatch);
236    if (ret != Result::SUCCESS) {
237        LOGE("json parse result error");
238        return false;
239    }
240    std::unique_ptr<PtJson> watchResult;
241    ret = resultWatch->GetArray("result", &watchResult);
242    if (ret != Result::SUCCESS) {
243        LOGE("json parse result error");
244        return false;
245    }
246    auto it = watchInfoMap_.find(id);
247    if (it == watchInfoMap_.end()) {
248        return false;
249    }
250    std::cout << "    " << watchInfoList_[it->second] << " = { ";
251    OutputWatchResult(std::move(watchResult));
252    std::cout << " }" << std::endl;
253    inputRowFlag_--;
254    if (inputRowFlag_ == 0) {
255        std::cout << ">>> ";
256        fflush(stdout);
257        isShowWatchInfo_ = true;
258    }
259    DebugTrueState();
260    watchInfoMap_.erase(id);
261    return true;
262}
263}