GCC Code Coverage Report


Directory: src/gate/
File: src/gate/tech/microservices.c
Date: 2025-09-14 13:10:38
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