pars 0.2.1
Loading...
Searching...
No Matches
client.cpp
Go to the documentation of this file.
1/*
2Copyright (c) 2025 Giuseppe Roberti.
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without modification,
6are permitted provided that the following conditions are met:
7
81. Redistributions of source code must retain the above copyright notice, this
9list of conditions and the following disclaimer.
10
112. Redistributions in binary form must reproduce the above copyright notice,
12this list of conditions and the following disclaimer in the documentation and/or
13other materials provided with the distribution.
14
153. Neither the name of the copyright holder nor the names of its contributors
16may be used to endorse or promote products derived from this software without
17specific prior written permission.
18
19THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29*/
30#include "event.h"
31
33{
34
35using namespace event;
36using namespace resource;
37
39class client : public app::single<comp::client>
40{
41private:
43
44 using parent_type = self_type;
45 using self = client;
46
48
49 milli req_recv_timeout{-1};
50 milli req_send_timeout{1000};
51
53
54 component_type::connect_p connect_p;
55 std::size_t work_id = 0;
56 bool fast_fib = false;
57 uint64_t n = 0;
58
60
61 app::state_machine<client_state> state = {client_state::creating};
62
64
65 using parent_type::parent_type;
66
68
69 void usage()
70 {
71 throw std::invalid_argument(
72 "Usage: ./client service_cmode service_addr work_id fast_or_slow N");
73 }
74
75 void startup(int argc, char** argv) override
76 {
78
80 auto ts = state.tx(client_state::creating, client_state::initializing);
81
83 switch (argc)
84 {
85 case 6:
86 connect_p.service_cmode = net::cmode_from_string(argv[1]);
87
88 connect_p.service_addr = argv[2];
89
90 work_id = std::stoull(argv[3]);
91
92 if (std::string_view(argv[4]).compare("fast") == 0)
93 fast_fib = true;
94 else if (std::string_view(argv[4]).compare("slow") == 0)
95 fast_fib = false;
96 else
97 usage();
98
99 n = std::stoull(argv[5]);
100
101 break;
102
103 default:
104 usage();
105 }
106
108 hfs().on<fired, init>(&self::initialize, this);
109
110 hfs().on<fired, exception>(&self::terminate, this);
111
112 comp().req().on<fired, pipe_created>(&self::send_work, this);
113
114 comp().req().on<sent, fib_requested>(&self::recv_answer, this);
115
116 comp().req().on<received, fib_computed>(&self::terminate, this);
117
118 comp().req().on<fired, network_error>(&self::terminate, this);
119
120 comp().req().on<fired, pipe_removed>(&self::terminate, this);
121
123 ts.commit();
124
125 pars::info(SL, "Application Started!");
126 }
127
129
130 void initialize(hf_arg<fired, init> fired)
131 {
132 auto ts = state.tx(client_state::initializing, client_state::started);
133
134 comp().init({.req_opts = {.recv_timeout = req_recv_timeout.count(),
135 .send_timeout = req_send_timeout.count()}});
136
137 comp().connect(connect_p);
138
139 ts.commit();
140
141 pars::info(SL, "Fired {}, Application Initialized!", fired.event());
142 }
143
144 void send_work(hf_arg<fired, pipe_created> fired)
145 {
146 auto ts = state.tx(client_state::started, client_state::sending_work);
147
148 auto [ev, md] = fired.as_tuple();
149
150 auto out_ev = fib_requested{work_id, n, fast_fib};
151
152 // use the default context on the sock to send the event
153 comp().req().sock().send(out_ev, md.pipe());
154
155 ts.commit();
156
157 pars::info(SL, "Fired {}, Sent {}!", ev, out_ev);
158 }
159
160 void recv_answer(hf_arg<sent, fib_requested> sent)
161 {
162 auto ts =
163 state.tx(client_state::sending_work, client_state::waiting_work_done);
164
165 // recv on the default context of the sock
166 comp().req().sock().recv();
167
168 ts.commit();
169
170 pars::info(SL, "Sent {}, Receiving!", sent.event());
171 }
172
173 void terminate(hf_arg<received, fib_computed> recv)
174 {
175 auto ts =
176 state.tx(client_state::waiting_work_done, client_state::terminating);
177
178 auto& ev = recv.event();
179
181
182 ts.commit();
183
184 pars::info(SL, "Received {}, Application Terminated!", ev);
185
186 std::cout << "WORK(" << ev.work_id << ") FIB(" << n << ") = " << ev.fib_n
187 << "\n";
188 }
189
190 void terminate(hf_arg<fired, exception> fired)
191 {
192 auto ts = state.tx(client_state::terminated);
193
194 auto& ev = fired.event();
195
197
198 ts.commit();
199
200 pars::info(SL, "Fired {} while \"{}\", Application Terminated!", ev,
201 state.current());
202
203 std::cout << std::format("ERROR: {}", ev) << std::endl;
204 }
205
206 void terminate(hf_arg<fired, network_error> fired)
207 {
208 auto ts = state.tx(client_state::terminated);
209
210 auto& ev = fired.event();
211
213
214 ts.commit();
215
216 pars::info(SL, "Fired {} while \"{}\", Application Terminated!", ev,
217 state.current());
218
219 std::cout << std::format("ERROR: {}", ev.error) << std::endl;
220 }
221
222 void terminate(hf_arg<fired, pipe_removed> fired)
223 {
224 auto ts = state.tx(client_state::terminated);
225
227
228 ts.commit();
229
230 pars::info(SL, "Fired {} while \"{}\", Application Terminated!",
231 fired.event(), state.current());
232
233 std::cout << std::format("Client Disconnected!") << std::endl;
234 }
235};
236
237} // namespace pars_example::apps
238
239int main(int argc, char** argv)
240{
242
243 try
244 {
245 return app.exec(argc, argv);
246 }
247 catch (std::exception& e)
248 {
249 std::cout << std::format("Error: {}", e.what()) << "\n";
250
251 return EXIT_FAILURE;
252 }
253}
single< component_type > self_type
Definition single.h:47
ev::hf_registry & hfs()
Definition single.h:74
component_type & comp()
Definition single.h:70
void init(const init_p &params)
Definition client.h:54
void connect(const connect_p &params)
Definition client.h:62
net::req & req()
Definition client.h:47
void on(void(class_t::*hf)(ev::hf_arg< kind_of, event_t >), class_t *self)
Definition req.h:75
socket & sock()
Get the socket.
Definition req.h:56
void send(event_t ev, pipe p={})
Definition socket.h:136
Runs the client component as an single application (req)
Definition client.cpp:40
int main(int argc, char **argv)
Definition client.cpp:239
#define SL
Definition log.h:58
kind_of< event_t > hf_arg
Definition make_hf.h:46
void info(spdlog::source_loc loc, pars::lf lf, spdlog::format_string_t< args_t... > fmt, args_t &&... args)
Definition log.h:157
std::chrono::duration< nng_duration, std::milli > milli
Definition init.h:47
void on(void(class_t::*mem_fn)(hf_arg< kind_of, event_t >), class_t *self)
Definition hf_registry.h:74