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