1 /* libobby - Network text editing library
2 * Copyright (C) 2005, 2006 0x539 dev group
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public
15 * License along with this program; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #ifndef _OBBY_HOST_BUFFER_HPP_
20 #define _OBBY_HOST_BUFFER_HPP_
21
22 #include <sigc++/signal.h>
23 #include <net6/host.hpp>
24 #include "command.hpp"
25 #include "host_document_info.hpp"
26 #include "server_buffer.hpp"
27 #include "local_buffer.hpp"
28
29 namespace obby
30 {
31
32 template<typename Document, typename Selector>
33 class basic_host_buffer:
34 virtual public basic_local_buffer<Document, Selector>,
35 virtual public basic_server_buffer<Document, Selector>
36 {
37 public:
38 // Document info
39 typedef typename basic_server_buffer<Document, Selector>::
40 base_document_info_type base_document_info_type;
41
42 typedef basic_host_document_info<Document, Selector>
43 document_info_type;
44
45 // Network
46 typedef typename basic_server_buffer<Document, Selector>::
47 base_net_type base_net_type;
48
49 typedef net6::basic_host<Selector> net_type;
50
51 // TODO: Move this parameters into the open() call. The call would have
52 // to lose its virtualness, but should be better nevertheless.
53
54 /** Creates a new host_buffer.
55 * @param username User name for the local user.
56 * @param colour Local user colour.
57 */
58 basic_host_buffer(const std::string& username,
59 const colour& colour);
60
61 /** Opens the server on the given port.
62 */
63 virtual void open(unsigned int port);
64
65 /** Opens the server on the given port and resumes the obby session
66 * stored in the given file.
67 */
68 virtual void open(const std::string& session, unsigned int port);
69
70 /** Looks for a document with the given ID which belongs to the user
71 * with the given owner ID. Note that we do not take a real user object
72 * here because the ID is enough and one might not have a user object
73 * to the corresponding ID. So a time-consuming lookup is obsolete.
74 */
75 document_info_type* document_find(unsigned int owner_id,
76 unsigned int id) const;
77
78 /** Returns the local user.
79 */
80 virtual const user& get_self() const;
81
82 /** Sends a global message to all users.
83 */
84 virtual void send_message(const std::string& message);
85
86 /** Sends a message to the given user.
87 */
88 virtual void send_message(const std::string& message, const user& to);
89
90 /** @brief Executes a command.
91 */
92 virtual void send_command(const command_query& query);
93
94 /** Creates a new document with predefined content.
95 * signal_insert_document will be emitted and may be used to access
96 * the resulting obby::document.
97 */
98 virtual void document_create(const std::string& title,
99 const std::string& encoding,
100 const std::string& content);
101
102 /** Sets a new colour for the local user.
103 */
104 virtual void set_colour(const colour& colour);
105
106 protected:
107 /** Creates a new document info object according to the type of buffer.
108 */
109 virtual base_document_info_type*
110 new_document_info(const user* owner,
111 unsigned int id,
112 const std::string& title,
113 const std::string& encoding,
114 const std::string& content);
115
116 /** Creates a new document info deserialised from a serialisation
117 * object according to the type of buffer.
118 */
119 virtual base_document_info_type*
120 new_document_info(const serialise::object& obj);
121
122 /** Creates the underlaying net6 network object corresponding to the
123 * buffer's type.
124 */
125 virtual base_net_type* new_net();
126
127 /** @brief Creates the local user after the user table has been
128 * deserialised.
129 */
130 void on_user_table_deserialised();
131
132 /** @brief Closes the session.
133 */
134 virtual void session_close();
135
136 /** @brief Implementation of session_close() that does not call
137 * a base function.
138 */
139 void session_close_impl();
140
141 std::string m_username;
142 colour m_colour;
143
144 const user* m_self;
145 private:
146 /** @brief Common initialisation function called by both constructors
147 * to avoid code duplication.
148 */
149 void init_impl();
150
151 /** This function provides access to the underlaying net6::basic_host
152 * object.
153 */
154 net_type& net6_host();
155
156 /** This function provides access to the underlaying net6::basic_host
157 * object.
158 */
159 const net_type& net6_host() const;
160 };
161
162 typedef basic_host_buffer<obby::document, net6::selector> host_buffer;
163
164 template<typename Document, typename Selector>
165 basic_host_buffer<Document, Selector>::
basic_host_buffer(const std::string & username,const colour & colour)166 basic_host_buffer(const std::string& username,
167 const colour& colour):
168 basic_buffer<Document, Selector>(),
169 basic_local_buffer<Document, Selector>(),
170 basic_server_buffer<Document, Selector>(),
171 m_username(username), m_colour(colour), m_self(NULL)
172 {
173 init_impl();
174 }
175
176 template<typename Document, typename Selector>
open(unsigned int port)177 void basic_host_buffer<Document, Selector>::open(unsigned int port)
178 {
179 // Must NULL m_self here. If server open fails, the user table will
180 // be cleared without having called on_user_table_deserialised
181 // and m_self would refer to nothing anymore.
182 m_self = NULL;
183 basic_server_buffer<Document, Selector>::open(port);
184 on_user_table_deserialised();
185 }
186
187 template<typename Document, typename Selector>
open(const std::string & session,unsigned int port)188 void basic_host_buffer<Document, Selector>::open(const std::string& session,
189 unsigned int port)
190 {
191 m_self = NULL; // (same as above)
192 basic_server_buffer<Document, Selector>::open(session, port);
193 // on_user_table_deserialised() is called automatically by the user
194 // table after all other users have been loaded
195 }
196
197 template<typename Document, typename Selector>
198 typename basic_host_buffer<Document, Selector>::document_info_type*
199 basic_host_buffer<Document, Selector>::
document_find(unsigned int owner_id,unsigned int id) const200 document_find(unsigned int owner_id,
201 unsigned int id) const
202 {
203 return dynamic_cast<document_info_type*>(
204 basic_server_buffer<Document, Selector>::document_find(
205 owner_id,
206 id
207 )
208 );
209 }
210
211 template<typename Document, typename Selector>
get_self() const212 const user& basic_host_buffer<Document, Selector>::get_self() const
213 {
214 if(m_self == NULL)
215 {
216 throw std::logic_error(
217 "obby::host_buffer::get_self:\n"
218 "Local user is not available This probably means that "
219 "the server has never been opened"
220 );
221 }
222
223 return *m_self;
224 }
225
226 template<typename Document, typename Selector>
227 void basic_host_buffer<Document, Selector>::
send_message(const std::string & message)228 send_message(const std::string& message)
229 {
230 if(m_self == NULL)
231 {
232 throw std::logic_error(
233 "obby::host_buffer::send_message:\n"
234 "Local user is not available. This probably means "
235 "that the server has never been opened"
236 );
237 }
238
239 // Send message from local user instead of server
240 basic_server_buffer<Document, Selector>::send_message_impl(
241 message,
242 m_self
243 );
244 }
245
246 template<typename Document, typename Selector>
247 void basic_host_buffer<Document, Selector>::
send_message(const std::string & message,const user & to)248 send_message(const std::string& message, const user& to)
249 {
250 if(m_self == NULL)
251 {
252 throw std::logic_error(
253 "obby::host_buffer::send_message:\n"
254 "Local user is not available. This probably means "
255 "that the server has never been opened"
256 );
257 }
258
259 // Send message from local user instead of server
260 basic_server_buffer<Document, Selector>::send_message_impl(
261 message,
262 m_self,
263 to
264 );
265 }
266
267 template<typename Document, typename Selector>
268 void basic_host_buffer<Document, Selector>::
send_command(const command_query & query)269 send_command(const command_query& query)
270 {
271 if(m_self == NULL)
272 {
273 throw std::logic_error(
274 "obby::host_buffer::send_command:\n"
275 "Local user is not available. This probably means "
276 "that the server has never been opened"
277 );
278 }
279
280 // Execute command locally, report result
281 basic_local_buffer<Document, Selector>::m_command_queue.query(query);
282 command_result result = basic_server_buffer<Document, Selector>::
283 m_command_map.exec_command(*m_self, query);
284 basic_local_buffer<Document, Selector>::m_command_queue.result(result);
285 }
286
287 template<typename Document, typename Selector>
288 void basic_host_buffer<Document, Selector>::
document_create(const std::string & title,const std::string & encoding,const std::string & content)289 document_create(const std::string& title,
290 const std::string& encoding,
291 const std::string& content)
292 {
293 if(m_self == NULL)
294 {
295 throw std::logic_error(
296 "obby::host_buffer::document_create:\n"
297 "Local user is not available This probably means that "
298 "the server has never been opened"
299 );
300 }
301
302 unsigned int id = ++ basic_buffer<Document, Selector>::m_doc_counter;
303
304 // Create document with local user as owner instead of NULL indicating
305 // that it is the server's document.
306 basic_server_buffer<Document, Selector>::document_create_impl(
307 m_self, id, title, encoding, content
308 );
309 }
310
311 template<typename Document, typename Selector>
set_colour(const colour & colour)312 void basic_host_buffer<Document, Selector>::set_colour(const colour& colour)
313 {
314 if(m_self == NULL)
315 {
316 throw std::logic_error(
317 "obby::host_buffer::set_colour:\n"
318 "Local user is not available This probably means that "
319 "the server has never been opened"
320 );
321 }
322
323 // Check for colour conflicts
324 // TODO: user_colour_impl should check this
325 if(!basic_buffer<Document, Selector>::check_colour(colour, m_self))
326 {
327 basic_local_buffer<Document, Selector>::
328 m_signal_user_colour_failed.emit();
329 }
330 else
331 {
332 basic_server_buffer<Document, Selector>::user_colour_impl(
333 *m_self,
334 colour
335 );
336 }
337 }
338
339 template<typename Document, typename Selector>
on_user_table_deserialised()340 void basic_host_buffer<Document, Selector>::on_user_table_deserialised()
341 {
342 // Create user local user
343 m_self = basic_buffer<Document, Selector>::m_user_table.add_user(
344 basic_buffer<Document, Selector>::m_user_table.find_free_id(),
345 net6_host().get_self(),
346 m_colour
347 );
348
349 basic_buffer<Document, Selector>::m_signal_user_join.emit(*m_self);
350 }
351
352 template<typename Document, typename Selector>
session_close()353 void basic_host_buffer<Document, Selector>::session_close()
354 {
355 session_close_impl();
356 basic_local_buffer<Document, Selector>::session_close_impl();
357 basic_buffer<Document, Selector>::session_close_impl();
358 }
359
360 template<typename Document, typename Selector>
session_close_impl()361 void basic_host_buffer<Document, Selector>::session_close_impl()
362 {
363 // Keep self until reopening
364 }
365
366 template<typename Document, typename Selector>
init_impl()367 void basic_host_buffer<Document, Selector>::init_impl()
368 {
369 user_table& table = this->m_user_table;
370 table.deserialised_event().connect(
371 sigc::mem_fun(
372 *this,
373 &basic_host_buffer::on_user_table_deserialised
374 )
375 );
376 }
377
378 template<typename Document, typename Selector>
379 typename basic_host_buffer<Document, Selector>::base_document_info_type*
380 basic_host_buffer<Document, Selector>::
new_document_info(const user * owner,unsigned int id,const std::string & title,const std::string & encoding,const std::string & content)381 new_document_info(const user* owner,
382 unsigned int id,
383 const std::string& title,
384 const std::string& encoding,
385 const std::string& content)
386 {
387 // Create host_document_info, according to host_buffer
388 return new document_info_type(
389 *this,
390 net6_host(),
391 owner,
392 id,
393 title,
394 encoding,
395 content
396 );
397 }
398
399 template<typename Document, typename Selector>
400 typename basic_host_buffer<Document, Selector>::base_document_info_type*
401 basic_host_buffer<Document, Selector>::
new_document_info(const serialise::object & obj)402 new_document_info(const serialise::object& obj)
403 {
404 // Create host_document_info, according to host_buffer
405 return new document_info_type(*this, net6_host(), obj);
406 }
407
408 template<typename Document, typename Selector>
409 typename basic_host_buffer<Document, Selector>::base_net_type*
new_net()410 basic_host_buffer<Document, Selector>::new_net()
411 {
412 return new net_type(m_username);
413 }
414
415 template<typename Document, typename Selector>
416 typename basic_host_buffer<Document, Selector>::net_type&
net6_host()417 basic_host_buffer<Document, Selector>::net6_host()
418 {
419 return dynamic_cast<net_type&>(
420 *basic_buffer<Document, Selector>::m_net
421 );
422 }
423
424 template<typename Document, typename Selector>
425 const typename basic_host_buffer<Document, Selector>::net_type&
net6_host() const426 basic_host_buffer<Document, Selector>::net6_host() const
427 {
428 return dynamic_cast<const net_type&>(
429 *basic_buffer<Document, Selector>::m_net
430 );
431 }
432
433 } // namespace obby
434
435 #endif // _OBBY_HOST_BUFFER_HPP_
436