GCC Code Coverage Report


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