Make the object inherits the 'raw' class
[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::*)(afb_req_t);
61
62                 /***
63                  * @brief TApi's const method pointer.
64                  */
65                 using TVerbCallbackConst = void(TApi::*)(afb_req_t) 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->handle_ = 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] req Request to handle.
135                  */
136                 template <TVerbCallback callback>
137                 static void verb(afb_req_t req)
138                 {
139                         assert(req != nullptr);
140
141                         afb_api_t handle = afb_req_get_api(req);
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)(req);
149                                 }
150                                 else
151                                 {
152                                         afb_req_fail(req, "Failed to get the API object!", nullptr);
153                                 }
154                         }
155                         else
156                         {
157                                 afb_req_fail(req, "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 req)
168                 {
169                         assert(req != nullptr);
170
171                         afb_api_t handle = afb_req_get_api(req);
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)(req);
179                                 }
180                                 else
181                                 {
182                                         afb_req_fail(req, "Failed to get the API object!", nullptr);
183                                 }
184                         }
185                         else
186                         {
187                                 afb_req_fail(req, "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                 afb_api_t handle_;
216
217                 /**
218                  * @brief Default constructor.
219                  */
220                 explicit base_api_t() = default;
221
222                 /**
223                  * @brief Move constructor.
224                  */
225                 explicit base_api_t(base_api_t&&) = default;
226
227                 /**
228                  * @brief Add a verb to an API.
229                  * @param[in] api API on which the verb should be added.
230                  * @param[in] verb Verb's name.
231                  * @param[in] info Verb's description.
232                  * @param[in] auth Verb's permissions required.
233                  * @param[in] session Verb's session handling.
234                  * @param[in] glob is the verb glob name.
235                  * @return Zero if success, non-zero otherwise.
236                  */
237                 template <typename TTraits::TVerbCallback Callback>
238                 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)
239                 {
240                         return afb_api_add_verb(
241                                 handle_,
242                                 verb.c_str(),
243                                 info == "" ? nullptr : info.c_str(),
244                                 TTraits::template verb<Callback>,
245                                 vcbdata,
246                                 auth,
247                                 session,
248                                 glob
249                         );
250                 }
251
252                 /**
253                  * @brief Add a verb to an API.
254                  * @param[in] api API on which the verb should be added.
255                  * @param[in] verb Verb's name.
256                  * @param[in] info Verb's description.
257                  * @param[in] auth Verb's permissions required.
258                  * @param[in] session Verb's session handling.
259                  * @param[in] glob is the verb glob name.
260                  * @return Zero if success, non-zero otherwise.
261                  */
262                 template <typename TTraits::TVerbCallbackConst Callback>
263                 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)
264                 {
265                         return afb_api_add_verb(
266                                 handle_,
267                                 verb.c_str(),
268                                 info == "" ? nullptr : info.c_str(),
269                                 TTraits::template verb<Callback>,
270                                 vcbdata,
271                                 auth,
272                                 session,
273                                 glob
274                         );
275                 }
276
277         public:
278                 /**
279                  * @brief Move assignation operator.
280                  */
281                 base_api_t& operator=(base_api_t&&) = default;
282
283                 /**
284                  * @brief Get the API's handle.
285                  * @return The API's handle.
286                  */
287                 afb_api_t handle() const { return handle_; }
288
289                 /**
290                  * @brief Implicit conversion to C handle.
291                  * @return The API's handle.
292                  */
293                 operator afb_api_t() const { return handle_; }
294
295                 /**
296                  * @brief Destructor.
297                  */
298                 virtual ~base_api_t()
299                 {
300                         if (handle_ && afb_api_delete_api(handle_))
301                                 AFB_API_ERROR(handle_, "Failed to delete API.");
302                 }
303
304                 /**
305                  * @brief Called by the binder during the API's pre-init phase.
306                  * @param[in] handle Handle representing the API on the binder's side.
307                  * @return Zero if success, non-zero otherwise.
308                  */
309                 virtual int preinit(afb_api_t handle) { return 0; }
310
311                 /**
312                  * @brief Called by the binder during the API's init phase.
313                  * @return Zero on success, non-zero otherwise.
314                  */
315                 virtual int init() { return 0; }
316
317                 /**
318                  * @brief Called by the binder when an event is received for this API.
319                  * @param[in] name Event's name.
320                  * @param[in] arg Event's argument.
321                  */
322                 virtual void event(const std::string& name, json_object* arg) { }
323         };
324 }