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