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 #ifndef ECMASCRIPT_TOOLING_DISPATCHER_H
17 #define ECMASCRIPT_TOOLING_DISPATCHER_H
18 
19 #include <map>
20 #include <memory>
21 
22 #include "tooling/base/pt_returns.h"
23 
24 #include "ecmascript/debugger/js_debugger_interface.h"
25 #include "ecmascript/napi/include/jsnapi.h"
26 #include "libpandabase/macros.h"
27 
28 namespace panda::ecmascript::tooling {
29 class ProtocolChannel;
30 class PtBaseReturns;
31 class PtBaseEvents;
32 
33 enum class RequestCode : uint8_t {
34     OK = 0,
35     NOK,
36 
37     // Json parse errors
38     JSON_PARSE_ERROR,
39     PARSE_ID_ERROR,
40     ID_FORMAT_ERROR,
41     PARSE_METHOD_ERROR,
42     METHOD_FORMAT_ERROR,
43     PARSE_PARAMS_ERROR,
44     PARAMS_FORMAT_ERROR
45 };
46 
47 enum class ResponseCode : uint8_t { OK, NOK };
48 
49 class DispatchRequest {
50 public:
51     explicit DispatchRequest(const std::string &message);
52     ~DispatchRequest();
53 
IsValid() const54     bool IsValid() const
55     {
56         return code_ == RequestCode::OK;
57     }
GetCallId() const58     int32_t GetCallId() const
59     {
60         return callId_;
61     }
GetParams() const62     const PtJson &GetParams() const
63     {
64         return *params_;
65     }
GetDomain() const66     const std::string &GetDomain() const
67     {
68         return domain_;
69     }
GetMethod() const70     const std::string &GetMethod() const
71     {
72         return method_;
73     }
74 
75 private:
76     int32_t callId_ = -1;
77     std::string domain_ {};
78     std::string method_ {};
79     std::unique_ptr<PtJson> params_ = std::make_unique<PtJson>();
80     RequestCode code_ {RequestCode::OK};
81     std::string errorMsg_ {};
JsonParseError()82     void JsonParseError()
83     {
84         code_ = RequestCode::JSON_PARSE_ERROR;
85         LOG_DEBUGGER(ERROR) << "json parse error";
86     }
JsonFormatError(std::unique_ptr<PtJson>& json)87     void JsonFormatError(std::unique_ptr<PtJson>& json)
88     {
89         code_ = RequestCode::PARAMS_FORMAT_ERROR;
90         LOG_DEBUGGER(ERROR) << "json parse format error";
91         json->ReleaseRoot();
92     }
93 };
94 
95 class DispatchResponse {
96 public:
IsOk() const97     bool IsOk() const
98     {
99         return code_ == ResponseCode::OK;
100     }
101 
GetError() const102     ResponseCode GetError() const
103     {
104         return code_;
105     }
106 
GetMessage() const107     const std::string &GetMessage() const
108     {
109         return errorMsg_;
110     }
111 
112     static DispatchResponse Create(ResponseCode code, const std::string &msg = "");
113     static DispatchResponse Create(std::optional<std::string> error);
114     static DispatchResponse Ok();
115     static DispatchResponse Fail(const std::string &message);
116 
117     ~DispatchResponse() = default;
118 
119 private:
120     DispatchResponse() = default;
121 
122     ResponseCode code_ {ResponseCode::OK};
123     std::string errorMsg_ {};
124 };
125 
126 class DispatcherBase {
127 public:
DispatcherBase(ProtocolChannel *channel)128     explicit DispatcherBase(ProtocolChannel *channel) : channel_(channel) {}
~DispatcherBase()129     virtual ~DispatcherBase()
130     {
131         channel_ = nullptr;
132     };
133     virtual void Dispatch(const DispatchRequest &request) = 0;
134 
135 protected:
136     void SendResponse(const DispatchRequest &request, const DispatchResponse &response,
137                       const PtBaseReturns &result = PtBaseReturns());
138 
139 private:
140     ProtocolChannel *channel_ {nullptr};
141 
142     NO_COPY_SEMANTIC(DispatcherBase);
143     NO_MOVE_SEMANTIC(DispatcherBase);
144 };
145 
146 class Dispatcher {
147 public:
148     explicit Dispatcher(const EcmaVM *vm, ProtocolChannel *channel);
149     ~Dispatcher() = default;
150     void Dispatch(const DispatchRequest &request);
151 
152 private:
153     std::unordered_map<std::string, std::unique_ptr<DispatcherBase>> dispatchers_ {};
154 
155     NO_COPY_SEMANTIC(Dispatcher);
156     NO_MOVE_SEMANTIC(Dispatcher);
157 };
158 }  // namespace panda::ecmascript::tooling
159 #endif
160