GCC Code Coverage Report


Directory: src/gate/
File: src/gate/tech/microservices/procrunner_service.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 0 81 0.0%
Functions: 0 8 0.0%
Branches: 0 16 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 #include "gate/tech/microservices/procrunner_service.h"
29 #include "gate/processes.h"
30 #include "gate/applications.h"
31 #include "gate/results.h"
32
33 typedef struct procrunner_config_class
34 {
35 gate_struct_t struct_base;
36
37 gate_bool_t autostart; /* start executable on service startup */
38 gate_string_t start_on_msg_id; /* start executable when a specific message is received */
39 gate_bool_t append_msg_to_arguments; /* append received message content to process arguments */
40
41 gate_string_t executable; /* path to process executable */
42 gate_string_t arguments; /* process arguments */
43 gate_string_t working_directory; /* process working directory */
44 gate_string_t location; /* system location (e.g. session) where process is started */
45 gate_uint32_t flags; /* process creation flags */
46
47 } procrunner_config_t;
48
49
50 #define PROCRUNNER_ROOT_NAME "procrunner_service"
51
52 #define PROCRUNNER_CONFIG_NAME GATE_STRUCT_ROOT_NAME GATE_STRUCT_SEPARATOR PROCRUNNER_ROOT_NAME GATE_STRUCT_SEPARATOR "config"
53
54 static gate_struct_item_t const procrunner_config_members[] =
55 {
56 GATE_STRUCT_ITEM(procrunner_config_t, GATE_TYPE_BOOL, autostart),
57 GATE_STRUCT_ITEM(procrunner_config_t, GATE_TYPE_STRING, start_on_msg_id),
58 GATE_STRUCT_ITEM(procrunner_config_t, GATE_TYPE_BOOL, append_msg_to_arguments),
59
60 GATE_STRUCT_ITEM(procrunner_config_t, GATE_TYPE_STRING, executable),
61 GATE_STRUCT_ITEM(procrunner_config_t, GATE_TYPE_STRING, arguments),
62 GATE_STRUCT_ITEM(procrunner_config_t, GATE_TYPE_STRING, working_directory),
63 GATE_STRUCT_ITEM(procrunner_config_t, GATE_TYPE_STRING, location),
64 GATE_STRUCT_ITEM(procrunner_config_t, GATE_TYPE_UI32, flags)
65 };
66
67 static gate_struct_descriptor_t const procrunner_config_descriptor =
68 {
69 PROCRUNNER_CONFIG_NAME,
70 procrunner_config_members,
71 sizeof(procrunner_config_members) / sizeof(procrunner_config_members[0]),
72 sizeof(procrunner_config_t)
73 };
74
75
76 typedef struct gate_procrunner_service_data_class
77 {
78 procrunner_config_t config;
79 } gate_procrunner_service_data_t;
80
81
82 static void procrunner_on_release(gate_microservice_base_t* self)
83 {
84 gate_procrunner_service_data_t* data = (gate_procrunner_service_data_t*)self->data_ptr;
85 gate_struct_release(&data->config.struct_base);
86 }
87
88 static void procrunner_execute_process(gate_microservice_base_t* self, gate_string_t const* arg_update)
89 {
90 char buffer[4096];
91 gate_strbuilder_t arg_builder = GATE_INIT_EMPTY;
92 gate_strbuilder_t log_builder = GATE_INIT_EMPTY;
93 gate_string_t args = GATE_STRING_INIT_EMPTY;
94 gate_string_t logmsg = GATE_STRING_INIT_EMPTY;
95 gate_procrunner_service_data_t* data = (gate_procrunner_service_data_t*)self->data_ptr;
96 gate_string_t arg_items[256];
97 gate_size_t arg_count = 0;
98 gate_result_t res;
99 gate_uint32_t flags = 0;
100 gate_size_t index;
101
102 do
103 {
104 gate_mem_clear(&arg_items[0], sizeof(arg_items));
105 gate_strbuilder_create_static(&arg_builder, buffer, sizeof(buffer), 0);
106
107 if (!gate_string_is_empty(&data->config.arguments))
108 {
109 gate_strbuilder_append_string(&arg_builder, &data->config.arguments);
110 }
111 if (!gate_string_is_empty(arg_update))
112 {
113 gate_strbuilder_append_string(&arg_builder, arg_update);
114 }
115 gate_strbuilder_to_string(&arg_builder, &args);
116
117 arg_count = gate_app_parse_args(&args, arg_items, sizeof(arg_items) / sizeof(arg_items[0]));
118
119 flags = data->config.flags;
120 flags |= GATE_PROCESS_START_NEWSESSION;
121 flags |= GATE_PROCESS_START_NOINHERIT;
122 flags |= GATE_PROCESS_START_PRIVILEGED;
123
124 res = gate_process_start(&data->config.executable, &arg_items[0], arg_count,
125 &data->config.working_directory, NULL, 0, flags,
126 NULL, NULL, NULL);
127
128 for (index = 0; index != arg_count; ++index)
129 {
130 gate_string_release(&arg_items[index]);
131 }
132
133 gate_string_release(&args);
134 gate_strbuilder_release(&arg_builder);
135
136 gate_strbuilder_create_static(&log_builder, buffer, sizeof(buffer), 0);
137
138 if (GATE_SUCCEEDED(res))
139 {
140 gate_strbuilder_append(&log_builder,
141 GATE_PRINT_CSTR, "Process started: ",
142 GATE_PRINT_STRING, &data->config.executable,
143 GATE_PRINT_END);
144 gate_strbuilder_to_string(&log_builder, &logmsg);
145
146 gate_microhost_log(self->host, GATE_MICROSERVICE_LOGTYPE_STATUS, 0, 0,
147 &self->address, &logmsg);
148 }
149 else
150 {
151 gate_strbuilder_append(&log_builder,
152 GATE_PRINT_CSTR, "Process start failed: ",
153 GATE_PRINT_STRING, &data->config.executable,
154 GATE_PRINT_END);
155 gate_strbuilder_to_string(&log_builder, &logmsg);
156
157 gate_microhost_log(self->host, GATE_MICROSERVICE_LOGTYPE_ERROR, res, 0,
158 &self->address, &logmsg);
159 }
160
161 } while (0);
162
163 gate_string_release(&logmsg);
164 gate_string_release(&args);
165 gate_strbuilder_release(&log_builder);
166 gate_strbuilder_release(&arg_builder);
167
168 }
169
170 static gate_result_t procrunner_on_start(gate_microservice_base_t* self)
171 {
172 gate_result_t ret = GATE_RESULT_OK;
173 gate_procrunner_service_data_t* data = (gate_procrunner_service_data_t*)self->data_ptr;
174
175 /* export parameters from property storage to native config struct */
176 gate_property_export(&self->parameters, GATE_TYPE_STRUCT, &data->config.struct_base);
177
178 if (data->config.autostart)
179 {
180 procrunner_execute_process(self, NULL);
181 }
182
183 return ret;
184 }
185 static gate_result_t procrunner_on_stop(gate_microservice_base_t* self)
186 {
187 gate_result_t ret = GATE_RESULT_OK;
188 gate_procrunner_service_data_t* data = (gate_procrunner_service_data_t*)self->data_ptr;
189
190 gate_struct_release(&data->config.struct_base);
191
192 return ret;
193 }
194 static gate_result_t procrunner_on_message_received(gate_microservice_base_t* self,
195 gate_string_t const* source, gate_string_t const* destination,
196 gate_string_t const* msg_id, gate_string_t const* message)
197 {
198 gate_result_t ret = GATE_RESULT_OK;
199 gate_procrunner_service_data_t* data = (gate_procrunner_service_data_t*)self->data_ptr;
200
201 GATE_UNUSED_ARG(source);
202 GATE_UNUSED_ARG(destination);
203
204 if (!gate_string_is_empty(&data->config.start_on_msg_id))
205 {
206 if (gate_string_equals(msg_id, &data->config.start_on_msg_id))
207 {
208 procrunner_execute_process(self, message);
209 }
210 }
211
212 return ret;
213 }
214 static gate_result_t procrunner_on_object_received(gate_microservice_base_t* self,
215 gate_string_t const* source, gate_string_t const* destination,
216 gate_string_t const* obj_id, gate_object_t* obj)
217 {
218 GATE_UNUSED_ARG(self);
219 GATE_UNUSED_ARG(source);
220 GATE_UNUSED_ARG(destination);
221 GATE_UNUSED_ARG(obj_id);
222 GATE_UNUSED_ARG(obj);
223 return GATE_RESULT_NOTSUPPORTED;
224 }
225 static gate_result_t procrunner_on_invoke(gate_microservice_base_t* self, gate_string_t const* method,
226 gate_struct_t const* request, gate_struct_t* response)
227 {
228 GATE_UNUSED_ARG(self);
229 GATE_UNUSED_ARG(method);
230 GATE_UNUSED_ARG(request);
231 GATE_UNUSED_ARG(response);
232 return GATE_RESULT_NOTSUPPORTED;
233 }
234
235
236 gate_microservice_t* gate_microservice_procrunner_create()
237 {
238 gate_microservice_base_t* procrunner_service = gate_microservice_base_create(sizeof(gate_procrunner_service_data_t), NULL);
239 gate_procrunner_service_data_t* procrunner_data;
240
241 if (procrunner_service)
242 {
243 procrunner_service->on_start = &procrunner_on_start;
244 procrunner_service->on_stop = &procrunner_on_stop;
245 procrunner_service->on_release = &procrunner_on_release;
246 procrunner_service->on_message_received = &procrunner_on_message_received;
247 procrunner_service->on_object_received = &procrunner_on_object_received;
248 procrunner_service->on_invoke = procrunner_on_invoke;
249
250 procrunner_data = (gate_procrunner_service_data_t*)procrunner_service->data_ptr;
251 gate_struct_init(&procrunner_data->config.struct_base, &procrunner_config_descriptor);
252 gate_property_create_object(&procrunner_service->parameters);
253 gate_property_import(&procrunner_service->parameters, GATE_TYPE_STRUCT, &procrunner_data->config.struct_base);
254 procrunner_service->ptr_parameters = &procrunner_data->config.struct_base;
255
256 }
257 return (gate_microservice_t*)procrunner_service;
258 }
259
260