KiCad PCB EDA Suite
Loading...
Searching...
No Matches
api_handler.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2023 Jon Evans <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21#ifndef KICAD_API_HANDLER_H
22#define KICAD_API_HANDLER_H
23
24#include <functional>
25#include <optional>
26
27#include <fmt/format.h>
28#include <tl/expected.hpp>
29
30#include <wx/debug.h>
31#include <wx/string.h>
32
33#include <google/protobuf/message.h>
34
35#include <kicommon.h>
36#include <api/common/envelope.pb.h>
37#include <core/typeinfo.h>
38
40
41using kiapi::common::ApiRequest, kiapi::common::ApiResponse;
42using kiapi::common::ApiResponseStatus, kiapi::common::ApiStatusCode;
43
44typedef tl::expected<ApiResponse, ApiResponseStatus> API_RESULT;
45
46template <typename T>
47using HANDLER_RESULT = tl::expected<T, ApiResponseStatus>;
48
49
50template <typename RequestMessageType>
52{
53 std::string ClientName;
54 RequestMessageType Request;
55};
56
57
59{
60public:
62
63 virtual ~API_HANDLER() {}
64
70 API_RESULT Handle( ApiRequest& aMsg );
71
76 virtual void onNetSettingsChanged() {}
77
79
82 {
83 bool pending = m_notifyNetSettings;
84 m_notifyNetSettings = false;
85 return pending;
86 }
87
89 void setApiServer( KICAD_API_SERVER* aServer ) { m_apiServer = aServer; }
91
92protected:
97 typedef std::function<HANDLER_RESULT<ApiResponse>( ApiRequest& )> REQUEST_HANDLER;
98
113 template <class RequestType, class ResponseType, class HandlerType>
114 void registerHandler( HANDLER_RESULT<ResponseType> ( HandlerType::*aHandler )(
116 {
117 std::string typeName { RequestType().GetTypeName() };
118
119 wxASSERT_MSG( !m_handlers.contains( typeName ),
120 wxString::Format( "Duplicate API handler for type %s", typeName ) );
121
122 m_handlers[typeName] =
123 [this, aHandler]( ApiRequest& aRequest ) -> API_RESULT
124 {
126 ApiResponse envelope;
127
128 if( !tryUnpack( aRequest, envelope, ctx.Request ) )
129 return envelope;
130
131 ctx.ClientName = aRequest.header().client_name();
132
134 std::invoke( aHandler, static_cast<HandlerType*>( this ), ctx );
135
136 if( response.has_value() )
137 {
138 envelope.mutable_status()->set_status( ApiStatusCode::AS_OK );
139 envelope.mutable_message()->PackFrom( *response );
140 return envelope;
141 }
142 else
143 {
144 return tl::unexpected( response.error() );
145 }
146 };
147 }
148
150 std::map<std::string, REQUEST_HANDLER> m_handlers;
151
153
155
156 static const wxString m_defaultCommitMessage;
157
158private:
159
160 template<typename MessageType>
161 bool tryUnpack( ApiRequest& aRequest, ApiResponse& aReply, MessageType& aDest )
162 {
163 if( !aRequest.message().UnpackTo( &aDest ) )
164 {
165 std::string msg = fmt::format( "could not unpack message of type {} from request",
166 aDest.GetTypeName() );
167 aReply.mutable_status()->set_status( ApiStatusCode::AS_BAD_REQUEST );
168 aReply.mutable_status()->set_error_message( msg );
169 return false;
170 }
171
172 return true;
173 }
174};
175
176#endif //KICAD_API_HANDLER_H
tl::expected< ApiResponse, ApiResponseStatus > API_RESULT
Definition api_handler.h:44
tl::expected< T, ApiResponseStatus > HANDLER_RESULT
Definition api_handler.h:47
static const wxString m_defaultCommitMessage
KICAD_API_SERVER * m_apiServer
virtual void onNetSettingsChanged()
Called on all registered handlers after project net settings (netclasses or netclass assignments) hav...
Definition api_handler.h:76
std::map< std::string, REQUEST_HANDLER > m_handlers
Maps type name (without the URL prefix) to a handler method.
KICAD_API_SERVER * apiServer() const
Definition api_handler.h:90
virtual ~API_HANDLER()
Definition api_handler.h:63
void registerHandler(HANDLER_RESULT< ResponseType >(HandlerType::*aHandler)(const HANDLER_CONTEXT< RequestType > &))
Registers an API command handler for the given message types.
bool m_notifyNetSettings
void requestNetSettingsNotification()
Definition api_handler.h:78
bool clearNetSettingsNotification()
Returns true if the notification had been requested at the time of the call.
Definition api_handler.h:81
bool tryUnpack(ApiRequest &aRequest, ApiResponse &aReply, MessageType &aDest)
std::function< HANDLER_RESULT< ApiResponse >(ApiRequest &)> REQUEST_HANDLER
A handler for outer messages (envelopes) that will unpack to inner messages and call a specific handl...
Definition api_handler.h:97
void setApiServer(KICAD_API_SERVER *aServer)
Set by KICAD_API_SERVER::RegisterHandler; null when the handler is not registered.
Definition api_handler.h:89
Handle(KICAD3D_INFO) KICAD3D_INFO
#define KICOMMON_API
Definition kicommon.h:27
std::string ClientName
Definition api_handler.h:53
RequestMessageType Request
Definition api_handler.h:54