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 "dispatcher.h" 17 18#include "agent/debugger_impl.h" 19#include "agent/runtime_impl.h" 20#ifdef ECMASCRIPT_SUPPORT_HEAPPROFILER 21#include "agent/heapprofiler_impl.h" 22#endif 23#ifdef ECMASCRIPT_SUPPORT_CPUPROFILER 24#include "agent/profiler_impl.h" 25#endif 26#include "agent/tracing_impl.h" 27#include "agent/css_impl.h" 28#include "agent/dom_impl.h" 29#include "agent/overlay_impl.h" 30#include "agent/page_impl.h" 31#include "agent/target_impl.h" 32#include "protocol_channel.h" 33 34namespace panda::ecmascript::tooling { 35DispatchRequest::DispatchRequest(const std::string &message) 36{ 37 std::unique_ptr<PtJson> json = PtJson::Parse(message); 38 if (json == nullptr) { 39 JsonParseError(); 40 return; 41 } 42 if (!json->IsObject()) { 43 JsonFormatError(json); 44 return; 45 } 46 47 Result ret; 48 int32_t callId; 49 ret = json->GetInt("id", &callId); 50 if (ret != Result::SUCCESS) { 51 code_ = RequestCode::PARSE_ID_ERROR; 52 LOG_DEBUGGER(ERROR) << "parse id error"; 53 return; 54 } 55 callId_ = callId; 56 57 std::string wholeMethod; 58 ret = json->GetString("method", &wholeMethod); 59 if (ret != Result::SUCCESS || wholeMethod.empty()) { 60 code_ = RequestCode::PARSE_METHOD_ERROR; 61 LOG_DEBUGGER(ERROR) << "parse method error"; 62 return; 63 } 64 std::string::size_type length = wholeMethod.length(); 65 std::string::size_type indexPoint = wholeMethod.find_first_of('.', 0); 66 if (indexPoint == std::string::npos || indexPoint == 0 || indexPoint == length - 1) { 67 code_ = RequestCode::METHOD_FORMAT_ERROR; 68 LOG_DEBUGGER(ERROR) << "method format error: " << wholeMethod; 69 return; 70 } 71 domain_ = wholeMethod.substr(0, indexPoint); 72 method_ = wholeMethod.substr(indexPoint + 1, length); 73 74 LOG_DEBUGGER(DEBUG) << "id: " << callId_ << ", domain: " << domain_ << ", method: " << method_; 75 76 std::unique_ptr<PtJson> params; 77 ret = json->GetObject("params", ¶ms); 78 if (ret == Result::NOT_EXIST) { 79 return; 80 } 81 if (ret == Result::TYPE_ERROR) { 82 code_ = RequestCode::PARAMS_FORMAT_ERROR; 83 LOG_DEBUGGER(ERROR) << "params format error"; 84 return; 85 } 86 params_ = std::move(params); 87} 88 89DispatchRequest::~DispatchRequest() 90{ 91 params_->ReleaseRoot(); 92} 93 94DispatchResponse DispatchResponse::Create(ResponseCode code, const std::string &msg) 95{ 96 DispatchResponse response; 97 response.code_ = code; 98 response.errorMsg_ = msg; 99 return response; 100} 101 102DispatchResponse DispatchResponse::Create(std::optional<std::string> error) 103{ 104 DispatchResponse response; 105 if (error.has_value()) { 106 response.code_ = ResponseCode::NOK; 107 response.errorMsg_ = error.value(); 108 } 109 return response; 110} 111 112DispatchResponse DispatchResponse::Ok() 113{ 114 return DispatchResponse(); 115} 116 117DispatchResponse DispatchResponse::Fail(const std::string &message) 118{ 119 DispatchResponse response; 120 response.code_ = ResponseCode::NOK; 121 response.errorMsg_ = message; 122 return response; 123} 124 125void DispatcherBase::SendResponse(const DispatchRequest &request, const DispatchResponse &response, 126 const PtBaseReturns &result) 127{ 128 if (channel_ != nullptr) { 129 channel_->SendResponse(request, response, result); 130 } 131} 132 133Dispatcher::Dispatcher(const EcmaVM *vm, ProtocolChannel *channel) 134{ 135 // profiler 136#ifdef ECMASCRIPT_SUPPORT_CPUPROFILER 137 auto profiler = std::make_unique<ProfilerImpl>(vm, channel); 138 dispatchers_["Profiler"] = 139 std::make_unique<ProfilerImpl::DispatcherImpl>(channel, std::move(profiler)); 140#endif 141#ifdef ECMASCRIPT_SUPPORT_HEAPPROFILER 142 auto heapProfiler = std::make_unique<HeapProfilerImpl>(vm, channel); 143 dispatchers_["HeapProfiler"] = 144 std::make_unique<HeapProfilerImpl::DispatcherImpl>(channel, std::move(heapProfiler)); 145#endif 146#ifdef ECMASCRIPT_SUPPORT_TRACING 147 auto tracing = std::make_unique<TracingImpl>(vm, channel); 148 dispatchers_["Tracing"] = 149 std::make_unique<TracingImpl::DispatcherImpl>(channel, std::move(tracing)); 150#endif 151 152 // debugger 153 auto runtime = std::make_unique<RuntimeImpl>(vm, channel); 154 auto debugger = std::make_unique<DebuggerImpl>(vm, channel, runtime.get()); 155 dispatchers_["Runtime"] = 156 std::make_unique<RuntimeImpl::DispatcherImpl>(channel, std::move(runtime)); 157 dispatchers_["Debugger"] = 158 std::make_unique<DebuggerImpl::DispatcherImpl>(channel, std::move(debugger)); 159 160 auto dom = std::make_unique<DomImpl>(); 161 dispatchers_["DOM"] = 162 std::make_unique<DomImpl::DispatcherImpl>(channel, std::move(dom)); 163 164 auto css = std::make_unique<CssImpl>(); 165 dispatchers_["CSS"] = 166 std::make_unique<CssImpl::DispatcherImpl>(channel, std::move(css)); 167 168 auto overlay = std::make_unique<OverlayImpl>(); 169 dispatchers_["Overlay"] = 170 std::make_unique<OverlayImpl::DispatcherImpl>(channel, std::move(overlay)); 171 172 auto target = std::make_unique<TargetImpl>(); 173 dispatchers_["Target"] = 174 std::make_unique<TargetImpl::DispatcherImpl>(channel, std::move(target)); 175 176 auto page = std::make_unique<PageImpl>(); 177 dispatchers_["Page"] = 178 std::make_unique<PageImpl::DispatcherImpl>(channel, std::move(page)); 179} 180 181void Dispatcher::Dispatch(const DispatchRequest &request) 182{ 183 if (!request.IsValid()) { 184 LOG_DEBUGGER(ERROR) << "Unknown request"; 185 return; 186 } 187 const std::string &domain = request.GetDomain(); 188 auto dispatcher = dispatchers_.find(domain); 189 if (dispatcher != dispatchers_.end()) { 190 dispatcher->second->Dispatch(request); 191 } else { 192 if (domain == "Test") { 193 if (request.GetMethod() == "fail") { 194 LOG_DEBUGGER(FATAL) << "Test fail"; 195 UNREACHABLE(); 196 } 197 LOG_DEBUGGER(INFO) << "Test success"; 198 } else { 199 LOG_DEBUGGER(ERROR) << "unknown domain: " << domain; 200 } 201 } 202} 203} // namespace panda::ecmascript::tooling 204