1 /*
2 * Copyright (c) 2021 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 "protocol_handler.h"
17
18 #include "agent/debugger_impl.h"
19
20 namespace panda::ecmascript::tooling {
WaitForDebugger()21 void ProtocolHandler::WaitForDebugger()
22 {
23 waitingForDebugger_ = true;
24 ProcessCommand();
25 }
26
RunIfWaitingForDebugger()27 void ProtocolHandler::RunIfWaitingForDebugger()
28 {
29 waitingForDebugger_ = false;
30 }
31
DispatchCommand(std::string && msg)32 void ProtocolHandler::DispatchCommand(std::string &&msg)
33 {
34 LOG_DEBUGGER(DEBUG) << "ProtocolHandler::DispatchCommand: " << msg;
35 std::unique_lock<std::mutex> queueLock(requestLock_);
36 requestQueue_.push(std::move(msg));
37 requestQueueCond_.notify_one();
38 }
39
40 // called after DispatchCommand
GetDispatchStatus()41 int32_t ProtocolHandler::GetDispatchStatus()
42 {
43 if (isDispatchingMessage_ || waitingForDebugger_) {
44 return DispatchStatus::DISPATCHING;
45 }
46 std::unique_lock<std::mutex> queueLock(requestLock_);
47 if (requestQueue_.empty()) {
48 return DispatchStatus::DISPATCHED;
49 }
50 return DispatchStatus::UNKNOWN;
51 }
52
ProcessCommand()53 void ProtocolHandler::ProcessCommand()
54 {
55 std::queue<std::string> dispatchingQueue;
56 do {
57 {
58 std::unique_lock<std::mutex> queueLock(requestLock_);
59 if (requestQueue_.empty()) {
60 if (!waitingForDebugger_) {
61 return;
62 }
63 requestQueueCond_.wait(queueLock);
64 }
65 requestQueue_.swap(dispatchingQueue);
66 }
67
68 isDispatchingMessage_ = true;
69 while (!dispatchingQueue.empty()) {
70 std::string msg = std::move(dispatchingQueue.front());
71 dispatchingQueue.pop();
72
73 [[maybe_unused]] LocalScope scope(vm_);
74 auto exception = DebuggerApi::GetAndClearException(vm_);
75 dispatcher_.Dispatch(DispatchRequest(msg));
76 DebuggerApi::SetException(vm_, exception);
77 }
78 isDispatchingMessage_ = false;
79 } while (true);
80 }
81
SendResponse(const DispatchRequest & request,const DispatchResponse & response,const PtBaseReturns & result)82 void ProtocolHandler::SendResponse(const DispatchRequest &request, const DispatchResponse &response,
83 const PtBaseReturns &result)
84 {
85 LOG_DEBUGGER(INFO) << "ProtocolHandler::SendResponse: "
86 << (response.IsOk() ? "success" : "failed: " + response.GetMessage());
87
88 std::unique_ptr<PtJson> reply = PtJson::CreateObject();
89 reply->Add("id", request.GetCallId());
90 std::unique_ptr<PtJson> resultObj;
91 if (response.IsOk()) {
92 resultObj = result.ToJson();
93 } else {
94 resultObj = CreateErrorReply(response);
95 }
96 reply->Add("result", resultObj);
97 SendReply(*reply);
98 reply->ReleaseRoot();
99 }
100
SendNotification(const PtBaseEvents & events)101 void ProtocolHandler::SendNotification(const PtBaseEvents &events)
102 {
103 LOG_DEBUGGER(DEBUG) << "ProtocolHandler::SendNotification: " << events.GetName();
104 std::unique_ptr<PtJson> reply = events.ToJson();
105 SendReply(*reply);
106 reply->ReleaseRoot();
107 }
108
SendReply(const PtJson & reply)109 void ProtocolHandler::SendReply(const PtJson &reply)
110 {
111 std::string str = reply.Stringify();
112 if (str.empty()) {
113 LOG_DEBUGGER(ERROR) << "ProtocolHandler::SendReply: json stringify error";
114 return;
115 }
116
117 callback_(reinterpret_cast<const void *>(vm_), str);
118 }
119
CreateErrorReply(const DispatchResponse & response)120 std::unique_ptr<PtJson> ProtocolHandler::CreateErrorReply(const DispatchResponse &response)
121 {
122 std::unique_ptr<PtJson> result = PtJson::CreateObject();
123
124 if (!response.IsOk()) {
125 result->Add("code", static_cast<int32_t>(response.GetError()));
126 result->Add("message", response.GetMessage().c_str());
127 }
128
129 return result;
130 }
131 } // namespace panda::ecmascript::tooling
132