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