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 (C) 2023 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 along
18 * with this program. If not, see <http://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
39using kiapi::common::ApiRequest, kiapi::common::ApiResponse;
40using kiapi::common::ApiResponseStatus, kiapi::common::ApiStatusCode;
41
42typedef tl::expected<ApiResponse, ApiResponseStatus> API_RESULT;
43
44template <typename T>
45using HANDLER_RESULT = tl::expected<T, ApiResponseStatus>;
46
47
49{
50 std::string ClientName;
51};
52
53
55{
56public:
58
59 virtual ~API_HANDLER() {}
60
66 API_RESULT Handle( ApiRequest& aMsg );
67
68protected:
69
74 typedef std::function<HANDLER_RESULT<ApiResponse>( ApiRequest& )> REQUEST_HANDLER;
75
90 template <class RequestType, class ResponseType, class HandlerType>
92 HANDLER_RESULT<ResponseType>( HandlerType::* aHandler )( RequestType&,
93 const HANDLER_CONTEXT& ) )
94 {
95 std::string typeName = RequestType().GetTypeName();
96
97 wxASSERT_MSG( !m_handlers.count( typeName ),
98 wxString::Format( "Duplicate API handler for type %s", typeName ) );
99
100 m_handlers[typeName] =
101 [this, aHandler]( ApiRequest& aRequest ) -> API_RESULT
102 {
103 RequestType cmd;
104 ApiResponse envelope;
105
106 if( !tryUnpack( aRequest, envelope, cmd ) )
107 return envelope;
108
109 HANDLER_CONTEXT ctx;
110 ctx.ClientName = aRequest.header().client_name();
111
113 std::invoke( aHandler, static_cast<HandlerType*>( this ), cmd, ctx );
114
115 if( response.has_value() )
116 {
117 envelope.mutable_status()->set_status( ApiStatusCode::AS_OK );
118 envelope.mutable_message()->PackFrom( *response );
119 return envelope;
120 }
121 else
122 {
123 return tl::unexpected( response.error() );
124 }
125 };
126 }
127
129 std::map<std::string, REQUEST_HANDLER> m_handlers;
130
131 static const wxString m_defaultCommitMessage;
132
133private:
134
135 template<typename MessageType>
136 bool tryUnpack( ApiRequest& aRequest, ApiResponse& aReply, MessageType& aDest )
137 {
138 if( !aRequest.message().UnpackTo( &aDest ) )
139 {
140 std::string msg = fmt::format( "could not unpack message of type {} from request",
141 aDest.GetTypeName() );
142 aReply.mutable_status()->set_status( ApiStatusCode::AS_BAD_REQUEST );
143 aReply.mutable_status()->set_error_message( msg );
144 return false;
145 }
146
147 return true;
148 }
149};
150
151#endif //KICAD_API_HANDLER_H
tl::expected< ApiResponse, ApiResponseStatus > API_RESULT
Definition: api_handler.h:42
tl::expected< T, ApiResponseStatus > HANDLER_RESULT
Definition: api_handler.h:45
static const wxString m_defaultCommitMessage
Definition: api_handler.h:131
void registerHandler(HANDLER_RESULT< ResponseType >(HandlerType::*aHandler)(RequestType &, const HANDLER_CONTEXT &))
Registers an API command handler for the given message types.
Definition: api_handler.h:91
std::map< std::string, REQUEST_HANDLER > m_handlers
Maps type name (without the URL prefix) to a handler method.
Definition: api_handler.h:129
virtual ~API_HANDLER()
Definition: api_handler.h:59
bool tryUnpack(ApiRequest &aRequest, ApiResponse &aReply, MessageType &aDest)
Definition: api_handler.h:136
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:74
#define KICOMMON_API
Definition: kicommon.h:28
std::string ClientName
Definition: api_handler.h:50