c++: Avoid relative path when including headers
[src/app-framework-binder.git] / include / afb / c++ / binding-object.hpp
1 #pragma once
2
3 /*
4  * Copyright (C) 2018 "IoT.bzh"
5  * Author Loïc Collignon <loic.collignon@iot.bzh>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 extern "C" {
21 #include <afb/afb-binding.h>
22 }
23 #include <cassert>
24 #include <string>
25
26 namespace afb
27 {
28         /**
29          * @brief Create a new API.
30          * @tparam TApi The Api's concrete class to create an instance from.
31          * @param[in] handle Parent API.
32          * @param[in] name API's name.
33          * @param[in] info API's description.
34          * @param[in] noconcurrency Zero for a reentrant API, non-zero otherwise.
35          * @return The created API.
36          */
37         template <typename TApi>
38         TApi* new_api(afb_api_t handle, const std::string& name, const std::string& info = "", int noconcurrency = 1)
39         {
40                 TApi* api = new TApi();
41                 afb_api_new_api(
42                         handle,
43                         name.c_str(),
44                         info == "" ? nullptr : info.c_str(),
45                         noconcurrency,
46                         TApi::Traits::preinit,
47                         api
48                 );
49                 return api;
50         }
51
52         /**
53          * @brief Default Api's traits implementation.
54          * @tparam TApi The Api's concrete class.
55          */
56         template <typename TApi>
57         struct ApiTraits
58         {
59                 /**
60                  * @brief TApi's method pointer.
61                  */
62                 using TVerbCallback = void(TApi::*)(req);
63
64                 /***
65                  * @brief TApi's const method pointer.
66                  */
67                 using TVerbCallbackConst = void(TApi::*)(req) const;
68
69                 /**
70                  * @brief Pre-init callback for an api created using @c afb::api::new_api.
71                  * @param[in] closure Pointer to the API object.
72                  * @param[in] handle Handle of the API.
73                  * @return Zero on success, non-zero otherwise.
74                  */
75                 static int preinit(void* closure, afb_api_t handle)
76                 {
77                         assert(closure != nullptr);
78                         assert(handle != nullptr);
79
80                         afb_api_set_userdata(handle, closure);
81
82                         TApi* api = reinterpret_cast<TApi*>(closure);
83
84                         if (afb_api_on_init(handle, TApi::Traits::init))
85                         {
86                                 AFB_API_ERROR(handle, "Failed to register init handler callback.");
87                                 return -1;
88                         }
89
90                         if (afb_api_on_event(handle, TApi::Traits::event))
91                         {
92                                 AFB_API_ERROR(handle, "Failed to register event handler callback.");
93                                 return -2;
94                         }
95
96                         api->handle_ = handle;
97                         return api->preinit(handle);
98                 }
99
100                 /**
101                  * @brief Init callback for an api created using @c afb::api::new_api.
102                  * @param[in] handle Handle to the API to initialize.
103                  * @return Zero on success, non-zero otherwise.
104                  */
105                 static int init(afb_api_t handle)
106                 {
107                         assert(handle != nullptr);
108
109                         void* userdata = afb_api_get_userdata(handle);
110                         assert(userdata != nullptr);
111
112                         TApi* api = reinterpret_cast<TApi*>(userdata);
113                         return api->init();
114                 }
115
116                 /**
117                  * @brief Event callback for an api created using @c afb::api::new_api.
118                  * @param[in] handle Handle to the API that is receiving an event.
119                  * @param[in] event The event's name.
120                  * @param[in] object The event's json argument.
121                  */
122                 static void event(afb_api_t handle, const char* event, json_object* object)
123                 {
124                         assert(handle != nullptr);
125
126                         void* userdata = afb_api_get_userdata(handle);
127                         assert(userdata != nullptr);
128
129                         TApi* api = reinterpret_cast<TApi*>(userdata);
130                         api->event(event, object);
131                 }
132
133                 /**
134                  * @brief Verb callback for a verb added using @c afb::api::add_verb.
135                  * @tparam callback TApi's method to call
136                  * @param[in] r Request to handle.
137                  */
138                 template <TVerbCallback callback>
139                 static void verb(afb_req_t r)
140                 {
141                         assert(r != nullptr);
142
143                         afb_api_t handle = afb_req_get_api(r);
144                         if (handle)
145                         {
146                                 void* userdata = afb_api_get_userdata(handle);
147                                 if (userdata)
148                                 {
149                                         TApi* api = reinterpret_cast<TApi*>(userdata);
150                                         (api->*callback)(afb::req(r));
151                                 }
152                                 else
153                                 {
154                                         afb_req_fail(r, "Failed to get the API object!", nullptr);
155                                 }
156                         }
157                         else
158                         {
159                                 afb_req_fail(r, "Failed to get the corresponding API from the query!", nullptr);
160                         }
161                 }
162
163                 /**
164                  * @brief Verb callback for a verb added using @c afb::api::add_verb.
165                  * @tparam callback TApi's const method to call.
166                  * @param[in] req Request to handle.
167                  */
168                 template <TVerbCallbackConst callback>
169                 static void verb(afb_req_t r)
170                 {
171                         assert(r != nullptr);
172
173                         afb_api_t handle = afb_req_get_api(r);
174                         if (handle)
175                         {
176                                 void* userdata = afb_api_get_userdata(handle);
177                                 if (userdata)
178                                 {
179                                         TApi* api = reinterpret_cast<TApi*>(userdata);
180                                         (api->*callback)(afb::req(r));
181                                 }
182                                 else
183                                 {
184                                         afb_req_fail(r, "Failed to get the API object!", nullptr);
185                                 }
186                         }
187                         else
188                         {
189                                 afb_req_fail(r, "Failed to get the corresponding API from the query!", nullptr);
190                         }
191                 }
192         };
193
194         /**
195          * @brief Base class for API implementation.
196          * @tparam TApi The Api's concrete class.
197          * @tparam TTraits The Api's static callback implementation.
198          */
199         template <
200                 typename TApi,
201                 typename TTraits = ApiTraits<TApi>
202         >
203         class base_api_t
204         {
205                 friend TTraits;
206
207         public:
208                 using Traits = TTraits;
209
210         private:
211                 // Non-copyable
212                 base_api_t(const base_api_t&) = delete;
213                 base_api_t& operator=(const base_api_t&) = delete;
214
215         protected:
216                 afb_api_t handle_;
217
218                 /**
219                  * @brief Default constructor.
220                  */
221                 explicit base_api_t() = default;
222
223                 /**
224                  * @brief Move constructor.
225                  */
226                 explicit base_api_t(base_api_t&&) = default;
227
228                 /**
229                  * @brief Add a verb to an API.
230                  * @param[in] api API on which the verb should be added.
231                  * @param[in] verb Verb's name.
232                  * @param[in] info Verb's description.
233                  * @param[in] auth Verb's permissions required.
234                  * @param[in] session Verb's session handling.
235                  * @param[in] glob is the verb glob name.
236                  * @return Zero if success, non-zero otherwise.
237                  */
238                 template <typename TTraits::TVerbCallback Callback>
239                 int add_verb(const std::string& verb, const std::string& info, void* vcbdata = nullptr, const struct afb_auth* auth = nullptr, uint32_t session = AFB_SESSION_NONE_X2, int glob = 0)
240                 {
241                         return afb_api_add_verb(
242                                 handle_,
243                                 verb.c_str(),
244                                 info == "" ? nullptr : info.c_str(),
245                                 TTraits::template verb<Callback>,
246                                 vcbdata,
247                                 auth,
248                                 session,
249                                 glob
250                         );
251                 }
252
253                 /**
254                  * @brief Add a verb to an API.
255                  * @param[in] api API on which the verb should be added.
256                  * @param[in] verb Verb's name.
257                  * @param[in] info Verb's description.
258                  * @param[in] auth Verb's permissions required.
259                  * @param[in] session Verb's session handling.
260                  * @param[in] glob is the verb glob name.
261                  * @return Zero if success, non-zero otherwise.
262                  */
263                 template <typename TTraits::TVerbCallbackConst Callback>
264                 int add_verb(const std::string& verb, const std::string& info, void* vcbdata = nullptr, const struct afb_auth* auth = nullptr, uint32_t session = AFB_SESSION_NONE_X2, int glob = 0)
265                 {
266                         return afb_api_add_verb(
267                                 handle_,
268                                 verb.c_str(),
269                                 info == "" ? nullptr : info.c_str(),
270                                 TTraits::template verb<Callback>,
271                                 vcbdata,
272                                 auth,
273                                 session,
274                                 glob
275                         );
276                 }
277
278         public:
279                 /**
280                  * @brief Move assignation operator.
281                  */
282                 base_api_t& operator=(base_api_t&&) = default;
283
284                 /**
285                  * @brief Get the API's handle.
286                  * @return The API's handle.
287                  */
288                 afb_api_t handle() const { return handle_; }
289
290                 /**
291                  * @brief Implicit conversion to C handle.
292                  * @return The API's handle.
293                  */
294                 operator afb_api_t() const { return handle_; }
295
296                 /**
297                  * @brief Destructor.
298                  */
299                 virtual ~base_api_t()
300                 {
301                         if (handle_ && afb_api_delete_api(handle_))
302                                 AFB_API_ERROR(handle_, "Failed to delete API.");
303                 }
304
305                 /**
306                  * @brief Called by the binder during the API's pre-init phase.
307                  * @param[in] handle Handle representing the API on the binder's side.
308                  * @return Zero if success, non-zero otherwise.
309                  */
310                 virtual int preinit(afb_api_t handle) { return 0; }
311
312                 /**
313                  * @brief Called by the binder during the API's init phase.
314                  * @return Zero on success, non-zero otherwise.
315                  */
316                 virtual int init() { return 0; }
317
318                 /**
319                  * @brief Called by the binder when an event is received for this API.
320                  * @param[in] name Event's name.
321                  * @param[in] arg Event's argument.
322                  */
323                 virtual void event(const std::string& name, json_object* arg) { }
324         };
325 }