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 DebuggerApi::DebuggerNativeScope nativeScope(vm_);
58 {
59 std::unique_lock<std::mutex> queueLock(requestLock_);
60 if (requestQueue_.empty()) {
61 if (!waitingForDebugger_) {
62 return;
63 }
64 requestQueueCond_.wait(queueLock);
65 }
66 requestQueue_.swap(dispatchingQueue);
67 }
68
69 isDispatchingMessage_ = true;
70 {
71 DebuggerApi::DebuggerManagedScope managedScope(vm_);
72 while (!dispatchingQueue.empty()) {
73 std::string msg = std::move(dispatchingQueue.front());
74 dispatchingQueue.pop();
75
76 [[maybe_unused]] LocalScope scope(vm_);
77 auto exception = DebuggerApi::GetAndClearException(vm_);
78 dispatcher_.Dispatch(DispatchRequest(msg));
79 DebuggerApi::SetException(vm_, exception);
80 }
81 }
82 isDispatchingMessage_ = false;
83 } while (true);
84 }
85
SendResponse(const DispatchRequest &request, const DispatchResponse &response, const PtBaseReturns &result)86 void ProtocolHandler::SendResponse(const DispatchRequest &request, const DispatchResponse &response,
87 const PtBaseReturns &result)
88 {
89 LOG_DEBUGGER(INFO) << "ProtocolHandler::SendResponse: "
90 << (response.IsOk() ? "success" : "failed: " + response.GetMessage());
91
92 std::unique_ptr<PtJson> reply = PtJson::CreateObject();
93 reply->Add("id", request.GetCallId());
94 std::unique_ptr<PtJson> resultObj;
95 if (response.IsOk()) {
96 resultObj = result.ToJson();
97 } else {
98 resultObj = CreateErrorReply(response);
99 }
100 reply->Add("result", resultObj);
101 SendReply(*reply);
102 reply->ReleaseRoot();
103 }
104
SendNotification(const PtBaseEvents &events)105 void ProtocolHandler::SendNotification(const PtBaseEvents &events)
106 {
107 LOG_DEBUGGER(DEBUG) << "ProtocolHandler::SendNotification: " << events.GetName();
108 std::unique_ptr<PtJson> reply = events.ToJson();
109 SendReply(*reply);
110 reply->ReleaseRoot();
111 }
112
SendReply(const PtJson &reply)113 void ProtocolHandler::SendReply(const PtJson &reply)
114 {
115 std::string str = reply.Stringify();
116 if (str.empty()) {
117 LOG_DEBUGGER(ERROR) << "ProtocolHandler::SendReply: json stringify error";
118 return;
119 }
120
121 callback_(reinterpret_cast<const void *>(vm_), str);
122 }
123
CreateErrorReply(const DispatchResponse &response)124 std::unique_ptr<PtJson> ProtocolHandler::CreateErrorReply(const DispatchResponse &response)
125 {
126 std::unique_ptr<PtJson> result = PtJson::CreateObject();
127
128 if (!response.IsOk()) {
129 result->Add("code", static_cast<int32_t>(response.GetError()));
130 result->Add("message", response.GetMessage().c_str());
131 }
132
133 return result;
134 }
135 } // namespace panda::ecmascript::tooling
136