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