GCC Code Coverage Report


Directory: src/gate/
File: src/gate/tech/microservices.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 0 232 0.0%
Functions: 0 25 0.0%
Branches: 0 96 0.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/tech/microservices.h"
30 #include "gate/properties.h"
31 #include "gate/results.h"
32 #include "gate/threading.h"
33
34
35 static void msb_destroy(gate_microservice_base_t* self)
36 {
37 if (self->on_release)
38 {
39 self->on_release(self);
40 }
41 gate_property_destroy(&self->parameters);
42
43 gate_string_release(&self->address);
44
45 if (NULL != self->host)
46 {
47 gate_object_release(self->host);
48 self->host = NULL;
49 }
50
51 gate_mem_dealloc(self);
52 }
53
54 static char const* msb_get_interface_name(void* thisptr)
55 {
56 (void)thisptr;
57 return GATE_INTERFACE_NAME_MICROSERVICE;
58 }
59 static void msb_release(void* thisptr)
60 {
61 gate_microservice_base_t* self = (gate_microservice_base_t*)thisptr;
62 if (gate_atomic_int_dec(&self->ref_counter) == 0)
63 {
64 msb_destroy(self);
65 }
66 }
67 static int msb_retain(void* thisptr)
68 {
69 gate_microservice_base_t* self = (gate_microservice_base_t*)thisptr;
70 return gate_atomic_int_inc(&self->ref_counter);
71 }
72
73 static gate_bool_t msb_update_state(gate_microservice_base_t* self, gate_int32_t from_state, gate_int32_t to_state)
74 {
75 return from_state == gate_atomic_int_xchg_if(&self->status, from_state, to_state);
76 }
77 static void msb_set_state(gate_microservice_base_t* self, gate_int32_t state)
78 {
79 gate_atomic_int_set(&self->status, state);
80 }
81
82 static gate_result_t msb_setup(void* thisptr, gate_string_t const* instance_address, gate_microhost_t* host)
83 {
84 gate_microservice_base_t* self = (gate_microservice_base_t*)thisptr;
85
86 gate_result_t ret = GATE_RESULT_FAILED;
87 gate_microhost_t* old_host = NULL;
88 gate_string_t tmp;
89
90 do
91 {
92 if (!msb_update_state(self, GATE_MICROSERVICE_STATUS_OFFLINE, GATE_MICROSERVICE_STATUS_CONFIGURE))
93 {
94 return GATE_RESULT_INVALIDSTATE;
95 }
96
97 if (instance_address)
98 {
99 if (NULL == gate_string_clone(&tmp, instance_address))
100 {
101 ret = GATE_RESULT_OUTOFMEMORY;
102 break;
103 }
104 gate_string_release(&self->address);
105 gate_mem_copy(&self->address, &tmp, sizeof(tmp));
106 }
107
108 old_host = self->host;
109 self->host = host;
110 if (self->host)
111 {
112 gate_object_retain(self->host);
113 }
114
115 ret = GATE_RESULT_OK;
116 } while (0);
117
118 if (old_host)
119 {
120 gate_object_release(old_host);
121 }
122
123 msb_set_state(self, GATE_MICROSERVICE_STATUS_OFFLINE);
124 return ret;
125 }
126
127 static gate_result_t msb_get_address(void* thisptr, gate_string_t* ptr_output_address)
128 {
129 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
130 gate_microservice_base_t* self = (gate_microservice_base_t*)thisptr;
131
132 do
133 {
134 if (NULL == gate_string_clone(ptr_output_address, &self->address))
135 {
136 ret = GATE_RESULT_OUTOFMEMORY;
137 break;
138 }
139 ret = GATE_RESULT_OK;
140 } while (0);
141
142 return ret;
143 }
144 static gate_enumint_t msb_get_status(void* thisptr)
145 {
146 gate_microservice_base_t* self = (gate_microservice_base_t*)thisptr;
147 gate_uint32_t ret = (gate_uint32_t)gate_atomic_int_get(&self->status);
148 return ret;
149 }
150 static gate_result_t msb_get_condition_bits(void* thisptr, gate_enumint_t* ptr_bits)
151 {
152 gate_microservice_base_t* self = (gate_microservice_base_t*)thisptr;
153 gate_int32_t bits = gate_atomic_int_get(&self->condition_bits);
154 if (ptr_bits)
155 {
156 *ptr_bits = (gate_enumint_t)bits;
157 return GATE_RESULT_OK;
158 }
159 else
160 {
161 return GATE_RESULT_INVALIDARG;
162 }
163 }
164
165 static gate_result_t msb_start(void* thisptr)
166 {
167 gate_result_t ret = GATE_RESULT_FAILED;
168 gate_microservice_base_t* self = (gate_microservice_base_t*)thisptr;
169
170 do
171 {
172 if (!msb_update_state(self, GATE_MICROSERVICE_STATUS_OFFLINE, GATE_MICROSERVICE_STATUS_STARTING))
173 {
174 return GATE_RESULT_INVALIDSTATE;
175 }
176
177 if (self->host == NULL)
178 {
179 ret = GATE_RESULT_NOTREADY;
180 break;
181 }
182
183 if (self->on_start)
184 {
185 ret = self->on_start(self);
186 }
187 else
188 {
189 ret = GATE_RESULT_OK;
190 }
191
192 } while (0);
193
194
195 if (GATE_FAILED(ret))
196 {
197 msb_set_state(self, GATE_MICROSERVICE_STATUS_OFFLINE);
198 }
199 else
200 {
201 msb_set_state(self, GATE_MICROSERVICE_STATUS_ONLINE);
202 }
203
204 return ret;
205 }
206 static gate_result_t msb_stop(void* thisptr)
207 {
208 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
209 gate_microservice_base_t* self = (gate_microservice_base_t*)thisptr;
210
211 do
212 {
213 if (!msb_update_state(self, GATE_MICROSERVICE_STATUS_ONLINE, GATE_MICROSERVICE_STATUS_STOPPING))
214 {
215 ret = GATE_RESULT_INVALIDSTATE;
216 break;
217 }
218
219 if (self->on_stop)
220 {
221 ret = self->on_stop(self);
222 }
223 else
224 {
225 ret = GATE_RESULT_OK;
226 }
227
228 if (GATE_FAILED(ret))
229 {
230 msb_set_state(self, GATE_MICROSERVICE_STATUS_ERROR);
231 }
232 else
233 {
234 msb_set_state(self, GATE_MICROSERVICE_STATUS_OFFLINE);
235 }
236
237 } while (0);
238
239 return ret;
240 }
241
242 static gate_result_t msb_process_message(void* thisptr, gate_string_t const* source, gate_string_t const* destination,
243 gate_string_t const* msg_id, gate_string_t const* message, void* user_param)
244 {
245 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
246 gate_microservice_base_t* self = (gate_microservice_base_t*)thisptr;
247 (void)user_param;
248 do
249 {
250 if (self->on_message_received)
251 {
252 ret = self->on_message_received(self, source, destination, msg_id, message);
253 }
254
255 } while (0);
256
257 return ret;
258 }
259
260 static gate_result_t msb_process_object(void* thisptr, gate_string_t const* source, gate_string_t const* destination,
261 gate_string_t const* obj_id, gate_object_t* ptr_object, void* user_param)
262 {
263 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
264 gate_microservice_base_t* self = (gate_microservice_base_t*)thisptr;
265 (void)user_param;
266 do
267 {
268 if (self->on_object_received)
269 {
270 ret = self->on_object_received(self, source, destination, obj_id, ptr_object);
271 }
272
273 } while (0);
274
275 return ret;
276 }
277 static gate_result_t msb_invoke(void* thisptr, gate_string_t const* method, gate_struct_t const* request,
278 gate_struct_t* response)
279 {
280 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
281 gate_microservice_base_t* self = (gate_microservice_base_t*)thisptr;
282
283 do
284 {
285 if (self->on_invoke)
286 {
287 ret = self->on_invoke(self, method, request, response);
288 }
289
290 } while (0);
291
292 return ret;
293 }
294
295 static gate_result_t msb_get_parameter_names(void* thisptr, gate_array_t* ptr_output_names)
296 {
297 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
298 gate_microservice_base_t* self = (gate_microservice_base_t*)thisptr;
299
300 do
301 {
302 if (gate_property_get_type(&self->parameters) == GATE_PROPERTY_TYPE_OBJECT)
303 {
304 if (NULL == gate_property_member_names(&self->parameters, ptr_output_names))
305 {
306 ret = GATE_RESULT_OUTOFMEMORY;
307 }
308 else
309 {
310 ret = GATE_RESULT_OK;
311 }
312 }
313 else
314 {
315 if (NULL == gate_array_create_empty(ptr_output_names))
316 {
317 ret = GATE_RESULT_OUTOFMEMORY;
318 }
319 else
320 {
321 ret = GATE_RESULT_OK;
322 }
323 }
324 } while (0);
325
326 return ret;
327 }
328 static gate_result_t msb_get_parameter_type(void* thisptr, gate_string_t const* name, gate_uint32_t* ptr_output_type)
329 {
330 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
331 gate_microservice_base_t* const self = (gate_microservice_base_t*)thisptr;
332
333 do
334 {
335 gate_property_t const* prop = gate_property_member_get(&self->parameters, name);
336 if (prop)
337 {
338 if (ptr_output_type)
339 {
340 *ptr_output_type = gate_property_get_type(prop);
341 }
342 ret = GATE_RESULT_OK;
343 }
344 else
345 {
346 ret = GATE_RESULT_NOMATCH;
347 }
348 } while (0);
349
350 return ret;
351 }
352 static gate_result_t msb_get_parameter(void* thisptr, gate_string_t const* name, gate_property_t* ptr_output_value)
353 {
354 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
355 gate_microservice_base_t* const self = (gate_microservice_base_t*)thisptr;
356
357 do
358 {
359 gate_property_t const* const prop = gate_property_member_get(&self->parameters, name);
360 if (prop)
361 {
362 if (ptr_output_value)
363 {
364 if (NULL == gate_property_copy(ptr_output_value, prop))
365 {
366 ret = GATE_RESULT_OUTOFMEMORY;
367 break;
368 }
369 }
370 ret = GATE_RESULT_OK;
371 }
372 else
373 {
374 ret = GATE_RESULT_NOMATCH;
375 }
376 } while (0);
377
378 return ret;
379 }
380 static gate_result_t msb_set_parameter(void* thisptr, gate_string_t const* name, gate_property_t const* value)
381 {
382 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
383 gate_microservice_base_t* self = (gate_microservice_base_t*)thisptr;
384
385 do
386 {
387 gate_property_t const* prop = gate_property_member_get(&self->parameters, name);
388 if (prop)
389 {
390 if (gate_property_get_type(prop) == gate_property_get_type(value))
391 {
392 if (NULL == gate_property_member_add(&self->parameters, name, value))
393 {
394 ret = GATE_RESULT_OUTOFMEMORY;
395 }
396 else
397 {
398 ret = GATE_RESULT_OK;
399 }
400 }
401 else
402 {
403 ret = GATE_RESULT_INCORRECTTYPE;
404 }
405 }
406 else
407 {
408 ret = GATE_RESULT_NOMATCH;
409 }
410 } while (0);
411
412 return ret;
413 }
414
415
416 static GATE_INTERFACE_VTBL(gate_microservice) gate_msb_vtbl;
417 static void gate_init_msb_vtbl(void)
418 {
419 if (!gate_msb_vtbl.get_interface_name)
420 {
421 GATE_INTERFACE_VTBL(gate_microservice) const local_vtbl =
422 {
423 &msb_get_interface_name,
424 &msb_release,
425 &msb_retain,
426
427 &msb_start,
428 &msb_stop,
429 &msb_get_status,
430
431 &msb_setup,
432 &msb_get_address,
433 &msb_get_condition_bits,
434
435 &msb_process_message,
436 &msb_process_object,
437 &msb_invoke,
438
439 &msb_get_parameter_names,
440 &msb_get_parameter_type,
441 &msb_get_parameter,
442 &msb_set_parameter
443 };
444 gate_msb_vtbl = local_vtbl;
445 }
446 }
447
448
449 gate_microservice_base_t* gate_microservice_base_create(gate_size_t data_size, void* user_param)
450 {
451 gate_microservice_base_t* ret = NULL;
452 gate_microservice_base_t* impl = NULL;
453 do
454 {
455 impl = (gate_microservice_base_t*)gate_mem_alloc(sizeof(gate_microservice_base_t) + data_size);
456 if (impl == NULL)
457 {
458 break;
459 }
460
461 gate_mem_clear(impl, sizeof(gate_microservice_base_t) + data_size);
462 gate_init_msb_vtbl();
463 impl->vtbl = &gate_msb_vtbl;
464
465 gate_atomic_int_init(&impl->ref_counter, 1);
466 impl->user_param = user_param;
467 gate_atomic_int_init(&impl->status, GATE_MICROSERVICE_STATUS_OFFLINE);
468
469 gate_string_create_empty(&impl->address);
470 impl->host = NULL;
471 if (NULL == gate_property_create_object(&impl->parameters))
472 {
473 /* error */
474 break;
475 }
476
477 impl->data_ptr = &impl->custom_data;
478
479 ret = impl;
480 impl = NULL;
481 } while (0);
482
483 if (impl != NULL)
484 {
485 msb_destroy(impl);
486 }
487
488 return ret;
489 }
490
491 gate_result_t gate_microservice_encode_address(gate_string_t const* name, gate_string_t const* instance, gate_string_t* output_address)
492 {
493 gate_result_t ret = GATE_RESULT_FAILED;
494 gate_strbuilder_t builder = GATE_INIT_EMPTY;
495 do
496 {
497 gate_strbuilder_create(&builder, gate_string_length(name) + gate_string_length(instance) + 4);
498 gate_strbuilder_append_string(&builder, name);
499 gate_strbuilder_append_cstr(&builder, ".");
500 gate_strbuilder_append_string(&builder, instance);
501
502 if (NULL == gate_strbuilder_to_string(&builder, output_address))
503 {
504 ret = GATE_RESULT_OUTOFMEMORY;
505 break;
506 }
507 ret = GATE_RESULT_OK;
508 } while (0);
509
510 gate_strbuilder_release(&builder);
511 return ret;
512 }
513
514 gate_result_t gate_microservice_decode_address(gate_string_t const* address, gate_string_t* output_name, gate_string_t* output_instance)
515 {
516 gate_size_t pos = gate_string_char_pos(address, '.', 0);
517 if (pos == GATE_STR_NPOS)
518 {
519 return GATE_RESULT_INVALIDINPUT;
520 }
521 else
522 {
523 if (output_name)
524 {
525 if (NULL == gate_string_substr(output_name, address, 0, pos))
526 {
527 return GATE_RESULT_OUTOFMEMORY;
528 }
529 }
530 if (output_instance)
531 {
532 if (NULL == gate_string_substr(output_instance, address, pos + 1, GATE_STR_NPOS))
533 {
534 if (output_name)
535 {
536 gate_string_release(output_name);
537 }
538 return GATE_RESULT_OUTOFMEMORY;
539 }
540 }
541 return GATE_RESULT_OK;
542 }
543 }
544
545 gate_result_t gate_microservice_base_set_condition_bits(gate_microservice_base_t* service, gate_uint32_t bits)
546 {
547 gate_int32_t add_bits = (gate_int32_t)bits;
548 unsigned retry_counter = 32;
549 if (!service)
550 {
551 return GATE_RESULT_INVALIDARG;
552 }
553 while (retry_counter-- != 0)
554 {
555 gate_int32_t old_bits = gate_atomic_int_get(&service->condition_bits);
556 gate_int32_t new_bits = old_bits | add_bits;
557 if (old_bits == gate_atomic_int_xchg_if(&service->condition_bits, old_bits, new_bits))
558 {
559 return GATE_RESULT_OK;
560 }
561
562 /* atomic concurrency issue detected, bits were changed by another thread */
563 gate_thread_yield();
564 }
565 return GATE_RESULT_FAILED;
566 }
567
568 gate_result_t gate_microservice_base_clear_condition_bits(gate_microservice_base_t* service, gate_uint32_t bits)
569 {
570 gate_int32_t del_bits = (gate_int32_t)bits;
571 unsigned retry_counter = 32;
572 if (!service)
573 {
574 return GATE_RESULT_INVALIDARG;
575 }
576 while (retry_counter-- != 0)
577 {
578 gate_int32_t old_bits = gate_atomic_int_get(&service->condition_bits);
579 gate_int32_t new_bits = old_bits & (~del_bits);
580 if (old_bits == gate_atomic_int_xchg_if(&service->condition_bits, old_bits, new_bits))
581 {
582 return GATE_RESULT_OK;
583 }
584
585 /* atomic concurrency issue detected, bits were changed by another thread */
586 gate_thread_yield();
587 }
588 return GATE_RESULT_FAILED;
589 }
590