GCC Code Coverage Report


Directory: src/gate/
File: src/gate/tech/gateservices.c
Date: 2026-10-19 17:06:30
Exec Total Coverage
Lines: 380 786 48.3%
Functions: 36 59 61.0%
Branches: 109 365 29.9%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2026, 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/gateservices.h"
30 #include "gate/results.h"
31 #include "gate/utilities.h"
32 #include "gate/synchronization.h"
33 #include "gate/structs.h"
34 #include "gate/tech/microservices/webserver_service.h"
35 #include "gate/tech/microservices/timer_service.h"
36 #include "gate/tech/microservices/procrunner_service.h"
37 #include "gate/io/logging.h"
38 #include "gate/encode/yaml.h"
39 #include "gate/encode/json.h"
40
41
42
43 #define GATE_STRUCT_SERVICEHOST_ROOT_NAME "servicehost"
44
45 #define GATE_SERVICEHOST_CONFIG_SERVICE_NAME GATE_STRUCT_ROOT_NAME GATE_STRUCT_SEPARATOR GATE_STRUCT_SERVICEHOST_ROOT_NAME GATE_STRUCT_SEPARATOR "config_service"
46
47 static gate_struct_item_t const config_service_members[] =
48 {
49 GATE_STRUCT_ITEM_EX(gate_servicehost_config_service_t, GATE_TYPE_STRING, name, "Service class name", GATE_STRUCT_FLAG_DEFAULT),
50 GATE_STRUCT_ITEM_EX(gate_servicehost_config_service_t, GATE_TYPE_STRING, instance, "Service instance identifier", GATE_STRUCT_FLAG_DEFAULT),
51 GATE_STRUCT_ITEM_EX(gate_servicehost_config_service_t, GATE_TYPE_ARRAYLIST_STRING, msg_subscriptions, "Message subscriptions", GATE_STRUCT_FLAG_DEFAULT),
52 GATE_STRUCT_ITEM_EX(gate_servicehost_config_service_t, GATE_TYPE_ARRAYLIST_STRING, obj_subscriptions, "Object subscriptions", GATE_STRUCT_FLAG_DEFAULT),
53 GATE_STRUCT_ITEM_EX(gate_servicehost_config_service_t, GATE_TYPE_STRING, service_group, "Service execution group name", GATE_STRUCT_FLAG_DEFAULT),
54 GATE_STRUCT_ITEM_EX(gate_servicehost_config_service_t, GATE_TYPE_BOOL, autostart, "Automatic start of service", GATE_STRUCT_FLAG_DEFAULT),
55 GATE_STRUCT_ITEM_EX(gate_servicehost_config_service_t, GATE_TYPE_UI32, startorder, "Start order of service", GATE_STRUCT_FLAG_DEFAULT),
56 GATE_STRUCT_ITEM_EX(gate_servicehost_config_service_t, GATE_TYPE_PROPERTY, parameters, "Service internal parameters", GATE_STRUCT_FLAG_DEFAULT)
57 };
58
59 static gate_struct_descriptor_t const config_service_descriptor =
60 {
61 GATE_SERVICEHOST_CONFIG_SERVICE_NAME,
62 config_service_members,
63 sizeof(config_service_members) / sizeof(config_service_members[0]),
64 sizeof(gate_servicehost_config_service_t)
65 };
66
67 ✗ gate_result_t gate_servicehost_config_service_copy_constructor(void* dest, void const* src)
68 {
69 gate_result_t result;
70 ✗ gate_servicehost_config_service_t* ptr = (gate_servicehost_config_service_t*)dest;
71 ✗ gate_struct_t const* ptr_src = (gate_struct_t const*)src;
72
73 ✗ gate_mem_clear(&ptr->struct_base, sizeof(gate_servicehost_config_service_t));
74 ✗ if (ptr_src)
75 {
76 ✗ result = gate_struct_copy(&ptr->struct_base, ptr_src);
77 }
78 else
79 {
80 ✗ result = gate_struct_init(&ptr->struct_base, &config_service_descriptor);
81 }
82 ✗ return result;
83 }
84
85 ✗ gate_result_t gate_servicehost_config_service_init(gate_struct_t* ptr)
86 {
87 ✗ gate_result_t result = gate_servicehost_config_service_copy_constructor(ptr, NULL);
88 ✗ return result;
89 }
90
91
92
93 #define GATE_STRUCT_GSVC_CONFIG_NAME GATE_STRUCT_ROOT_NAME GATE_STRUCT_SEPARATOR GATE_STRUCT_SERVICEHOST_ROOT_NAME GATE_STRUCT_SEPARATOR "config"
94
95 static gate_struct_item_t const config_members[] =
96 {
97 GATE_STRUCT_ITEM(gate_servicehost_config_t, GATE_TYPE_STRING, id),
98 GATE_STRUCT_ITEM(gate_servicehost_config_t, GATE_TYPE_STRING, version),
99 GATE_STRUCT_ITEM(gate_servicehost_config_t, GATE_TYPE_ARRAYLIST_STRUCT, services)
100 };
101
102 static gate_struct_descriptor_t const config_descriptor =
103 {
104 GATE_STRUCT_GSVC_CONFIG_NAME,
105 config_members,
106 sizeof(config_members) / sizeof(config_members[0]),
107 sizeof(gate_servicehost_config_t)
108 };
109
110
111 ✗ void* gate_servicehost_config_copy_constructor(void* dest, void const* src)
112 {
113 ✗ void* ret = NULL;
114 gate_result_t result;
115 ✗ gate_servicehost_config_t* ptr = (gate_servicehost_config_t*)dest;
116 ✗ gate_mem_clear(ptr, sizeof(gate_servicehost_config_t));
117
118 ✗ if (src)
119 {
120 ✗ result = gate_struct_copy(&ptr->struct_base, (gate_struct_t const*)src);
121 }
122 else
123 {
124 ✗ result = gate_struct_init(&ptr->struct_base, &config_descriptor);
125 ✗ ptr->services = gate_arraylist_create(sizeof(gate_servicehost_config_service_t), NULL, 0,
126 &gate_servicehost_config_service_copy_constructor, &gate_struct_destructor);
127 }
128 ✗ if (GATE_SUCCEEDED(result))
129 {
130 ✗ ret = dest;
131 }
132 ✗ return ret;
133 }
134
135 ✗ gate_result_t gate_servicehost_config_init(gate_struct_t* ptr)
136 {
137 ✗ if (NULL == gate_servicehost_config_copy_constructor(ptr, NULL))
138 {
139 ✗ return GATE_RESULT_FAILED;
140 }
141 else
142 {
143 ✗ return GATE_RESULT_OK;
144 }
145 }
146
147
148
149
150 typedef struct gate_essentials_impl_class
151 {
152 GATE_INTERFACE_VTBL(gate_microfactory) const* vtbl;
153
154 gate_atomic_int_t ref_counter;
155 } gate_essentials_impl_t;
156
157
158 1 static void essentials_destroy(gate_essentials_impl_t* impl)
159 {
160 (void)impl;
161 /* no deallocation, static object */
162 1 }
163
164 ✗ static char const* essentials_get_interface_name(void* thisptr)
165 {
166 ✗ gate_essentials_impl_t* self = (gate_essentials_impl_t*)thisptr;
167 (void)self;
168 ✗ return GATE_INTERFACE_NAME_MICROFACTORY;
169 }
170 2 static void essentials_release(void* thisptr)
171 {
172 2 gate_essentials_impl_t* self = (gate_essentials_impl_t*)thisptr;
173
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2 if (0 == gate_atomic_int_dec(&self->ref_counter))
174 {
175 1 essentials_destroy(self);
176 }
177 2 }
178 1 static int essentials_retain(void* thisptr)
179 {
180 1 gate_essentials_impl_t* self = (gate_essentials_impl_t*)thisptr;
181 1 return gate_atomic_int_inc(&self->ref_counter);
182 }
183
184 static gate_string_t name_webserver = GATE_STRING_INIT_STATIC(GATE_MICROSERVICE_NAME_WEBSERVER);
185 static gate_string_t name_timer = GATE_STRING_INIT_STATIC(GATE_MICROSERVICE_NAME_TIMER);
186 static gate_string_t name_procrunner = GATE_STRING_INIT_STATIC(GATE_MICROSERVICE_NAME_PROCRUNNER);
187
188 typedef struct factory_mapping_class
189 {
190 gate_string_t const* name;
191 gate_microservice_creator_t creator;
192 } factory_mapping_t;
193
194 static factory_mapping_t essential_mappings[] =
195 {
196 { &name_webserver, &gate_microservice_webserver_create },
197 { &name_timer, &gate_microservice_timer_create },
198 { &name_procrunner, &gate_microservice_procrunner_create }
199 };
200
201
202 ✗ static gate_result_t essentials_supported_service_names(void* thisptr, gate_array_t* ptr_output_names)
203 {
204 ✗ gate_result_t ret = GATE_RESULT_FAILED;
205 ✗ gate_essentials_impl_t* self = (gate_essentials_impl_t*)thisptr;
206 gate_size_t index;
207 gate_size_t count;
208 ✗ gate_arraylist_t names = GATE_INIT_EMPTY;
209
210 (void)self;
211 do
212 {
213 ✗ count = sizeof(essential_mappings) / sizeof(essential_mappings[0]);
214
215 ✗ names = gate_util_stringarray_create_duplicate(count);
216 ✗ if (gate_arraylist_is_null(names))
217 {
218 ✗ ret = GATE_RESULT_OUTOFMEMORY;
219 ✗ break;
220 }
221
222 ✗ for (index = 0; index != count; ++index)
223 {
224 ✗ gate_arraylist_add(names, essential_mappings[index].name);
225 }
226
227 ✗ if (NULL == gate_array_create(ptr_output_names, names))
228 {
229 ✗ ret = GATE_RESULT_OUTOFMEMORY;
230 }
231 else
232 {
233 ✗ ret = GATE_RESULT_OK;
234 }
235 } while (0);
236
237 ✗ gate_arraylist_release(&names);
238 ✗ return ret;
239 }
240 3 static gate_result_t essentials_create_service(void* thisptr, gate_string_t const* service_name, gate_microservice_t** ptr_service)
241 {
242 3 gate_result_t ret = GATE_RESULT_NOMATCH;
243 gate_size_t index, count;
244 3 gate_essentials_impl_t* self = (gate_essentials_impl_t*)thisptr;
245 (void)self;
246
247 do
248 {
249 3 count = sizeof(essential_mappings) / sizeof(essential_mappings[0]);
250
251
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 for (index = 0; index != count; ++index)
252 {
253
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if (gate_string_equals(service_name, essential_mappings[index].name))
254 {
255 3 ret = GATE_RESULT_OK;
256
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (ptr_service != NULL)
257 {
258 3 *ptr_service = essential_mappings[index].creator();
259
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (*ptr_service == NULL)
260 {
261 ✗ ret = GATE_RESULT_FAILED;
262 }
263 }
264 3 break;
265 }
266 }
267 } while (0);
268
269 3 return ret;
270 }
271
272
273 static GATE_INTERFACE_VTBL(gate_microfactory) gate_essentials_microfactory_vtbl;
274 1 static void gate_init_essentials_microfactory_vtbl()
275 {
276
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!gate_essentials_microfactory_vtbl.get_interface_name)
277 {
278 GATE_INTERFACE_VTBL(gate_microfactory) const local_vtbl =
279 {
280 &essentials_get_interface_name,
281 &essentials_release,
282 &essentials_retain,
283
284 &essentials_supported_service_names,
285 &essentials_create_service
286 };
287 1 gate_essentials_microfactory_vtbl = local_vtbl;
288 }
289 1 }
290
291 static gate_essentials_impl_t global_essentials_factory =
292 {
293 &gate_essentials_microfactory_vtbl,
294 0
295 };
296
297
298
299 1 GATE_TECH_API gate_microfactory_t* gate_servicehost_essentials_factory()
300 {
301 1 gate_microfactory_t* factory = (gate_microfactory_t*)&global_essentials_factory;
302
303 1 gate_init_essentials_microfactory_vtbl();
304
305 1 gate_atomic_int_inc(&global_essentials_factory.ref_counter);
306 1 return factory;
307 }
308
309
310
311
312
313
314
315
316 typedef struct subscription_class
317 {
318 gate_string_t source_address;
319 gate_string_t destination_address;
320 gate_string_t msg_id;
321 void* user_param;
322 gate_microservice_t* service;
323 } subscription_t;
324
325 3 static void subscription_destroy(subscription_t* subscr)
326 {
327 3 gate_string_release(&subscr->source_address);
328 3 gate_string_release(&subscr->destination_address);
329 3 gate_string_release(&subscr->msg_id);
330 3 subscr->user_param = NULL;
331
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (subscr->service != NULL)
332 {
333 3 gate_object_release(subscr->service);
334 }
335 3 }
336
337 3 static subscription_t* subscription_create(
338 subscription_t* subscr, gate_string_t const* source, gate_string_t const* dest, gate_string_t const* msg_id,
339 void* user_param, gate_microservice_t* service)
340 {
341 3 subscription_t* ret = NULL;
342
343 do
344 {
345 3 gate_mem_clear(subscr, sizeof(subscription_t));
346
347
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (NULL == gate_string_clone(&subscr->source_address, source))
348 {
349 ✗ break;
350 }
351
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (NULL == gate_string_clone(&subscr->destination_address, dest))
352 {
353 ✗ break;
354 }
355
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (NULL == gate_string_clone(&subscr->msg_id, msg_id))
356 {
357 ✗ break;
358 }
359 3 subscr->user_param = user_param;
360 3 subscr->service = service;
361
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (subscr->service != NULL)
362 {
363 3 gate_object_retain(subscr->service);
364 }
365
366 3 ret = subscr;
367 } while (0);
368
369
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!ret)
370 {
371 ✗ subscription_destroy(subscr);
372 }
373
374 3 return ret;
375 }
376
377 2 static gate_result_t GATE_CALL subscription_copy_ctor(void* dest, void const* source)
378 {
379 2 subscription_t const* src_ptr = (subscription_t const*)source;
380 2 subscription_t* dst_ptr = subscription_create((subscription_t*)dest,
381 &src_ptr->source_address, &src_ptr->destination_address,
382 &src_ptr->msg_id, src_ptr->user_param, src_ptr->service);
383
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (NULL == dst_ptr)
384 {
385 ✗ return GATE_RESULT_OUTOFMEMORY;
386 }
387 else
388 {
389 2 return GATE_RESULT_OK;
390 }
391 }
392
393 1 static void GATE_CALL subscription_dtor(void* dest)
394 {
395 1 subscription_destroy((subscription_t*)dest);
396 1 }
397
398
399 typedef struct gate_servicehost_impl_class
400 {
401 GATE_INTERFACE_VTBL(gate_servicehost) const* vtbl;
402
403 gate_atomic_int_t ref_counter;
404
405 gate_mutex_t lock;
406 gate_map_t factories; /* map: (string)name -> (object)gate_microfactory_t */
407 gate_map_t services; /* map: (string)name -> (object)gate_microservice_t */
408 gate_map_t services_configs; /* map: (string)name -> [map: (ui32)id -> (value)value] */
409 gate_arraylist_t msg_subscriptions; /* subscription_t[] */
410 gate_arraylist_t obj_subscriptions; /* subscription_t[] */
411 gate_logger_t const* logger;
412
413
414 } gate_servicehost_impl_t;
415
416 1 static gate_result_t gsvchost_init_members(gate_servicehost_impl_t* impl)
417 {
418 1 gate_result_t ret = GATE_RESULT_FAILED;
419
420 do
421 {
422 1 gate_atomic_int_init(&impl->ref_counter, 1);
423
424 1 ret = gate_mutex_create(&impl->lock);
425
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
426
427
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_map_create(&impl->factories, &gate_compare_string,
428 sizeof(gate_string_t), &gate_string_copy_constructor, &gate_string_destructor,
429 sizeof(gate_object_t*), &gate_object_ptr_copyctor, &gate_object_ptr_dtor))
430 {
431 ✗ ret = GATE_RESULT_OUTOFMEMORY;
432 ✗ break;
433 }
434
435
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_map_create(&impl->services, &gate_compare_string,
436 sizeof(gate_string_t), &gate_string_copy_constructor, &gate_string_destructor,
437 sizeof(gate_object_t*), &gate_object_ptr_copyctor, &gate_object_ptr_dtor))
438 {
439 ✗ ret = GATE_RESULT_OUTOFMEMORY;
440 ✗ break;
441 }
442
443
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_map_create(&impl->services_configs, &gate_compare_string,
444 sizeof(gate_string_t), &gate_string_copy_constructor, &gate_string_destructor,
445 sizeof(gate_map_t), &gate_map_copy_constructor, &gate_map_destructor))
446 {
447 ✗ ret = GATE_RESULT_OUTOFMEMORY;
448 ✗ break;
449 }
450
451 1 impl->msg_subscriptions = gate_arraylist_create(sizeof(subscription_t), NULL, 0, &subscription_copy_ctor, &subscription_dtor);
452
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (gate_arraylist_is_null(impl->msg_subscriptions))
453 {
454 ✗ ret = GATE_RESULT_OUTOFMEMORY;
455 ✗ break;
456 }
457
458 1 impl->obj_subscriptions = gate_arraylist_create(sizeof(subscription_t), NULL, 0, &subscription_copy_ctor, &subscription_dtor);
459
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (gate_arraylist_is_null(impl->obj_subscriptions))
460 {
461 ✗ ret = GATE_RESULT_OUTOFMEMORY;
462 ✗ break;
463 }
464
465 1 impl->logger = gate_logger_get();
466
467 } while (0);
468
469 1 return ret;
470 }
471
472
473 1 static void gsvchost_destroy(gate_servicehost_impl_t* impl)
474 {
475 1 gate_arraylist_release(&impl->obj_subscriptions);
476 1 gate_arraylist_release(&impl->msg_subscriptions);
477 1 gate_map_destroy(&impl->services_configs);
478 1 gate_map_destroy(&impl->services);
479 1 gate_map_destroy(&impl->factories);
480 1 gate_mutex_destroy(&impl->lock);
481
482 1 gate_mem_dealloc(impl);
483 1 }
484
485 ✗ static char const* gsvchost_get_interface_name(void* this_ptr)
486 {
487 (void)this_ptr;
488 ✗ return GATE_INTERFACE_NAME_GATESERVICEHOST;
489 }
490 4 static void gsvchost_release(void* this_ptr)
491 {
492 4 gate_servicehost_impl_t* impl = (gate_servicehost_impl_t*)this_ptr;
493
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
4 if (0 == gate_atomic_int_dec(&impl->ref_counter))
494 {
495 1 gsvchost_destroy(impl);
496 }
497 4 }
498 3 static int gsvchost_retain(void* this_ptr)
499 {
500 3 gate_servicehost_impl_t* impl = (gate_servicehost_impl_t*)this_ptr;
501 3 return gate_atomic_int_inc(&impl->ref_counter);
502 }
503
504 1 static gate_size_t extract_subscriptions(gate_arraylist_t source, subscription_t* subscrs, gate_size_t max_subscrs,
505 gate_string_t const* source_address, gate_string_t const* destination_address,
506 gate_string_t const* msg_id)
507 {
508 1 gate_size_t ret = 0;
509 gate_size_t index;
510 1 gate_size_t count = gate_arraylist_length(source);
511 subscription_t const* ptr;
512 gate_result_t result;
513
514
3/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2 for (index = 0; (max_subscrs != 0) && (index != count); ++index)
515 {
516 1 ptr = (subscription_t const*)gate_arraylist_get(source, index);
517
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ptr != NULL)
518 {
519
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1 if (!gate_string_is_empty(source_address) && !gate_string_is_empty(&ptr->source_address))
520 {
521 ✗ if (!gate_string_like(source_address, &ptr->source_address))
522 {
523 ✗ continue;
524 }
525 }
526
527
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 if (!gate_string_is_empty(destination_address) && !gate_string_is_empty(&ptr->destination_address))
528 {
529
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (!gate_string_like(destination_address, &ptr->destination_address))
530 {
531 ✗ continue;
532 }
533 }
534
535
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 if (!gate_string_is_empty(msg_id) && !gate_string_is_empty(&ptr->msg_id))
536 {
537
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (!gate_string_equals(msg_id, &ptr->msg_id))
538 {
539 ✗ continue;
540 }
541 }
542
543 /* copy this subscription */
544 1 result = subscription_copy_ctor(subscrs, ptr);
545
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (GATE_SUCCEEDED(result))
546 {
547 1 ++ret;
548 1 ++subscrs;
549 1 --max_subscrs;
550 }
551 }
552 }
553 1 return ret;
554 }
555 1 static void release_subscriptions(subscription_t* subscrs, gate_size_t count)
556 {
557
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 while (count-- != 0)
558 {
559 1 subscription_destroy(subscrs);
560 1 ++subscrs;
561 }
562 1 }
563
564 1 static gate_result_t gsvchost_publish_message(void* this_ptr,
565 gate_string_t const* source_address, gate_string_t const* destination_address,
566 gate_string_t const* msg_id, gate_string_t const* ptr_message)
567 {
568 1 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
569 1 gate_servicehost_impl_t* impl = (gate_servicehost_impl_t*)this_ptr;
570 subscription_t subscriptions[128];
571 1 gate_size_t subscriptions_extracted = 0;
572 1 gate_size_t index = 0;
573 gate_result_t msg_result;
574 static gate_string_t log_msg_origin = GATE_STRING_INIT_STATIC("microservice::publish_message");
575 1 gate_strbuilder_t log_builder = GATE_INIT_EMPTY;
576 char log_buffer[4096];
577 1 gate_string_t log_text = GATE_STRING_INIT_EMPTY;
578 1 gate_uint32_t svc_status = 0;
579
580 do
581 {
582 {
583 1 gate_strbuilder_create_static(&log_builder, log_buffer, sizeof(log_buffer), 0);
584 1 gate_strbuilder_append(&log_builder,
585 GATE_PRINT_CSTR, "Publish message ID '",
586 GATE_PRINT_STRING, msg_id,
587 GATE_PRINT_CSTR, "' from '",
588 GATE_PRINT_STRING, source_address,
589 GATE_PRINT_CSTR, "' to '",
590 GATE_PRINT_STRING, destination_address,
591 GATE_PRINT_CSTR, "'",
592 GATE_PRINT_END);
593 1 gate_strbuilder_to_string(&log_builder, &log_text);
594 1 gate_microhost_log(impl, GATE_LOG_TYPE_INFO, 0, 0, &log_msg_origin, &log_text);
595 1 gate_string_release(&log_text);
596 1 gate_strbuilder_release(&log_builder);
597 }
598
599 1 gate_mem_clear(subscriptions, sizeof(subscriptions));
600
601 1 ret = gate_mutex_acquire(&impl->lock);
602
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
603 do
604 {
605 1 subscriptions_extracted = extract_subscriptions(impl->msg_subscriptions,
606 subscriptions, sizeof(subscriptions) / sizeof(subscriptions[0]),
607 source_address, destination_address, msg_id);
608 } while (0);
609 1 gate_mutex_release(&impl->lock);
610
611 1 ret = GATE_RESULT_OK;
612
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (index = 0; index != subscriptions_extracted; ++index)
613 {
614
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (subscriptions[index].service)
615 {
616 1 svc_status = gate_microservice_get_status(subscriptions[index].service);
617
618
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (svc_status == GATE_MICROSERVICE_STATUS_ONLINE)
619 {
620 {
621 1 gate_strbuilder_create_static(&log_builder, log_buffer, sizeof(log_buffer), 0);
622 1 gate_strbuilder_append(&log_builder,
623 GATE_PRINT_CSTR, "Delivering published message ID '",
624 GATE_PRINT_STRING, msg_id,
625 GATE_PRINT_CSTR, "' from '",
626 GATE_PRINT_STRING, source_address,
627 GATE_PRINT_CSTR, "' to '",
628 GATE_PRINT_STRING, &subscriptions[index].destination_address,
629 GATE_PRINT_CSTR, "'",
630 GATE_PRINT_END);
631 1 gate_strbuilder_to_string(&log_builder, &log_text);
632 1 gate_microhost_log(impl, GATE_LOG_TYPE_INFO, 0, 0, &log_msg_origin, &log_text);
633 1 gate_string_release(&log_text);
634 1 gate_strbuilder_release(&log_builder);
635 }
636
637 1 msg_result = gate_microservice_process_message(subscriptions[index].service, source_address, destination_address,
638 msg_id, ptr_message, subscriptions[index].user_param);
639
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_FAILED(msg_result))
640 {
641 ✗ gate_strbuilder_create_static(&log_builder, log_buffer, sizeof(log_buffer), 0);
642 ✗ gate_strbuilder_append(&log_builder,
643 GATE_PRINT_CSTR, "Delivery of published message ID '",
644 GATE_PRINT_STRING, msg_id,
645 GATE_PRINT_CSTR, "' from '",
646 GATE_PRINT_STRING, source_address,
647 GATE_PRINT_CSTR, "' to '",
648 GATE_PRINT_STRING, &subscriptions[index].destination_address,
649 GATE_PRINT_CSTR, "' has failed",
650 GATE_PRINT_END);
651 ✗ gate_strbuilder_to_string(&log_builder, &log_text);
652 ✗ gate_microhost_log(impl, GATE_LOG_TYPE_WARN, msg_result, 0, &log_msg_origin, &log_text);
653 ✗ gate_string_release(&log_text);
654 ✗ gate_strbuilder_release(&log_builder);
655 }
656 else
657 {
658 1 gate_strbuilder_create_static(&log_builder, log_buffer, sizeof(log_buffer), 0);
659 1 gate_strbuilder_append(&log_builder,
660 GATE_PRINT_CSTR, "Delivery of published message ID '",
661 GATE_PRINT_STRING, msg_id,
662 GATE_PRINT_CSTR, "' from '",
663 GATE_PRINT_STRING, source_address,
664 GATE_PRINT_CSTR, "' to '",
665 GATE_PRINT_STRING, &subscriptions[index].destination_address,
666 GATE_PRINT_CSTR, "' succeeded",
667 GATE_PRINT_END);
668 1 gate_strbuilder_to_string(&log_builder, &log_text);
669 1 gate_microhost_log(impl, GATE_LOG_TYPE_INFO, 0, 0, &log_msg_origin, &log_text);
670 1 gate_string_release(&log_text);
671 1 gate_strbuilder_release(&log_builder);
672 }
673 }
674 else
675 {
676 {
677 ✗ gate_strbuilder_create_static(&log_builder, log_buffer, sizeof(log_buffer), 0);
678 ✗ gate_strbuilder_append(&log_builder,
679 GATE_PRINT_CSTR, "Subscription target service '",
680 GATE_PRINT_STRING, &subscriptions[index].destination_address,
681 GATE_PRINT_CSTR, "' has invalid state #",
682 GATE_PRINT_UI32, svc_status,
683 GATE_PRINT_END);
684 ✗ gate_strbuilder_to_string(&log_builder, &log_text);
685 ✗ gate_microhost_log(impl, GATE_LOG_TYPE_WARN, 0, 0, &log_msg_origin, &log_text);
686 ✗ gate_string_release(&log_text);
687 ✗ gate_strbuilder_release(&log_builder);
688 }
689
690 }
691
692
693 }
694 }
695 } while (0);
696
697 1 release_subscriptions(subscriptions, subscriptions_extracted);
698
699 1 return ret;
700 }
701
702 ✗ static gate_result_t gsvchost_publish_object(void* this_ptr,
703 gate_string_t const* source_address, gate_string_t const* destination_address,
704 gate_string_t const* obj_id, gate_object_t* ptr_object)
705 {
706 ✗ gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
707 ✗ gate_servicehost_impl_t* impl = (gate_servicehost_impl_t*)this_ptr;
708 subscription_t subscriptions[128];
709 ✗ gate_size_t subscriptions_extracted = 0;
710 ✗ gate_size_t index = 0;
711 gate_result_t msg_result;
712
713 do
714 {
715 ✗ gate_mem_clear(subscriptions, sizeof(subscriptions));
716
717 ✗ ret = gate_mutex_acquire(&impl->lock);
718 ✗ GATE_BREAK_IF_FAILED(ret);
719 do
720 {
721 ✗ subscriptions_extracted = extract_subscriptions(impl->obj_subscriptions,
722 subscriptions, sizeof(subscriptions) / sizeof(subscriptions[0]),
723 source_address, destination_address, NULL);
724 } while (0);
725 ✗ gate_mutex_release(&impl->lock);
726
727 ✗ ret = GATE_RESULT_OK;
728 ✗ for (index = 0; index != subscriptions_extracted; ++index)
729 {
730 ✗ if (subscriptions[index].service)
731 {
732 ✗ msg_result = gate_microservice_process_object(subscriptions[index].service, source_address, destination_address,
733 obj_id, ptr_object, subscriptions[index].user_param);
734 if (GATE_FAILED(msg_result))
735 {
736 /* TODO error logging */
737 }
738 }
739 }
740 } while (0);
741
742 ✗ release_subscriptions(subscriptions, subscriptions_extracted);
743
744 ✗ return ret;
745 }
746
747 1 static gate_result_t gsvchost_add_subscription(gate_servicehost_impl_t* impl, gate_arraylist_t subscription_list,
748 gate_string_t const* source_address, gate_string_t const* destination_address,
749 gate_string_t const* msg_id, gate_object_t* subscriber, void* user_data)
750 {
751 1 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
752 subscription_t subscr;
753 1 gate_microservice_t* microservice = NULL;
754
755 do
756 {
757 1 gate_mem_clear(&subscr, sizeof(subscr));
758
759
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (subscriber != NULL)
760 {
761
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (!gate_object_implements_interface(subscriber, GATE_INTERFACE_NAME_MICROSERVICE))
762 {
763 ✗ ret = GATE_RESULT_INVALIDARG;
764 ✗ break;
765 }
766 1 microservice = (gate_microservice_t*)subscriber;
767 }
768
769
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == subscription_create(&subscr, source_address, destination_address, msg_id, user_data, microservice))
770 {
771 ✗ ret = GATE_RESULT_OUTOFMEMORY;
772 ✗ break;
773 }
774
775 1 ret = gate_mutex_acquire(&impl->lock);
776
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
777 do
778 {
779
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_arraylist_add(subscription_list, &subscr))
780 {
781 ✗ ret = GATE_RESULT_OUTOFMEMORY;
782 }
783 else
784 {
785 1 ret = GATE_RESULT_OK;
786 }
787 } while (0);
788 1 gate_mutex_release(&impl->lock);
789
790 } while (0);
791
792 1 subscription_destroy(&subscr);
793 1 return ret;
794 }
795
796 ✗ static gate_bool_t gsvchost_remove_subscription_filter(void const* item, void* param)
797 {
798 ✗ subscription_t const* ptr = (subscription_t const*)item;
799 ✗ subscription_t const* pattern = (subscription_t const*)param;
800 ✗ return (ptr->service == pattern->service)
801 ✗ || (((pattern->service == NULL) || (ptr->service == NULL))
802 ✗ && gate_string_equals(&ptr->source_address, &pattern->source_address)
803 ✗ && gate_string_equals(&ptr->destination_address, &pattern->destination_address)
804 ✗ && gate_string_equals(&ptr->msg_id, &pattern->msg_id)
805 );
806 }
807
808 ✗ static gate_result_t gsvchost_remove_subscription(gate_servicehost_impl_t* impl, gate_arraylist_t subscription_list,
809 gate_string_t const* source_address, gate_string_t const* destination_address,
810 gate_string_t const* msg_id, gate_object_t* subscriber, void* user_data)
811 {
812 ✗ gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
813 subscription_t subscr;
814 ✗ gate_microservice_t* microservice = NULL;
815
816 do
817 {
818 ✗ gate_mem_clear(&subscr, sizeof(subscr));
819
820 ✗ if (subscriber != NULL)
821 {
822 ✗ if (!gate_object_implements_interface(subscriber, GATE_INTERFACE_NAME_MICROSERVICE))
823 {
824 ✗ ret = GATE_RESULT_INVALIDARG;
825 ✗ break;
826 }
827 ✗ microservice = (gate_microservice_t*)subscriber;
828 }
829
830 ✗ if (NULL == subscription_create(&subscr, source_address, destination_address, msg_id, user_data, microservice))
831 {
832 ✗ ret = GATE_RESULT_OUTOFMEMORY;
833 ✗ break;
834 }
835
836 ✗ ret = gate_mutex_acquire(&impl->lock);
837 ✗ GATE_BREAK_IF_FAILED(ret);
838 do
839 {
840 ✗ ret = gate_arraylist_remove_if(subscription_list, &gsvchost_remove_subscription_filter, &subscr);
841 } while (0);
842 ✗ gate_mutex_release(&impl->lock);
843
844 } while (0);
845
846 ✗ subscription_destroy(&subscr);
847 ✗ return ret;
848 }
849
850
851 1 static gate_result_t gsvchost_subscribe_messages(
852 void* this_ptr, gate_string_t const* source_address, gate_string_t const* destination_address,
853 gate_string_t const* msg_id, gate_object_t* subscriber, void* user_data)
854 {
855 1 gate_servicehost_impl_t* impl = (gate_servicehost_impl_t*)this_ptr;
856 1 return gsvchost_add_subscription(impl, impl->msg_subscriptions, source_address, destination_address, msg_id, subscriber, user_data);
857 }
858 ✗ static gate_result_t gsvchost_unsubscribe_messages(
859 void* this_ptr, gate_string_t const* source_address, gate_string_t const* destination_address,
860 gate_string_t const* msg_id, gate_object_t* subscriber, void* user_data)
861 {
862 ✗ gate_servicehost_impl_t* impl = (gate_servicehost_impl_t*)this_ptr;
863 ✗ return gsvchost_remove_subscription(impl, impl->msg_subscriptions, source_address, destination_address, msg_id, subscriber, user_data);
864 }
865
866 ✗ static gate_result_t gsvchost_subscribe_objects(
867 void* this_ptr, gate_string_t const* source_address, gate_string_t const* destination_address,
868 gate_string_t const* obj_id, gate_object_t* subscriber, void* user_data)
869 {
870 ✗ gate_servicehost_impl_t* impl = (gate_servicehost_impl_t*)this_ptr;
871 ✗ return gsvchost_add_subscription(impl, impl->obj_subscriptions, source_address, destination_address, obj_id, subscriber, user_data);
872 }
873 ✗ static gate_result_t gsvchost_unsubscribe_objects(
874 void* this_ptr, gate_string_t const* source_address, gate_string_t const* destination_address,
875 gate_string_t const* obj_id, gate_object_t* subscriber, void* user_data)
876 {
877 ✗ gate_servicehost_impl_t* impl = (gate_servicehost_impl_t*)this_ptr;
878 ✗ return gsvchost_remove_subscription(impl, impl->obj_subscriptions, source_address, destination_address, obj_id, subscriber, user_data);
879 }
880
881 ✗ static gate_result_t gsvchost_remote_invoke(void* this_ptr, gate_string_t const* destination_address, gate_string_t const* method,
882 gate_struct_t const* input_data, gate_struct_t* output_data)
883 {
884 ✗ gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
885 ✗ gate_servicehost_impl_t* impl = (gate_servicehost_impl_t*)this_ptr;
886 ✗ gate_microservice_t* service = NULL;
887
888 do
889 {
890 ✗ ret = gate_servicehost_get_service(impl, destination_address, &service);
891 ✗ GATE_BREAK_IF_FAILED(ret);
892
893 ✗ ret = gate_microservice_invoke(service, method, input_data, output_data);
894 } while (0);
895
896 ✗ if (service != NULL)
897 {
898 ✗ gate_object_release(service);
899 }
900 ✗ return ret;
901 }
902
903 7 static gate_result_t gsvchost_log(void* this_ptr, gate_uint32_t svc_log_type, gate_result_t result_code, gate_int32_t native_code,
904 gate_string_t const* origin, gate_string_t const* message)
905 {
906 7 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
907 7 gate_servicehost_impl_t* impl = (gate_servicehost_impl_t*)this_ptr;
908 7 gate_uint32_t logger_log_type = GATE_LOG_TYPE_INFO;
909 do
910 {
911
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (impl->logger != NULL)
912 {
913
5/7
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
7 switch (svc_log_type)
914 {
915
916 1 case GATE_MICROSERVICE_LOGTYPE_DEBUG: logger_log_type = GATE_LOG_TYPE_DEBUG; break;
917 1 case GATE_MICROSERVICE_LOGTYPE_INFO: logger_log_type = GATE_LOG_TYPE_INFO; break;
918 ✗ case GATE_MICROSERVICE_LOGTYPE_STATUS: logger_log_type = GATE_LOG_TYPE_STATUS; break;
919 1 case GATE_MICROSERVICE_LOGTYPE_WARNING: logger_log_type = GATE_LOG_TYPE_WARN; break;
920 1 case GATE_MICROSERVICE_LOGTYPE_ERROR: logger_log_type = GATE_LOG_TYPE_ERROR; break;
921 ✗ case GATE_MICROSERVICE_LOGTYPE_ALERT: logger_log_type = GATE_LOG_TYPE_FATAL; break;
922 }
923
924 7 ret = gate_log(impl->logger, logger_log_type, result_code, native_code, origin, message);
925 }
926 else
927 {
928 ✗ ret = GATE_RESULT_NOTREADY;
929 }
930
931 } while (0);
932
933 7 return ret;
934 }
935
936 2 static gate_result_t gsvchost_add_factory(void* this_ptr, gate_microfactory_t* factory, gate_string_t const* factory_name)
937 {
938 2 gate_result_t ret = GATE_RESULT_FAILED;
939 2 gate_servicehost_impl_t* impl = (gate_servicehost_impl_t*)this_ptr;
940 do
941 {
942 2 ret = gate_mutex_acquire(&impl->lock);
943
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret);
944
945
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (NULL == gate_map_add(&impl->factories, factory_name, &factory))
946 {
947 ✗ ret = GATE_RESULT_OUTOFMEMORY;
948 }
949 2 gate_mutex_release(&impl->lock);
950 } while (0);
951
952 2 return ret;
953 }
954 ✗ static gate_result_t gsvchost_remove_factory(void* this_ptr, gate_string_t const* factory_name)
955 {
956 ✗ gate_result_t ret = GATE_RESULT_FAILED;
957 ✗ gate_servicehost_impl_t* impl = (gate_servicehost_impl_t*)this_ptr;
958 do
959 {
960 ✗ ret = gate_mutex_acquire(&impl->lock);
961 ✗ GATE_BREAK_IF_FAILED(ret);
962 ✗ gate_map_remove(&impl->factories, factory_name);
963 ✗ gate_mutex_release(&impl->lock);
964 } while (0);
965
966 ✗ return ret;
967 }
968
969 ✗ static gate_result_t gsvchost_get_factory_service_names(void* this_ptr, gate_array_t* names)
970 {
971 ✗ gate_result_t ret = GATE_RESULT_FAILED;
972 ✗ gate_servicehost_impl_t* impl = (gate_servicehost_impl_t*)this_ptr;
973 ✗ gate_arraylist_t arr = GATE_INIT_EMPTY;
974
975 do
976 {
977 ✗ arr = gate_util_map_export_keys(&impl->factories);
978 ✗ if (gate_arraylist_is_null(arr))
979 {
980 ✗ ret = GATE_RESULT_OUTOFMEMORY;
981 ✗ break;
982 }
983 ✗ if (names != NULL)
984 {
985 ✗ if (NULL == gate_array_create(names, arr))
986 {
987 ✗ ret = GATE_RESULT_OUTOFMEMORY;
988 ✗ break;
989 }
990 }
991 ✗ ret = GATE_RESULT_OK;
992 } while (0);
993
994 ✗ gate_arraylist_release(&arr);
995 ✗ return ret;
996 }
997
998 3 static gate_result_t gsvchost_create_service(void* this_ptr,
999 gate_string_t const* service_name, gate_string_t const* service_instance, gate_string_t* service_address)
1000 {
1001 3 gate_result_t ret = GATE_RESULT_NOMATCH;
1002 3 gate_servicehost_impl_t* impl = (gate_servicehost_impl_t*)this_ptr;
1003 3 gate_microfactory_t* const* ptr_factory = NULL;
1004 3 gate_microfactory_t* factory = NULL;
1005 3 gate_microservice_t* service = NULL;
1006 3 gate_string_t address = GATE_STRING_INIT_EMPTY;
1007 gate_map_iterator_t iter;
1008
1009 do
1010 {
1011 3 ret = gate_microservice_encode_address(service_name, service_instance, &address);
1012
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_BREAK_IF_FAILED(ret);
1013
1014
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (NULL != gate_map_get(&impl->services, &address))
1015 {
1016 ✗ ret = GATE_RESULT_ALREADYEXISTS;
1017 ✗ break;
1018 }
1019
1020 3 ret = GATE_RESULT_NOMATCH;
1021 3 iter = gate_map_first(&impl->factories);
1022
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 while (gate_map_iterator_valid(iter))
1023 {
1024 3 ptr_factory = (gate_microfactory_t* const*)gate_map_iterator_value(iter);
1025
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (ptr_factory)
1026 {
1027 3 factory = *ptr_factory;
1028
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (factory)
1029 {
1030 3 ret = gate_microfactory_create_service(factory, service_name, &service);
1031
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (GATE_SUCCEEDED(ret))
1032 {
1033 3 break;
1034 }
1035 }
1036 }
1037 ✗ iter = gate_map_iterator_next(iter);
1038 }
1039
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_BREAK_IF_FAILED(ret);
1040
1041
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (!gate_map_add(&impl->services, &address, &service))
1042 {
1043 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1044 ✗ break;
1045 }
1046
1047 3 ret = GATE_RESULT_OK;
1048
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (service_address)
1049 {
1050 3 gate_string_clone(service_address, &address);
1051 }
1052 } while (0);
1053
1054 3 gate_string_release(&address);
1055
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (service)
1056 {
1057 3 gate_object_release(service);
1058 }
1059 3 return ret;
1060 }
1061
1062 2 static gate_result_t gsvchost_get_service_addresses(void* this_ptr, gate_array_t* addresses)
1063 {
1064 2 gate_result_t ret = GATE_RESULT_FAILED;
1065 2 gate_servicehost_impl_t* impl = (gate_servicehost_impl_t*)this_ptr;
1066 2 gate_arraylist_t arr = GATE_INIT_EMPTY;
1067
1068 do
1069 {
1070 2 arr = gate_util_map_export_keys(&impl->services);
1071
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (gate_arraylist_is_null(arr))
1072 {
1073 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1074 ✗ break;
1075 }
1076
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (addresses)
1077 {
1078
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (NULL == gate_array_create(addresses, arr))
1079 {
1080 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1081 ✗ break;
1082 }
1083 }
1084 2 ret = GATE_RESULT_OK;
1085 } while (0);
1086
1087 2 gate_arraylist_release(&arr);
1088 2 return ret;
1089
1090 }
1091
1092 10 static gate_result_t gsvchost_get_service(void* this_ptr, gate_string_t const* service_address, gate_microservice_t** ptr_service)
1093 {
1094 10 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
1095 10 gate_servicehost_impl_t* impl = (gate_servicehost_impl_t*)this_ptr;
1096 10 gate_microservice_t* microsvc = NULL;
1097 10 gate_microservice_t** ptr_microsvc = NULL;
1098 do
1099 {
1100
1101 10 ret = gate_mutex_acquire(&impl->lock);
1102
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 GATE_BREAK_IF_FAILED(ret);
1103 do
1104 {
1105 10 ptr_microsvc = gate_map_get_value(&impl->services, service_address);
1106
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (NULL == ptr_microsvc)
1107 {
1108 ✗ ret = GATE_RESULT_NOMATCH;
1109 }
1110 else
1111 {
1112 10 microsvc = *ptr_microsvc;
1113
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (microsvc != NULL)
1114 {
1115 10 gate_object_retain(microsvc);
1116 10 ret = GATE_RESULT_OK;
1117 }
1118 else
1119 {
1120 ✗ ret = GATE_RESULT_NULLPOINTER;
1121 }
1122 }
1123 } while (0);
1124 10 gate_mutex_release(&impl->lock);
1125
1126
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 GATE_BREAK_IF_FAILED(ret);
1127
1128
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (ptr_service != NULL)
1129 {
1130 10 *ptr_service = microsvc;
1131 10 microsvc = NULL;
1132 }
1133 } while (0);
1134
1135
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (microsvc != NULL)
1136 {
1137 ✗ gate_object_release(microsvc);
1138 }
1139
1140 10 return ret;
1141 }
1142
1143 3 static gate_result_t gsvchost_get_service_config(void* this_ptr, gate_string_t const* service_address, gate_uint32_t config_type, gate_value_t* value)
1144 {
1145 3 gate_result_t ret = GATE_RESULT_FAILED;
1146 3 gate_servicehost_impl_t* impl = (gate_servicehost_impl_t*)this_ptr;
1147
1148 do
1149 {
1150 gate_map_t const* ptr_map;
1151 gate_value_t const* ptr_value;
1152 3 gate_map_iterator_t iter = gate_map_get(&impl->services_configs, service_address);
1153
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 if (!gate_map_iterator_valid(iter))
1154 {
1155 3 break;
1156 }
1157 ✗ ptr_map = (gate_map_t const*)gate_map_iterator_value(iter);
1158 ✗ if (!ptr_map)
1159 {
1160 ✗ break;
1161 }
1162 ✗ iter = gate_map_get(ptr_map, &config_type);
1163 ✗ if (!gate_map_iterator_valid(iter))
1164 {
1165 ✗ break;
1166 }
1167 ✗ ptr_value = (gate_value_t const*)gate_map_iterator_value(iter);
1168 ✗ if (!ptr_value)
1169 {
1170 ✗ break;
1171 }
1172 ✗ if (NULL == gate_value_clone(ptr_value, value))
1173 {
1174 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1175 ✗ break;
1176 }
1177 ✗ ret = GATE_RESULT_OK;
1178 } while (0);
1179
1180 3 return ret;
1181 }
1182
1183 ✗ static gate_result_t gsvchost_set_service_config(void* this_ptr, gate_string_t const* service_address, gate_uint32_t config_type, gate_value_t const* value)
1184 {
1185 ✗ gate_result_t ret = GATE_RESULT_FAILED;
1186 ✗ gate_servicehost_impl_t* impl = (gate_servicehost_impl_t*)this_ptr;
1187
1188
1189
1190 do
1191 {
1192 ✗ gate_map_t tmp = GATE_INIT_EMPTY;
1193 ✗ gate_map_t* ptr_map = NULL;
1194 ✗ gate_map_iterator_t iter = gate_map_get(&impl->services_configs, service_address);
1195 ✗ if (!gate_map_iterator_valid(iter))
1196 {
1197 ✗ gate_map_create(&tmp, gate_compare_uint32, sizeof(gate_uint32_t), NULL, NULL,
1198 sizeof(gate_value_t), &gate_value_copy_constructor, &gate_value_destructor);
1199 ✗ iter = gate_map_add(&tmp, &config_type, value);
1200 ✗ if (!gate_map_iterator_valid(iter))
1201 {
1202 ✗ gate_map_destroy(&tmp);
1203 ✗ break;
1204 }
1205 ✗ iter = gate_map_add(&impl->services_configs, service_address, &tmp);
1206 ✗ gate_map_destroy(&tmp);
1207 ✗ if (gate_map_iterator_valid(iter))
1208 {
1209 ✗ ret = GATE_RESULT_OK;
1210 }
1211 }
1212 else
1213 {
1214 ✗ ptr_map = (gate_map_t*)gate_map_iterator_value(iter);
1215 ✗ if (!ptr_map)
1216 {
1217 ✗ break;
1218 }
1219 ✗ iter = gate_map_add(ptr_map, &config_type, value);
1220 ✗ if (gate_map_iterator_valid(iter))
1221 {
1222 ✗ ret = GATE_RESULT_OK;
1223 }
1224 }
1225
1226 } while (0);
1227
1228 ✗ return ret;
1229 }
1230
1231
1232 3 static gate_result_t gsvchost_start_service(void* this_ptr, gate_string_t const* service_address)
1233 {
1234 3 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
1235 3 gate_servicehost_impl_t* const impl = (gate_servicehost_impl_t*)this_ptr;
1236 3 gate_microservice_t* service = NULL;
1237
1238 do
1239 {
1240
1241 3 ret = gsvchost_get_service(this_ptr, service_address, &service);
1242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_BREAK_IF_FAILED(ret);
1243 3 ret = gate_microservice_setup(service, service_address, ((gate_microhost_t*)impl));
1244
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_BREAK_IF_FAILED(ret);
1245 3 ret = gate_microservice_start(service);
1246 } while (0);
1247
1248
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (service != NULL)
1249 {
1250 3 gate_object_release(service);
1251 }
1252
1253 3 return ret;
1254 }
1255 3 static gate_result_t gsvchost_stop_service(void* this_ptr, gate_string_t const* service_address)
1256 {
1257 3 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
1258 3 gate_microservice_t* service = NULL;
1259
1260 do
1261 {
1262 3 ret = gsvchost_get_service(this_ptr, service_address, &service);
1263
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_BREAK_IF_FAILED(ret);
1264 3 ret = gate_microservice_stop(service);
1265 } while (0);
1266
1267
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (service != NULL)
1268 {
1269 3 gate_object_release(service);
1270 }
1271
1272 3 return ret;
1273 }
1274
1275
1276 1 static gate_bool_t gsvchost_remove_subscription_by_pointer(void const* item, void* param)
1277 {
1278 1 subscription_t const* subscr = (subscription_t const*)item;
1279 1 gate_microservice_t* service = (gate_microservice_t*)param;
1280
1281 1 return subscr->service == service;
1282 }
1283
1284 ✗ static gate_bool_t gsvchost_remove_subscription_by_name(void const* item, void* param)
1285 {
1286 ✗ subscription_t const* subscr = (subscription_t const*)item;
1287 ✗ gate_string_t const* name = (gate_string_t const*)param;
1288
1289 ✗ return gate_string_equals(&subscr->destination_address, name);
1290 }
1291
1292
1293 3 static gate_result_t gsvchost_remove_service(void* this_ptr, gate_string_t const* service_address)
1294 {
1295 3 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
1296 3 gate_servicehost_impl_t* const impl = (gate_servicehost_impl_t*)this_ptr;
1297 3 gate_microservice_t* microsvc = NULL;
1298 do
1299 {
1300
1301 3 ret = gate_mutex_acquire(&impl->lock);
1302
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_BREAK_IF_FAILED(ret);
1303 do
1304 {
1305 3 gate_microservice_t** ptr_microsvc = (gate_microservice_t**)gate_map_get_value(&impl->services, service_address);
1306
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (NULL == ptr_microsvc)
1307 {
1308 ✗ ret = GATE_RESULT_NOMATCH;
1309 }
1310 else
1311 {
1312 3 microsvc = *ptr_microsvc;
1313
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (microsvc != NULL)
1314 {
1315 3 gate_object_retain(microsvc);
1316 3 ret = GATE_RESULT_OK;
1317
1318 3 gate_arraylist_remove_if(impl->msg_subscriptions, &gsvchost_remove_subscription_by_pointer, microsvc);
1319 3 gate_arraylist_remove_if(impl->msg_subscriptions, &gsvchost_remove_subscription_by_name, (void*)service_address);
1320 3 gate_arraylist_remove_if(impl->obj_subscriptions, &gsvchost_remove_subscription_by_pointer, microsvc);
1321 3 gate_arraylist_remove_if(impl->obj_subscriptions, &gsvchost_remove_subscription_by_name, (void*)service_address);
1322 }
1323 else
1324 {
1325 ✗ ret = GATE_RESULT_NULLPOINTER;
1326 }
1327 3 gate_map_remove(&impl->services, service_address);
1328 }
1329 } while (0);
1330 3 gate_mutex_release(&impl->lock);
1331
1332
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_BREAK_IF_FAILED(ret);
1333
1334 } while (0);
1335
1336
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (microsvc != NULL)
1337 {
1338 3 gate_microservice_stop(microsvc);
1339 3 gate_object_release(microsvc);
1340 }
1341
1342 3 return ret;
1343 }
1344
1345 1 static gate_size_t gsvchost_start_services(gate_servicehost_impl_t* host,
1346 gate_string_t const* const* addresses, gate_size_t addresses_count)
1347 {
1348 1 gate_size_t started_counter = 0;
1349
1350
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 while (addresses_count-- != 0)
1351 {
1352 gate_microservice_t* ptr_service;
1353 ✗ gate_result_t result = gate_servicehost_get_service(host, *addresses, &ptr_service);
1354 ✗ if (GATE_SUCCEEDED(result))
1355 {
1356 ✗ result = gate_microservice_setup(ptr_service, *addresses, (gate_microhost_t*)host);
1357 ✗ if (GATE_SUCCEEDED(result))
1358 {
1359 ✗ result = gate_microservice_start(ptr_service);
1360 ✗ if (GATE_SUCCEEDED(result))
1361 {
1362 ✗ ++started_counter;
1363 }
1364 }
1365 ✗ gate_object_release(ptr_service);
1366 }
1367 ✗ ++addresses;
1368 }
1369 1 return started_counter;
1370 }
1371
1372 1 static gate_size_t gsvchost_stop_services(gate_servicehost_impl_t* host,
1373 gate_string_t const* const* addresses, gate_size_t addresses_count)
1374 {
1375 1 gate_size_t started_counter = 0;
1376
1377
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 while (addresses_count-- != 0)
1378 {
1379 gate_microservice_t* ptr_service;
1380 3 gate_result_t result = gate_servicehost_get_service(host, *addresses, &ptr_service);
1381
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (GATE_SUCCEEDED(result))
1382 {
1383 3 result = gate_microservice_stop(ptr_service);
1384
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (GATE_SUCCEEDED(result))
1385 {
1386 ✗ ++started_counter;
1387 }
1388 3 gate_object_release(ptr_service);
1389 }
1390 3 ++addresses;
1391 }
1392 1 return started_counter;
1393 }
1394
1395 1 static void gsvchost_release_services(gate_servicehost_impl_t* host,
1396 gate_string_t const* const* addresses, gate_size_t addresses_count)
1397 {
1398
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 while (addresses_count-- != 0)
1399 {
1400 3 gate_servicehost_release_service(host, *addresses);
1401 3 ++addresses;
1402 }
1403 1 }
1404
1405
1406 1 static gate_result_t gsvchost_start_up(void* this_ptr)
1407 {
1408 1 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
1409 1 gate_servicehost_impl_t* const impl = (gate_servicehost_impl_t*)this_ptr;
1410 1 gate_array_t addresses = GATE_INIT_EMPTY;
1411
1412 do
1413 {
1414 gate_size_t index;
1415 gate_size_t length;
1416 gate_string_t const* addresses_to_start[1024];
1417 1 gate_size_t const addresses_max = sizeof(addresses_to_start) / sizeof(addresses_to_start[0]);
1418 1 gate_size_t addresses_to_start_count = 0;
1419 1 gate_value_t value_autostart_enabled = GATE_INIT_EMPTY;
1420
1421 1 ret = gate_servicehost_get_service_addresses(impl, &addresses);
1422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1423
1424 1 length = gate_array_length(&addresses);
1425
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 for (index = 0; index != length; ++index)
1426 {
1427 3 gate_string_t const* ptr_address = (gate_string_t const*)gate_array_get(&addresses, index);
1428
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (ptr_address)
1429 {
1430 3 gate_bool_t autostart_enabled = false;
1431 3 gate_result_t result = gate_servicehost_get_service_config(impl, ptr_address,
1432 GATE_SERVICEHOST_CONFIG_AUTOSTART,
1433 &value_autostart_enabled);
1434
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (GATE_SUCCEEDED(result))
1435 {
1436 ✗ gate_value_get(&value_autostart_enabled, &autostart_enabled, sizeof(autostart_enabled));
1437 }
1438
1439
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (autostart_enabled)
1440 {
1441 ✗ addresses_to_start[addresses_to_start_count++] = ptr_address;
1442 ✗ if (addresses_to_start_count >= addresses_max)
1443 {
1444 ✗ break;
1445 }
1446 }
1447 }
1448 }
1449 1 gsvchost_start_services(impl, addresses_to_start, addresses_to_start_count);
1450 } while (0);
1451
1452 1 gate_array_release(&addresses);
1453
1454 1 return ret;
1455 }
1456 1 static gate_result_t gsvchost_shut_down(void* this_ptr, gate_bool_t release_services)
1457 {
1458 1 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
1459 1 gate_servicehost_impl_t* const impl = (gate_servicehost_impl_t*)this_ptr;
1460 1 gate_array_t addresses = GATE_INIT_EMPTY;
1461
1462 do
1463 {
1464 gate_size_t index;
1465 gate_size_t length;
1466 gate_string_t const* addresses_to_stop[512];
1467 1 gate_size_t const addresses_max = sizeof(addresses_to_stop) / sizeof(addresses_to_stop[0]);
1468 1 gate_size_t addresses_to_stop_count = 0;
1469
1470 1 ret = gate_servicehost_get_service_addresses(impl, &addresses);
1471
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1472
1473 1 length = gate_array_length(&addresses);
1474
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 for (index = 0; index != length; ++index)
1475 {
1476 3 gate_string_t const* ptr_address = (gate_string_t const*)gate_array_get(&addresses, index);
1477
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (ptr_address)
1478 {
1479 3 addresses_to_stop[addresses_to_stop_count++] = ptr_address;
1480
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (addresses_to_stop_count >= addresses_max)
1481 {
1482 ✗ break;
1483 }
1484 }
1485 }
1486 1 gsvchost_stop_services(impl, addresses_to_stop, addresses_to_stop_count);
1487
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (release_services)
1488 {
1489 1 gsvchost_release_services(impl, addresses_to_stop, addresses_to_stop_count);
1490 }
1491 } while (0);
1492
1493 1 gate_array_release(&addresses);
1494
1495 1 return ret;
1496 }
1497
1498
1499 static GATE_INTERFACE_VTBL(gate_servicehost) gate_servicehost_vtbl;
1500 1 static void gate_init_servicehost_vtbl()
1501 {
1502
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!gate_servicehost_vtbl.get_interface_name)
1503 {
1504 GATE_INTERFACE_VTBL(gate_servicehost) const local_vtbl =
1505 {
1506 &gsvchost_get_interface_name,
1507 &gsvchost_release,
1508 &gsvchost_retain,
1509
1510 &gsvchost_publish_message,
1511 &gsvchost_publish_object,
1512
1513 &gsvchost_subscribe_messages,
1514 &gsvchost_unsubscribe_messages,
1515
1516 &gsvchost_subscribe_objects,
1517 &gsvchost_unsubscribe_objects,
1518
1519 &gsvchost_remote_invoke,
1520
1521 &gsvchost_log,
1522
1523 &gsvchost_add_factory,
1524 &gsvchost_remove_factory,
1525 &gsvchost_get_factory_service_names,
1526
1527 &gsvchost_create_service,
1528 &gsvchost_get_service_addresses,
1529 &gsvchost_get_service,
1530 &gsvchost_get_service_config,
1531 &gsvchost_set_service_config,
1532 &gsvchost_start_service,
1533 &gsvchost_stop_service,
1534 &gsvchost_remove_service,
1535
1536 &gsvchost_start_up,
1537 &gsvchost_shut_down
1538 };
1539 1 gate_servicehost_vtbl = local_vtbl;
1540 }
1541 1 }
1542
1543
1544 1 gate_servicehost_t* gate_servicehost_create()
1545 {
1546 1 gate_servicehost_t* ret = NULL;
1547 1 gate_servicehost_impl_t* impl = NULL;
1548 do
1549 {
1550 1 impl = (gate_servicehost_impl_t*)gate_mem_alloc(sizeof(gate_servicehost_impl_t));
1551
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (impl == NULL)
1552 {
1553 ✗ break;
1554 }
1555
1556
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (GATE_SUCCEEDED(gsvchost_init_members(impl)))
1557 {
1558 1 gate_init_servicehost_vtbl();
1559 1 impl->vtbl = &gate_servicehost_vtbl;
1560 1 ret = (gate_servicehost_t*)impl;
1561 1 impl = NULL;
1562 }
1563
1564 } while (0);
1565
1566
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (impl != NULL)
1567 {
1568 ✗ gsvchost_destroy(impl);
1569 }
1570
1571 1 return ret;
1572 }
1573
1574
1575 ✗ gate_result_t gate_servicehost_load_config(gate_stream_t* srcstream, gate_uint32_t format, gate_servicehost_config_t* ptr_config)
1576 {
1577 ✗ gate_result_t ret = GATE_RESULT_FAILED;
1578 ✗ gate_property_t prop = GATE_INIT_EMPTY;
1579
1580 do
1581 {
1582 ✗ switch(format)
1583 {
1584 ✗ case GATE_SERVICEHOST_CONFIG_FORMAT_YAML:
1585 {
1586 ✗ gate_yaml_result_t yaml_result = GATE_INIT_EMPTY;
1587 ✗ ret = gate_yaml_parse(srcstream, &prop, &yaml_result);
1588 ✗ GATE_BREAK_IF_FAILED(ret);
1589 ✗ if (!yaml_result.succeeded)
1590 {
1591 ✗ ret = GATE_RESULT_INVALIDCONTENT;
1592 }
1593 ✗ break;
1594 }
1595 ✗ case GATE_SERVICEHOST_CONFIG_FORMAT_JSON:
1596 {
1597 ✗ gate_json_result_t json_result = GATE_INIT_EMPTY;
1598 ✗ ret = gate_json_parse(srcstream, &prop, &json_result);
1599 ✗ GATE_BREAK_IF_FAILED(ret);
1600 ✗ if (!json_result.succeeded)
1601 {
1602 ✗ ret = GATE_RESULT_INVALIDCONTENT;
1603 }
1604 ✗ break;
1605 }
1606 ✗ default:
1607 {
1608 ✗ ret = GATE_RESULT_INVALIDARG;
1609 ✗ break;
1610 }
1611 }
1612 ✗ GATE_BREAK_IF_FAILED(ret);
1613
1614 ✗ if (gate_property_get_type(&prop) != GATE_PROPERTY_TYPE_OBJECT)
1615 {
1616 ✗ ret = GATE_RESULT_INVALIDDATA;
1617 ✗ break;
1618 }
1619
1620 ✗ ret = gate_servicehost_config_init(&ptr_config->struct_base);
1621 ✗ GATE_BREAK_IF_FAILED(ret);
1622
1623 ✗ ret = gate_property_export(&prop, GATE_TYPE_STRUCT, &ptr_config->struct_base);
1624 } while (0);
1625
1626 ✗ gate_property_destroy(&prop);
1627
1628 ✗ return ret;
1629 }
1630 ✗ gate_result_t gate_servicehost_save_config(gate_servicehost_config_t const* config, gate_uint32_t format, gate_stream_t* deststream)
1631 {
1632 ✗ gate_result_t ret = GATE_RESULT_FAILED;
1633 ✗ gate_property_t prop = GATE_INIT_EMPTY;
1634
1635 do
1636 {
1637 ✗ ret = gate_property_import(&prop, GATE_TYPE_STRUCT, &config->struct_base);
1638 ✗ GATE_BREAK_IF_FAILED(ret);
1639
1640 ✗ switch(format)
1641 {
1642 ✗ case GATE_SERVICEHOST_CONFIG_FORMAT_YAML:
1643 ✗ ret = gate_yaml_build(&prop, deststream);
1644 ✗ break;
1645 ✗ case GATE_SERVICEHOST_CONFIG_FORMAT_JSON:
1646 ✗ ret = gate_json_build(&prop, deststream, 2);
1647 ✗ break;
1648 ✗ default:
1649 ✗ ret = GATE_RESULT_INVALIDARG;
1650 ✗ break;
1651 }
1652 ✗ GATE_BREAK_IF_FAILED(ret);
1653
1654 } while (0);
1655
1656 ✗ gate_property_destroy(&prop);
1657
1658 ✗ return ret;
1659 }
1660
1661 ✗ gate_result_t gate_servicehost_import_config(gate_servicehost_t* host, gate_servicehost_config_t const* config)
1662 {
1663 ✗ gate_result_t ret = GATE_RESULT_FAILED;
1664 gate_size_t index;
1665 ✗ gate_size_t count = gate_arraylist_length(config->services);
1666 ✗ gate_string_t address = GATE_STRING_INIT_EMPTY;
1667
1668 ✗ for (index = 0; index != count; ++index)
1669 {
1670 ✗ gate_microservice_t* ptr_microsvc = NULL;
1671 gate_servicehost_config_service_t const* ptr_svc =
1672 ✗ (gate_servicehost_config_service_t const*)gate_arraylist_get(config->services, index);
1673 ✗ if(!ptr_svc)
1674 {
1675 ✗ continue;
1676 }
1677 ✗ ret = gate_servicehost_create_service(host, &ptr_svc->name, &ptr_svc->instance, &address);
1678 ✗ GATE_BREAK_IF_FAILED(ret);
1679 ✗ ret = gate_servicehost_get_service(host, &address, &ptr_microsvc);
1680 ✗ if (GATE_SUCCEEDED(ret))
1681 {
1682 gate_size_t subscr_count;
1683 gate_size_t subscr_index;
1684 gate_value_t cfg_value;
1685
1686 ✗ if (gate_property_get_type(&ptr_svc->parameters) == GATE_PROPERTY_TYPE_OBJECT)
1687 {
1688 gate_size_t name_ndx, name_count;
1689 ✗ gate_array_t param_names = GATE_INIT_EMPTY;
1690
1691 ✗ if (NULL == gate_property_member_names(&ptr_svc->parameters, &param_names))
1692 {
1693 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1694 ✗ break;
1695 }
1696
1697 ✗ name_count = gate_array_length(&param_names);
1698 ✗ for (name_ndx = 0; name_ndx != name_count; ++name_ndx)
1699 {
1700 ✗ gate_string_t const* const ptr_name = (gate_string_t const*)gate_array_get(&param_names, name_ndx);
1701 ✗ if (ptr_name)
1702 {
1703 ✗ gate_property_t const* ptr_param_prop = gate_property_member_get(&ptr_svc->parameters, ptr_name);
1704 ✗ if (ptr_param_prop)
1705 {
1706 ✗ ret = gate_microservice_set_parameter(ptr_microsvc, ptr_name, ptr_param_prop);
1707 }
1708 }
1709 }
1710 ✗ gate_array_release(&param_names);
1711 }
1712 ✗ subscr_count = gate_arraylist_length(ptr_svc->msg_subscriptions);
1713 ✗ for (subscr_index = 0; subscr_index != subscr_count; ++subscr_index)
1714 {
1715 ✗ gate_string_t const* const subscr_str = (gate_string_t const*)gate_arraylist_get(ptr_svc->msg_subscriptions, subscr_index);
1716 ✗ if (subscr_str)
1717 {
1718 ✗ gate_size_t subscr_pos = gate_string_char_pos(subscr_str, ':', 0);
1719 ✗ if (subscr_pos == GATE_STR_NPOS)
1720 {
1721 ✗ gate_servicehost_subscribe_messages(host, subscr_str, &address, NULL, ptr_microsvc, NULL);
1722 }
1723 else
1724 {
1725 ✗ gate_string_t subscr_id = GATE_STRING_INIT_EMPTY;
1726 ✗ gate_string_t subscr_addr = GATE_STRING_INIT_EMPTY;
1727 ✗ gate_string_substr(&subscr_addr, subscr_str, 0, subscr_pos);
1728 ✗ gate_string_substr(&subscr_id, subscr_str, subscr_pos + 1, GATE_STR_NPOS);
1729 ✗ gate_servicehost_subscribe_messages(host, &subscr_addr, &address, &subscr_id, ptr_microsvc, NULL);
1730 ✗ gate_string_release(&subscr_id);
1731 ✗ gate_string_release(&subscr_addr);
1732 }
1733 }
1734 }
1735
1736 /* inject advanced configuration values */
1737 ✗ if (gate_value_create(GATE_TYPE_BOOL, &ptr_svc->autostart, &cfg_value))
1738 {
1739 ✗ gate_servicehost_set_service_config(host, &address, GATE_SERVICEHOST_CONFIG_AUTOSTART, &cfg_value);
1740 ✗ gate_value_release(&cfg_value);
1741 }
1742 ✗ if (gate_value_create(GATE_TYPE_UI32, &ptr_svc->startorder, &cfg_value))
1743 {
1744 ✗ gate_servicehost_set_service_config(host, &address, GATE_SERVICEHOST_CONFIG_STARTORDER, &cfg_value);
1745 ✗ gate_value_release(&cfg_value);
1746 }
1747 ✗ if (gate_value_create(GATE_TYPE_STRING, &ptr_svc->service_group, &cfg_value))
1748 {
1749 ✗ gate_servicehost_set_service_config(host, &address, GATE_SERVICEHOST_CONFIG_SERVICEGROUP, &cfg_value);
1750 ✗ gate_value_release(&cfg_value);
1751 }
1752 }
1753 ✗ if (NULL != ptr_microsvc)
1754 {
1755 ✗ gate_object_release(ptr_microsvc);
1756 }
1757
1758 ✗ gate_string_release(&address);
1759 ✗ ret = GATE_RESULT_OK;
1760 }
1761
1762 ✗ gate_string_release(&address);
1763 ✗ return ret;
1764 }
1765
1766 static const gate_string_t default_servicehost_config_id = GATE_STRING_INIT_STATIC("gate/microservices/config");
1767 static const gate_string_t default_servicehost_config_version = GATE_STRING_INIT_STATIC("1.0");
1768
1769 ✗ gate_result_t gate_servicehost_export_config(gate_servicehost_t* host, gate_servicehost_config_t* config)
1770 {
1771 ✗ gate_result_t ret = GATE_RESULT_FAILED;
1772 ✗ gate_array_t addresses = GATE_INIT_EMPTY;
1773 ✗ gate_microservice_t* ptr_svc = NULL;
1774 do
1775 {
1776 gate_size_t ndx, length;
1777 gate_property_t prop;
1778 gate_size_t name_index, name_count;
1779
1780 ✗ ret = gate_servicehost_get_service_addresses(host, &addresses);
1781 ✗ GATE_BREAK_IF_FAILED(ret);
1782
1783 ✗ ret = gate_servicehost_config_init(&config->struct_base);
1784 ✗ GATE_BREAK_IF_FAILED(ret);
1785
1786 ✗ gate_string_duplicate(&config->id, &default_servicehost_config_id);
1787 ✗ gate_string_duplicate(&config->version, &default_servicehost_config_version);
1788
1789 ✗ length = gate_array_length(&addresses);
1790 ✗ for (ndx = 0; ndx != length; ++ndx)
1791 {
1792 gate_servicehost_config_service_t cfg_svc;
1793 gate_string_t const* ptr_str;
1794 ✗ if (ptr_svc != NULL)
1795 {
1796 ✗ gate_object_release(ptr_svc);
1797 ✗ ptr_svc = NULL;
1798 }
1799
1800 ✗ ptr_str = (gate_string_t const*)gate_array_get(&addresses, ndx);
1801 ✗ if (!ptr_str)
1802 {
1803 ✗ continue;
1804 }
1805 ✗ ret = gate_servicehost_get_service(host, ptr_str, &ptr_svc);
1806 ✗ if (GATE_FAILED(ret))
1807 {
1808 ✗ continue;
1809 }
1810
1811 ✗ ret = gate_servicehost_config_service_init(&cfg_svc.struct_base);
1812
1813 ✗ if (GATE_SUCCEEDED(ret))
1814 {
1815 ✗ gate_array_t param_names = GATE_INIT_EMPTY;
1816 ✗ gate_string_t const str_name = GATE_STRING_INIT_EMPTY;
1817 ✗ gate_string_t const str_instance = GATE_STRING_INIT_EMPTY;
1818 ✗ gate_string_duplicate(&cfg_svc.name, &str_name);
1819 ✗ gate_string_duplicate(&cfg_svc.instance, &str_instance);
1820
1821 ✗ ret = gate_microservice_get_parameter_names(ptr_svc, &param_names);
1822 ✗ if (GATE_SUCCEEDED(ret))
1823 {
1824 gate_property_t service_params;
1825 ✗ if (NULL != gate_property_create_object(&service_params))
1826 {
1827 ✗ name_count = gate_array_length(&param_names);
1828 ✗ for (name_index = 0; name_index != name_count; ++name_index)
1829 {
1830 ✗ gate_string_t const* const ptr_param_name = (gate_string_t const*)gate_array_get(&param_names, name_index);
1831 ✗ if (ptr_param_name)
1832 {
1833 ✗ ret = gate_microservice_get_parameter(ptr_svc, ptr_param_name, &prop);
1834 ✗ if (GATE_FAILED(ret))
1835 {
1836 ✗ continue;
1837 }
1838 ✗ gate_property_member_add(&service_params, ptr_param_name, &prop);
1839 ✗ gate_property_destroy(&prop);
1840 }
1841 }
1842 ✗ gate_mem_copy(&cfg_svc.parameters, &service_params, sizeof(gate_property_t));
1843 }
1844 ✗ gate_array_release(&param_names);
1845 }
1846 ✗ gate_arraylist_add(config->services, &cfg_svc.struct_base);
1847 ✗ gate_struct_release(&cfg_svc.struct_base);
1848 }
1849 }
1850
1851 } while (0);
1852
1853 ✗ if (ptr_svc != NULL)
1854 {
1855 ✗ gate_object_release(ptr_svc);
1856 ✗ ptr_svc = NULL;
1857 }
1858
1859 ✗ gate_array_release(&addresses);
1860 ✗ return ret;
1861 }
1862
1863 ✗ gate_result_t gate_servicehost_release_services(gate_servicehost_t* host)
1864 {
1865 gate_result_t result;
1866 ✗ gate_array_t addrs = GATE_INIT_EMPTY;
1867
1868 do
1869 {
1870 gate_enumerator_t addrs_enum;
1871 gate_string_t const* ptr_addr;
1872 ✗ result = gate_servicehost_get_service_addresses(host, &addrs);
1873 ✗ GATE_BREAK_IF_FAILED(result);
1874
1875 ✗ if (NULL == gate_array_enumerate(&addrs, &addrs_enum))
1876 {
1877 ✗ result = GATE_RESULT_OUTOFMEMORY;
1878 ✗ break;
1879 }
1880
1881 ✗ GATE_FOR_ENUMERATOR(gate_string_t, ptr_addr, &addrs_enum)
1882 {
1883 ✗ gate_servicehost_release_service(host, ptr_addr);
1884 }
1885
1886 } while (0);
1887
1888 ✗ gate_array_release(&addrs);
1889
1890 ✗ return result;
1891 }
1892