R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
R3BUcesbLauncher.cxx
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) 2019 GSI Helmholtzzentrum für Schwerionenforschung GmbH *
3 * Copyright (C) 2019-2025 Members of R3B Collaboration *
4 * *
5 * This software is distributed under the terms of the *
6 * GNU General Public Licence (GPL) version 3, *
7 * copied verbatim in the file "LICENSE". *
8 * *
9 * In applying this license GSI does not waive the privileges and immunities *
10 * granted to it by virtue of its status as an Intergovernmental Organization *
11 * or submit itself to any jurisdiction. *
12 ******************************************************************************/
13
14#include "R3BUcesbLauncher.h"
15#include <R3BException.h>
16#include <R3BLogger.h>
17#include <R3BShared.h>
18#include <boost/algorithm/string.hpp>
19#include <filesystem>
20#include <fmt/os.h>
21#include <regex>
22
23#include <ext_data_clnt.hh>
24
25constexpr auto CHILD_CLOSE_WAITING_TIME = std::chrono::seconds(5);
26
27namespace fs = std::filesystem;
28namespace bp = boost::process;
29namespace
30{
31 bool Check_exist(std::string_view exe)
32 {
33 auto exe_path = fs::path{ exe };
34 return fs::exists(exe_path) || fs::is_symlink(exe_path);
35 }
36
37 // TODO: C++23 insert range
38 template <typename T>
39 void Append_elements(std::vector<T>& base, std::vector<T> to_append)
40 {
41 base.reserve(base.size() + to_append.size());
42 for (auto& ele : to_append)
43 {
44 base.emplace_back(std::move(ele));
45 }
46 }
47
48 void Append_lmds(std::vector<std::string>& lmds, std::string_view filename_regex)
49 {
50 // expand filenames on regex
51 Append_elements(lmds, R3B::GetFilesFromRegex(filename_regex));
52 }
53
54 auto parse_splits(std::vector<std::string> splits) -> R3B::UcesbServerLauncher::ResolveResult
55 {
57
58 auto option_regex = std::regex{ "^--[0-9A-z,=\\-]+" };
59 auto lmd_regex = std::regex{ "^.*\\.lmd$" };
60
61 for (auto& split_item : splits)
62 {
63 if (std::regex_match(split_item, option_regex))
64 {
65 result.options.emplace_back(std::move(split_item));
66 }
67 else if (std::regex_match(split_item, lmd_regex))
68 {
69 Append_lmds(result.lmds, split_item);
70 }
71 else if (Check_exist(split_item))
72 {
73 // it must be an executable then
74 if (not result.executable.empty())
75 {
76 R3BLOG(info, fmt::format("Ucesb Executable has been set to \"{}\" ", result.executable));
77 R3BLOG(error, fmt::format("Found another executable \"{}\" but only one is allowed!", split_item));
78 continue;
79 }
80 R3BLOG(info, fmt::format("Ucesb Executable is set to \"{}\" ", split_item));
81 result.executable = std::move(split_item);
82 }
83 else
84 {
85 // In other cases, let ucesb deal with this
86 result.others.emplace_back(std::move(split_item));
87 }
88 }
89 return result;
90 }
91
92 void lmd_filenames_sorting(std::vector<std::string>& filenames)
93 {
94 // simple lexicographically sorting
95 std::sort(filenames.begin(), filenames.end());
96 }
97
98 auto resolve_exe_options_lmd(std::string cmd) -> R3B::UcesbServerLauncher::ResolveResult
99 {
100 if (cmd.empty())
101 {
102 throw R3B::logic_error("Ucesb command string is empty!");
103 }
104 R3BLOG(debug, fmt::format("Resolving string command: {}", cmd));
105 boost::trim(cmd);
106 auto splits = std::vector<std::string>{};
107 boost::split(splits, cmd, boost::is_any_of(" "), boost::token_compress_on);
108 if (splits.empty())
109 {
110 throw R3B::runtime_error(fmt::format("Get 0 element from splitting string {}", cmd));
111 }
112 auto results = parse_splits(std::move(splits));
113 lmd_filenames_sorting(results.lmds);
114
115 return results;
116 }
117} // namespace
118
119namespace R3B
120{
121 void UcesbServerLauncher::SetLaunchCmd(const std::string& command_string)
122 {
123 launch_strings_ = resolve_exe_options_lmd(command_string);
124 if (launch_strings_.executable.empty())
125 {
126 R3BLOG(error, fmt::format("An unpacker executable doesn't exist in options {:?}", command_string));
127 }
128 Append_elements(launch_args, std::move(launch_strings_.options));
129 Append_elements(launch_args, std::move(launch_strings_.lmds));
130 Append_elements(launch_args, std::move(launch_strings_.others));
131
132 R3BLOG(debug,
133 fmt::format("Ucesb command after resolving wildcard filename: \n {} {}",
134 launch_strings_.executable,
135 fmt::join(launch_args, " ")));
136 }
137
139 {
140 server_pipe_ = boost::process::async_pipe{ ios_ };
141 ucesb_server_ = std::make_unique<boost::process::child>(
142 launch_strings_.executable, boost::process::args(launch_args), boost::process::std_out > server_pipe_);
143 R3BLOG(info, fmt::format("Launching an ucesb server with pid: {}", ucesb_server_->id()));
144 if (auto is_status_ok = client_->connect(server_pipe_.native_source()); not is_status_ok)
145 {
146 R3BLOG(error, "ext_data_clnt::connect() failed");
147 const auto* msg = (client_->last_error() == nullptr) ? UCESB_NULL_STR_MSG : client_->last_error();
148 throw R3B::runtime_error(fmt::format("UCESB error: {}", msg));
149 }
150 }
151
152 // void UcesbServerLauncher::Setup(ext_data_struct_info& struct_info, size_t event_struct_size) {}
153
155 {
156 if (auto ret_val = client_->close(); ret_val != 0)
157 {
158 R3BLOG(error, "ext_data_clnt::close() failed");
159 }
160 auto err_code = std::error_code{};
161 auto boost_err = boost::system::error_code{};
162
163 server_pipe_.close(boost_err);
164 R3BLOG(info, fmt::format("pipe closed: {}", boost_err.what()));
165
166 if (not ucesb_server_->wait_for(CHILD_CLOSE_WAITING_TIME, err_code))
167 {
168 R3BLOG(warn, fmt::format("Failed to close Ucesb server! Error code: {}", err_code.value()));
169 ucesb_server_->terminate(err_code);
170 R3BLOG(warn, "Killing Ucesb server");
171 }
172 else
173 {
174 R3BLOG(info, "Ucesb server is closed successfully");
175 }
176
177 auto child_handle = bp::child::child_handle{ ucesb_server_->id() };
178 R3BLOG(warn, fmt::format("Trying to killing Ucesb server with pid: {}", child_handle.id()));
179 bp::detail::api::terminate(child_handle, err_code);
180 // ucesb_server_->terminate(err_code);
181 // std::this_thread::sleep_for(std::chrono::seconds(1));
182 R3BLOG(info, fmt::format("Killed: {}", err_code));
183 }
184} // namespace R3B
#define R3BLOG(severity, x)
Definition R3BLogger.h:35
constexpr auto CHILD_CLOSE_WAITING_TIME
constexpr auto UCESB_NULL_STR_MSG
void SetLaunchCmd(const std::string &command_string)
auto GetFilesFromRegex(std::string_view filename_regex) -> std::vector< std::string >
Definition R3BShared.h:197