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