GCC Code Coverage Report


Directory: src/gate/
File: src/gate/tech/microservices.c
Date: 2025-09-22 22:57: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* self = (gate_microservice_base_t*)thisptr;
332 gate_property_t const* prop;
333
334 do
335 {
336 ✗ prop = gate_property_member_get(&self->parameters, name);
337 ✗ if (prop)
338 {
339 ✗ if (ptr_output_type)
340 {
341 ✗ *ptr_output_type = gate_property_get_type(prop);
342 }
343 ✗ ret = GATE_RESULT_OK;
344 }
345 else
346 {
347 ✗ ret = GATE_RESULT_NOMATCH;
348 }
349 } while (0);
350
351 ✗ return ret;
352 }
353 ✗ static gate_result_t msb_get_parameter(void* thisptr, gate_string_t const* name, gate_property_t* ptr_output_value)
354 {
355 ✗ gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
356 ✗ gate_microservice_base_t* self = (gate_microservice_base_t*)thisptr;
357 gate_property_t const* prop;
358
359 do
360 {
361 ✗ prop = gate_property_member_get(&self->parameters, name);
362 ✗ if (prop)
363 {
364 ✗ if (ptr_output_value)
365 {
366 ✗ if (NULL == gate_property_copy(ptr_output_value, prop))
367 {
368 ✗ ret = GATE_RESULT_OUTOFMEMORY;
369 ✗ break;
370 }
371 }
372 ✗ ret = GATE_RESULT_OK;
373 }
374 else
375 {
376 ✗ ret = GATE_RESULT_NOMATCH;
377 }
378 } while (0);
379
380 ✗ return ret;
381 }
382 ✗ static gate_result_t msb_set_parameter(void* thisptr, gate_string_t const* name, gate_property_t const* value)
383 {
384 ✗ gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
385 ✗ gate_microservice_base_t* self = (gate_microservice_base_t*)thisptr;
386 gate_property_t const* prop;
387
388 do
389 {
390 ✗ prop = gate_property_member_get(&self->parameters, name);
391 ✗ if (prop)
392 {
393 ✗ if (gate_property_get_type(prop) == gate_property_get_type(value))
394 {
395 ✗ if (NULL == gate_property_member_add(&self->parameters, name, value))
396 {
397 ✗ ret = GATE_RESULT_OUTOFMEMORY;
398 }
399 else
400 {
401 ✗ ret = GATE_RESULT_OK;
402 }
403 }
404 else
405 {
406 ✗ ret = GATE_RESULT_INCORRECTTYPE;
407 }
408 }
409 else
410 {
411 ✗ ret = GATE_RESULT_NOMATCH;
412 }
413 } while (0);
414
415 ✗ return ret;
416 }
417
418
419 static GATE_INTERFACE_VTBL(gate_microservice) gate_msb_vtbl;
420 ✗ static void gate_init_msb_vtbl()
421 {
422 ✗ if (!gate_msb_vtbl.get_interface_name)
423 {
424 GATE_INTERFACE_VTBL(gate_microservice) const local_vtbl =
425 {
426 &msb_get_interface_name,
427 &msb_release,
428 &msb_retain,
429
430 &msb_start,
431 &msb_stop,
432 &msb_get_status,
433
434 &msb_setup,
435 &msb_get_address,
436 &msb_get_condition_bits,
437
438 &msb_process_message,
439 &msb_process_object,
440 &msb_invoke,
441
442 &msb_get_parameter_names,
443 &msb_get_parameter_type,
444 &msb_get_parameter,
445 &msb_set_parameter
446 };
447 ✗ gate_msb_vtbl = local_vtbl;
448 }
449 ✗ }
450
451
452 ✗ gate_microservice_base_t* gate_microservice_base_create(gate_size_t data_size, void* user_param)
453 {
454 ✗ gate_microservice_base_t* ret = NULL;
455 ✗ gate_microservice_base_t* impl = NULL;
456 do
457 {
458 ✗ impl = (gate_microservice_base_t*)gate_mem_alloc(sizeof(gate_microservice_base_t) + data_size);
459 ✗ if (impl == NULL)
460 {
461 ✗ break;
462 }
463
464 ✗ gate_mem_clear(impl, sizeof(gate_microservice_base_t) + data_size);
465 ✗ gate_init_msb_vtbl();
466 ✗ impl->vtbl = &gate_msb_vtbl;
467
468 ✗ gate_atomic_int_init(&impl->ref_counter, 1);
469 ✗ impl->user_param = user_param;
470 ✗ gate_atomic_int_init(&impl->status, GATE_MICROSERVICE_STATUS_OFFLINE);
471
472 ✗ gate_string_create_empty(&impl->address);
473 ✗ impl->host = NULL;
474 ✗ if (NULL == gate_property_create_object(&impl->parameters))
475 {
476 /* error */
477 ✗ break;
478 }
479
480 ✗ impl->data_ptr = &impl->custom_data;
481
482 ✗ ret = impl;
483 ✗ impl = NULL;
484 } while (0);
485
486 ✗ if (impl != NULL)
487 {
488 ✗ msb_destroy(impl);
489 }
490
491 ✗ return ret;
492 }
493
494 ✗ gate_result_t gate_microservice_encode_address(gate_string_t const* name, gate_string_t const* instance, gate_string_t* output_address)
495 {
496 ✗ gate_result_t ret = GATE_RESULT_FAILED;
497 ✗ gate_strbuilder_t builder = GATE_INIT_EMPTY;
498 do
499 {
500 ✗ gate_strbuilder_create(&builder, gate_string_length(name) + gate_string_length(instance) + 4);
501 ✗ gate_strbuilder_append_string(&builder, name);
502 ✗ gate_strbuilder_append_cstr(&builder, ".");
503 ✗ gate_strbuilder_append_string(&builder, instance);
504
505 ✗ if (NULL == gate_strbuilder_to_string(&builder, output_address))
506 {
507 ✗ ret = GATE_RESULT_OUTOFMEMORY;
508 ✗ break;
509 }
510 ✗ ret = GATE_RESULT_OK;
511 } while (0);
512
513 ✗ gate_strbuilder_release(&builder);
514 ✗ return ret;
515 }
516
517 ✗ gate_result_t gate_microservice_decode_address(gate_string_t const* address, gate_string_t* output_name, gate_string_t* output_instance)
518 {
519 ✗ gate_size_t pos = gate_string_char_pos(address, '.', 0);
520 ✗ if (pos == GATE_STR_NPOS)
521 {
522 ✗ return GATE_RESULT_INVALIDINPUT;
523 }
524 else
525 {
526 ✗ if (output_name)
527 {
528 ✗ if (NULL == gate_string_substr(output_name, address, 0, pos))
529 {
530 ✗ return GATE_RESULT_OUTOFMEMORY;
531 }
532 }
533 ✗ if (output_instance)
534 {
535 ✗ if (NULL == gate_string_substr(output_instance, address, pos + 1, GATE_STR_NPOS))
536 {
537 ✗ if (output_name)
538 {
539 ✗ gate_string_release(output_name);
540 }
541 ✗ return GATE_RESULT_OUTOFMEMORY;
542 }
543 }
544 ✗ return GATE_RESULT_OK;
545 }
546 }
547
548 ✗ gate_result_t gate_microservice_base_set_condition_bits(gate_microservice_base_t* service, gate_uint32_t bits)
549 {
550 ✗ gate_int32_t add_bits = (gate_int32_t)bits;
551 gate_int32_t old_bits, new_bits;
552 ✗ unsigned retry_counter = 32;
553 ✗ if (!service)
554 {
555 ✗ return GATE_RESULT_INVALIDARG;
556 }
557 ✗ while (retry_counter-- != 0)
558 {
559 ✗ old_bits = gate_atomic_int_get(&service->condition_bits);
560 ✗ new_bits = old_bits | add_bits;
561 ✗ if (old_bits == gate_atomic_int_xchg_if(&service->condition_bits, old_bits, new_bits))
562 {
563 ✗ return GATE_RESULT_OK;
564 }
565
566 /* atomic concurrency issue detected, bits were changed by another thread */
567 ✗ gate_thread_yield();
568 }
569 ✗ return GATE_RESULT_FAILED;
570 }
571
572 ✗ gate_result_t gate_microservice_base_clear_condition_bits(gate_microservice_base_t* service, gate_uint32_t bits)
573 {
574 ✗ gate_int32_t del_bits = (gate_int32_t)bits;
575 gate_int32_t old_bits, new_bits;
576 ✗ unsigned retry_counter = 32;
577 ✗ if (!service)
578 {
579 ✗ return GATE_RESULT_INVALIDARG;
580 }
581 ✗ while (retry_counter-- != 0)
582 {
583 ✗ old_bits = gate_atomic_int_get(&service->condition_bits);
584 ✗ new_bits = old_bits & (~del_bits);
585 ✗ if (old_bits == gate_atomic_int_xchg_if(&service->condition_bits, old_bits, new_bits))
586 {
587 ✗ return GATE_RESULT_OK;
588 }
589
590 /* atomic concurrency issue detected, bits were changed by another thread */
591 ✗ gate_thread_yield();
592 }
593 ✗ return GATE_RESULT_FAILED;
594 }
595