libamxb  4.8.2
Bus Agnostic C API
amxb_ba_subscribe.c
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** SPDX-License-Identifier: BSD-2-Clause-Patent
4 **
5 ** SPDX-FileCopyrightText: Copyright (c) 2023 SoftAtHome
6 **
7 ** Redistribution and use in source and binary forms, with or without modification,
8 ** are permitted provided that the following conditions are met:
9 **
10 ** 1. Redistributions of source code must retain the above copyright notice,
11 ** this list of conditions and the following disclaimer.
12 **
13 ** 2. Redistributions in binary form must reproduce the above copyright notice,
14 ** this list of conditions and the following disclaimer in the documentation
15 ** and/or other materials provided with the distribution.
16 **
17 ** Subject to the terms and conditions of this license, each copyright holder
18 ** and contributor hereby grants to those receiving rights under this license
19 ** a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
20 ** (except for failure to satisfy the conditions of this license) patent license
21 ** to make, have made, use, offer to sell, sell, import, and otherwise transfer
22 ** this software, where such license applies only to those patent claims, already
23 ** acquired or hereafter acquired, licensable by such copyright holder or contributor
24 ** that are necessarily infringed by:
25 **
26 ** (a) their Contribution(s) (the licensed copyrights of copyright holders and
27 ** non-copyrightable additions of contributors, in source or binary form) alone;
28 ** or
29 **
30 ** (b) combination of their Contribution(s) with the work of authorship to which
31 ** such Contribution(s) was added by such copyright holder or contributor, if,
32 ** at the time the Contribution is added, such addition causes such combination
33 ** to be necessarily infringed. The patent license shall not apply to any other
34 ** combinations which include the Contribution.
35 **
36 ** Except as expressly stated above, no rights or licenses from any copyright
37 ** holder or contributor is granted under this license, whether expressly, by
38 ** implication, estoppel or otherwise.
39 **
40 ** DISCLAIMER
41 **
42 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
43 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
46 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
49 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
51 ** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 **
53 ****************************************************************************/
54 
55 #ifndef _GNU_SOURCE
56 #define _GNU_SOURCE
57 #endif
58 
59 #include <stdlib.h>
60 #include <errno.h>
61 #include <fcntl.h>
62 #include <string.h>
63 
64 #include <amxc/amxc.h>
65 #include <amxp/amxp.h>
66 #include <amxp/amxp_expression.h>
67 
68 #include <amxd/amxd_common.h>
69 #include <amxd/amxd_dm.h>
70 #include <amxd/amxd_object.h>
71 #include <amxd/amxd_object_event.h>
72 #include <amxd/amxd_path.h>
73 
74 #include <amxb/amxb_be_intf.h>
75 #include <amxb/amxb.h>
76 
77 #include "amxb_priv.h"
78 
80  const char* path,
81  const char* expression,
82  amxp_slot_fn_t slot_cb,
83  void* priv) {
84  int retval = -1;
85  amxd_dm_t* dm = ctx->dm;
86  amxd_object_t* object = amxd_dm_findf(dm, "%s", path);
87  amxp_signal_t* signal = NULL;
88  amxc_string_t local_expr;
89  amxc_htable_it_t* sub_hit = NULL;
90 
91  amxc_string_init(&local_expr, 0);
92 
93  when_null(object, exit);
94 
95  signal = amxp_sigmngr_find_signal(&ctx->sigmngr, path);
96  if(signal == NULL) {
97  amxp_sigmngr_add_signal(&ctx->sigmngr, path);
98  }
99  retval = amxp_slot_connect(&ctx->sigmngr, path, expression, slot_cb, priv);
100  when_failed(retval, exit);
101 
102  if(amxc_htable_contains(&ctx->subscriptions, path)) {
103  goto exit;
104  }
105 
106  sub_hit = (amxc_htable_it_t*) calloc(1, sizeof(amxc_htable_it_t));
107  amxc_htable_insert(&ctx->subscriptions, path, sub_hit);
108 
109  amxc_string_appendf(&local_expr,
110  "object starts with \"%s.\" || path starts with \"%s.\"",
111  path,
112  path);
113  retval = amxp_slot_connect(&ctx->dm->sigmngr,
114  "*",
115  amxc_string_get(&local_expr, 0),
117  sub_hit);
118 
119 exit:
120  amxc_string_clean(&local_expr);
121  return retval;
122 }
123 
125  const char* path,
126  const char* expression,
127  amxp_slot_fn_t slot_cb,
128  void* priv) {
129  int retval = -1;
130  amxp_signal_t* signal = NULL;
131 
132  signal = amxp_sigmngr_find_signal(&ctx->sigmngr, path);
133  if(signal == NULL) {
134  const amxb_be_funcs_t* fns = ctx->bus_fn;
135  if(amxb_is_valid_be_func(fns, subscribe, fns->subscribe)) {
136  retval = fns->subscribe(ctx->bus_ctx, path);
137  when_failed(retval, exit);
138  amxp_sigmngr_add_signal(&ctx->sigmngr, path);
139  } else {
141  goto exit;
142  }
143  }
144  amxp_slot_connect(&ctx->sigmngr, path, expression, slot_cb, priv);
145 
146  retval = 0;
147 
148 exit:
149  return retval;
150 }
151 
152 static void amxb_build_path(amxc_var_t* info, amxd_path_t* path) {
153  amxc_var_t* obj_data = GETI_ARG(info, 0);
154  uint32_t type = amxc_var_dyncast(uint32_t, GET_ARG(obj_data, "type_id"));
155  const char* obj_path = GET_CHAR(obj_data, "path");
156  uint32_t index = amxc_var_dyncast(uint32_t, GET_ARG(obj_data, "index"));
157  char* spath = NULL;
158 
159  free(amxd_path_get_fixed_part(path, true));
160  spath = strdup(amxd_path_get(path, AMXD_OBJECT_TERMINATE));
161 
162  if(type == amxd_object_instance) {
163  amxd_path_setf(path, false, "%s%d.%s", obj_path, index, spath);
164  } else {
165  amxd_path_setf(path, false, "%s%s", obj_path, spath);
166  }
167 
168  free(spath);
169 }
170 
171 static int amxb_build_expression(amxc_string_t* str_expr,
172  amxd_path_t* obj_path,
173  const char* expression) {
174  amxp_expr_status_t status = amxp_expr_status_ok;
175  const char* sep = "";
176  amxp_expr_t expr;
177 
178  if(amxd_path_is_search_path(obj_path)) {
179  amxc_string_setf(str_expr, "%s", amxd_path_get(obj_path, AMXD_OBJECT_TERMINATE));
180  amxc_string_replace(str_expr, "'", "\"", UINT32_MAX);
181  amxc_string_prependf(str_expr, "path starts with search_path('");
182  amxc_string_appendf(str_expr, "')");
183  sep = " && ";
184  } else {
185  amxc_string_setf(str_expr, "%s", amxd_path_get(obj_path, AMXD_OBJECT_TERMINATE));
186  amxc_string_replace(str_expr, "'", "\"", UINT32_MAX);
187  amxc_string_prependf(str_expr, "(path starts with '");
188  amxc_string_appendf(str_expr, "' || !(contains('path') && contains('object')))");
189  sep = " && ";
190  }
191 
192  if((expression != NULL) && (*expression != 0)) {
193  amxc_string_appendf(str_expr, "%s(%s)", sep, expression);
194  }
195 
196  if(!amxc_string_is_empty(str_expr)) {
197  status = amxp_expr_init(&expr, amxc_string_get(str_expr, 0));
198  amxp_expr_clean(&expr);
199  }
200 
201  return status == amxp_expr_status_ok ? 0 : -1;
202 }
203 
204 
206  const char* object,
207  const char* expression,
208  amxp_slot_fn_t slot_cb,
209  void* priv) {
210  int retval = -1;
211  char* obj_path = NULL;
212  amxc_var_t info;
213  amxd_path_t path;
214  amxb_request_t* req = NULL;
215  amxc_string_t rel_path;
216  amxc_string_t str_expr;
217 
218  amxd_path_init(&path, NULL);
219  amxc_var_init(&info);
220  amxc_string_init(&rel_path, 64);
221  amxc_string_init(&str_expr, 0);
222 
223  when_null(ctx, exit);
224  when_null(ctx->bus_ctx, exit);
225  when_null(object, exit);
226  when_null(slot_cb, exit);
227 
228  amxd_path_setf(&path, true, "%s", object);
229  if((path.type == amxd_path_invalid) ||
230  (path.type == amxd_path_reference) ||
231  (path.type == amxd_path_supported)) {
232  goto exit;
233  }
234  obj_path = amxd_path_get_fixed_part(&path, false);
235 
236  retval = amxb_describe(ctx, obj_path, 0, &info, 5);
237  if(retval == 0) {
238  free(obj_path);
239  amxb_build_path(&info, &path);
240  obj_path = amxd_path_get_fixed_part(&path, false);
241  }
242 
243  when_null(obj_path, exit);
244 
245  amxc_var_set_type(&info, AMXC_VAR_ID_HTABLE);
246  amxc_var_add_key(cstring_t, &info, "expression", expression);
247  req = amxb_async_call(ctx, obj_path, "_subscribe", &info, NULL, NULL);
248  amxb_close_request(&req);
249 
250  if(*obj_path != 0) {
251  obj_path[strlen(obj_path) - 1] = 0;
252  }
253 
254  retval = amxb_build_expression(&str_expr, &path, expression);
255  when_failed(retval, exit);
256  expression = amxc_string_get(&str_expr, 0);
257 
258  if(ctx->dm != NULL) {
259  retval = amxb_subscribe_local_impl(ctx, obj_path, expression, slot_cb, priv);
260  when_true(retval == 0, exit);
261  }
262 
263  retval = amxb_subscribe_be_impl(ctx, obj_path, expression, slot_cb, priv);
264 
265 exit:
266  amxc_string_clean(&str_expr);
267  amxc_string_clean(&rel_path);
268  amxd_path_clean(&path);
269  amxc_var_clean(&info);
270  free(obj_path);
271  return retval;
272 }
273 
275  const char* object,
276  amxp_slot_fn_t slot_cb,
277  void* priv) {
278  int retval = -1;
279  const amxb_be_funcs_t* fns = NULL;
280  amxb_request_t* req = NULL;
281  amxp_signal_t* signal = NULL;
282  char* obj_path = NULL;
283  amxc_var_t info;
284  amxd_path_t path;
285 
286  amxd_path_init(&path, NULL);
287  amxc_var_init(&info);
288 
289  when_null(ctx, exit);
290  when_null(ctx->bus_ctx, exit);
291  when_str_empty(object, exit);
292 
293  amxd_path_setf(&path, true, "%s", object);
294  if((path.type == amxd_path_invalid) ||
295  (path.type == amxd_path_reference) ||
296  (path.type == amxd_path_supported)) {
297  goto exit;
298  }
299  obj_path = amxd_path_get_fixed_part(&path, false);
300 
301  retval = amxb_describe(ctx, obj_path, 0, &info, 5);
302  if(retval == 0) {
303  free(obj_path);
304  amxb_build_path(&info, &path);
305  obj_path = amxd_path_get_fixed_part(&path, false);
306  }
307 
308  when_null(obj_path, exit);
309 
310  amxc_var_set_type(&info, AMXC_VAR_ID_HTABLE);
311  req = amxb_async_call(ctx, obj_path, "_unsubscribe", &info, NULL, NULL);
312  amxb_close_request(&req);
313 
314  if(*obj_path != 0) {
315  obj_path[strlen(obj_path) - 1] = 0;
316  }
317 
318  retval = -1;
319  signal = amxp_sigmngr_find_signal(&ctx->sigmngr, obj_path);
320  when_null(signal, exit);
321 
322  if(priv == NULL) {
323  amxp_slot_disconnect(&ctx->sigmngr, obj_path, slot_cb);
324  } else {
325  amxp_slot_disconnect_signal_with_priv(&ctx->sigmngr, obj_path, slot_cb, priv);
326  }
327  retval = 0;
328  when_true(amxp_signal_has_slots(signal), exit);
329 
330  fns = ctx->bus_fn;
331  if(amxb_is_valid_be_func(fns, unsubscribe, fns->unsubscribe)) {
332  retval = fns->unsubscribe(ctx->bus_ctx,
333  obj_path);
334  } else {
335  retval = AMXB_STATUS_OK;
336  }
337 
338  amxp_signal_delete(&signal);
339 
340 exit:
341  free(obj_path);
342  amxd_path_clean(&path);
343  amxc_var_clean(&info);
344  return retval;
345 }
346 
348  const char* object,
349  const char* name,
350  amxc_var_t* data) {
351  int retval = -1;
352  amxd_object_t* obj = NULL;
353 
354  when_null(ctx, exit);
355  when_null(ctx->dm, exit);
356  when_null(ctx->bus_ctx, exit);
357  when_str_empty(object, exit);
358  when_str_empty(name, exit);
359 
360  obj = amxd_object_findf(amxd_dm_get_root(ctx->dm), "%s", object);
361 
362  if(obj != NULL) {
363  amxd_object_emit_signal(obj, name, data);
364  retval = amxd_status_ok;
365  } else {
366  retval = amxd_status_object_not_found;
367  }
368 
369 exit:
370  return retval;
371 }
Ambiorix bus agnostic API header file.
static int amxb_subscribe_be_impl(amxb_bus_ctx_t *ctx, const char *path, const char *expression, amxp_slot_fn_t slot_cb, void *priv)
static int amxb_build_expression(amxc_string_t *str_expr, amxd_path_t *obj_path, const char *expression)
static int amxb_subscribe_local_impl(amxb_bus_ctx_t *ctx, const char *path, const char *expression, amxp_slot_fn_t slot_cb, void *priv)
static void amxb_build_path(amxc_var_t *info, amxd_path_t *path)
Ambiorix Bus Backend Interface.
#define amxb_is_valid_be_func(ft, member, ptr)
Definition: amxb_priv.h:78
void PRIVATE amxb_dm_event_to_object_event(const char *const sig_name, const amxc_var_t *const data, void *const priv)
Definition: amxb_ba_priv.c:76
#define AMXB_ERROR_NOT_SUPPORTED_OP
Function/operation not supported.
Definition: amxb_error.h:110
#define AMXB_STATUS_OK
All ok.
Definition: amxb_error.h:86
int amxb_unsubscribe(amxb_bus_ctx_t *const ctx, const char *object, amxp_slot_fn_t slot_cb, void *priv)
Removes an event subscription.
int amxb_publish(amxb_bus_ctx_t *const ctx, const char *object, const char *name, amxc_var_t *data)
Publish an event for a specific object.
int amxb_subscribe(amxb_bus_ctx_t *const ctx, const char *object, const char *expression, amxp_slot_fn_t slot_cb, void *priv)
Subscribes for events of a object tree.
int amxb_close_request(amxb_request_t **req)
Closes a previously create remote function called context.
int amxb_describe(amxb_bus_ctx_t *const bus_ctx, const char *object, uint32_t flags, amxc_var_t *ret, int timeout)
Describes an object.
amxb_request_t * amxb_async_call(amxb_bus_ctx_t *const bus_ctx, const char *object, const char *method, amxc_var_t *args, amxb_be_done_cb_fn_t done_fn, void *priv)
Invokes a data model function.
The back-end interface structure.
amxb_be_subscribe_fn_t subscribe
amxb_be_unsubscribe_fn_t unsubscribe
const amxb_be_funcs_t * bus_fn
Definition: amxb_types.h:121
amxd_dm_t * dm
Definition: amxb_types.h:123
amxp_signal_mngr_t sigmngr
Definition: amxb_types.h:120
amxc_htable_t subscriptions
Definition: amxb_types.h:124
void * bus_ctx
Definition: amxb_types.h:122
A request structure.
Definition: amxb_types.h:138
static amxd_dm_t dm
Definition: test_amxb_e2e.c:85