]> git.tdb.fi Git - r2c2.git/blob - source/network/server.cpp
Separate train routing logic to a class derived from TrainAI
[r2c2.git] / source / network / server.cpp
1 #include <msp/core/refptr.h>
2 #include <msp/net/inet.h>
3 #include <msp/net/resolve.h>
4 #include "libr2c2/driver.h"
5 #include "libr2c2/route.h"
6 #include "libr2c2/train.h"
7 #include "libr2c2/trainrouter.h"
8 #include "libr2c2/trainstatus.h"
9 #include "libr2c2/vehicletype.h"
10 #include "server.h"
11
12 using namespace std;
13 using namespace Msp;
14
15 namespace R2C2 {
16
17 Server::Server(Layout &l):
18         layout(l),
19         listen_sock(Net::INET),
20         event_disp(0)
21 {
22         layout.get_driver().signal_power.connect(sigc::hide(sigc::mem_fun(this, &Server::driver_state_changed)));
23         layout.get_driver().signal_halt.connect(sigc::hide(sigc::mem_fun(this, &Server::driver_state_changed)));
24         layout.signal_emergency.connect(sigc::mem_fun(this, &Server::emergency));
25
26         layout.signal_train_added.connect(sigc::mem_fun(this, &Server::train_added));
27
28         const map<unsigned, Train *> &trains = layout.get_trains();
29         for(map<unsigned, Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
30                 train_added(*i->second);
31
32         RefPtr<Net::SockAddr> addr = Net::resolve("*", "8315", Net::INET);
33         listen_sock.listen(*addr, 4);
34         listen_sock.signal_data_available.connect(sigc::mem_fun(this, &Server::incoming_connection));
35 }
36
37 void Server::use_event_dispatcher(IO::EventDispatcher &ed)
38 {
39         event_disp = &ed;
40         event_disp->add(listen_sock);
41 }
42
43 void Server::incoming_connection()
44 {
45         Net::StreamSocket *sock = listen_sock.accept();
46         if(event_disp)
47                 event_disp->add(*sock);
48         connections.push_back(new Connection(*this, sock));
49 }
50
51 void Server::driver_state_changed()
52 {
53         DriverStatePacket pkt;
54         pkt.power = layout.get_driver().get_power();
55         pkt.halt = layout.get_driver().is_halted();
56         send(pkt);
57 }
58
59 void Server::emergency(const string &msg)
60 {
61         EmergencyPacket pkt;
62         pkt.message = msg;
63         send(pkt);
64 }
65
66 void Server::train_added(Train &train)
67 {
68         train.signal_control_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_control_changed), sigc::ref(train)));
69         train.signal_function_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_function_changed), sigc::ref(train)));
70         train.signal_ai_event.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_ai_event), sigc::ref(train)));
71
72         TrainInfoPacket pkt;
73         pkt.address = train.get_address();
74         pkt.loco_type = train.get_locomotive_type().get_article_number().str();
75         pkt.name = train.get_name();
76         send(pkt);
77
78         TrainStatus *status = new TrainStatus(train);
79         status->set_tag("server:status");
80         status->signal_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_status_changed), sigc::ref(train)));
81 }
82
83 void Server::train_control_changed(const Train &train, const string &control, float value)
84 {
85         TrainControlPacket pkt;
86         pkt.address = train.get_address();
87         pkt.control = control;
88         pkt.value = value;
89         send(pkt);
90 }
91
92 void Server::train_function_changed(const Train &train, unsigned, bool)
93 {
94         TrainFunctionPacket pkt;
95         pkt.address = train.get_address();
96         pkt.functions = train.get_functions();
97         send(pkt);
98 }
99
100 void Server::train_ai_event(const Train &train, TrainAI &, const TrainAI::Message &ev)
101 {
102         if(ev.type=="route-changed")
103         {
104                 TrainRoutePacket pkt;
105                 pkt.address = train.get_address();
106                 if(const Route *route = ev.value.value<const Route *>())
107                         pkt.route = route->get_name();
108                 send(pkt);
109         }
110 }
111
112 void Server::train_status_changed(const Train &train, const string &status)
113 {
114         TrainStatusPacket pkt;
115         pkt.address = train.get_address();
116         pkt.status = status;
117         send(pkt);
118 }
119
120 template<typename P>
121 void Server::send(const P &pkt)
122 {
123         for(vector<Connection *>::const_iterator i=connections.begin(); i!=connections.end(); ++i)
124                 if(!(*i)->stale && (*i)->comm.is_handshake_done())
125                 {
126                         try
127                         {
128                                 (*i)->comm.send(pkt);
129                         }
130                         catch(...)
131                         {
132                                 (*i)->stale = true;
133                         }
134                 }
135 }
136
137
138 Server::Connection::Connection(Server &s, Net::StreamSocket *o):
139         server(s),
140         socket(o),
141         comm(*socket, server.proto, *this)
142 {
143         socket->signal_end_of_file.connect(sigc::mem_fun(this, &Connection::end_of_file));
144         comm.signal_handshake_done.connect(sigc::mem_fun(this, &Connection::handshake_done));
145         comm.initiate_handshake();
146 }
147
148 Server::Connection::~Connection()
149 {
150         delete socket;
151 }
152
153 void Server::Connection::handshake_done()
154 {
155         {
156                 DriverStatePacket pkt;
157                 pkt.power = server.layout.get_driver().get_power();
158                 pkt.halt = server.layout.get_driver().is_halted();
159                 comm.send(pkt);
160         }
161
162         const set<Route *> &routes = server.layout.get_routes();
163         for(set<Route *>::const_iterator i=routes.begin(); i!=routes.end(); ++i)
164                 if(!(*i)->is_temporary())
165                 {
166                         RouteInfoPacket pkt;
167                         pkt.name = (*i)->get_name();
168                         comm.send(pkt);
169                 }
170
171         const map<unsigned, Train *> &trains = server.layout.get_trains();
172         for(map<unsigned, Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
173         {
174                 const Train &train = *i->second;
175
176                 {
177                         TrainInfoPacket pkt;
178                         pkt.address = train.get_address();
179                         pkt.loco_type = train.get_locomotive_type().get_article_number().str();
180                         pkt.name = train.get_name();
181                         comm.send(pkt);
182                 }
183                 for(unsigned j=0;; ++j)
184                 {
185                         const char *name = train.get_controller().enumerate_controls(j);
186                         if(!name)
187                                 break;
188
189                         TrainControlPacket pkt;
190                         pkt.address = train.get_address();
191                         pkt.control = name;
192                         pkt.value = train.get_control(name);
193                         comm.send(pkt);
194                 }
195                 {
196                         TrainFunctionPacket pkt;
197                         pkt.address = train.get_address();
198                         pkt.functions = train.get_functions();
199                         comm.send(pkt);
200                 }
201                 if(TrainStatus *status = dynamic_cast<TrainStatus *>(train.get_tagged_ai("server:status")))
202                 {
203                         TrainStatusPacket pkt;
204                         pkt.address = train.get_address();
205                         pkt.status = status->get_status();
206                         comm.send(pkt);
207                 }
208                 if(TrainRouter *router = dynamic_cast<TrainRouter *>(train.get_tagged_ai("router")))
209                 {
210                         TrainRoutePacket pkt;
211                         pkt.address = train.get_address();
212                         pkt.route = router->get_route()->get_name();
213                         comm.send(pkt);
214                 }
215         }
216 }
217
218 void Server::Connection::end_of_file()
219 {
220         stale = true;
221 }
222
223 void Server::Connection::receive(const DriverStatePacket &pkt)
224 {
225         Driver &driver = server.layout.get_driver();
226         if(pkt.power!=driver.get_power())
227                 driver.set_power(pkt.power);
228         if(pkt.halt!=driver.is_halted())
229                 driver.halt(pkt.halt);
230 }
231
232 void Server::Connection::receive(const TrainControlPacket &pkt)
233 {
234         try
235         {
236                 Train &train = server.layout.get_train(pkt.address);
237                 train.set_control(pkt.control, pkt.value);
238         }
239         catch(const exception &e)
240         {
241                 error(e.what());
242         }
243 }
244
245 void Server::Connection::receive(const TrainFunctionPacket &pkt)
246 {
247         try
248         {
249                 Train &train = server.layout.get_train(pkt.address);
250                 for(unsigned i=0; i<9; ++i)
251                         if(((pkt.functions^train.get_functions())>>i)&1)
252                                 train.set_function(i, (pkt.functions>>i)&1);
253         }
254         catch(const exception &e)
255         {
256                 error(e.what());
257         }
258 }
259
260 void Server::Connection::receive(const TrainRoutePacket &pkt)
261 {
262         try
263         {
264                 Train &train = server.layout.get_train(pkt.address);
265                 if(pkt.route.empty())
266                         train.ai_message(TrainAI::Message("clear-route"));
267                 else
268                 {
269                         Route &route = server.layout.get_route(pkt.route);
270                         train.ai_message(TrainAI::Message("set-route", &route));
271                 }
272         }
273         catch(const exception &e)
274         {
275                 error(e.what());
276         }
277 }
278
279 void Server::Connection::error(const string &msg)
280 {
281         ErrorPacket pkt;
282         pkt.message = msg;
283         comm.send(pkt);
284 }
285
286 } // namespace R2C2