diff options
| author | Bent Bisballe Nyeng <deva@aasimon.org> | 2020-07-04 16:58:08 +0200 | 
|---|---|---|
| committer | Bent Bisballe Nyeng <deva@aasimon.org> | 2020-07-04 17:03:52 +0200 | 
| commit | 8db5ff97ffe34aa42f71b5c8aebfa0878e5fde89 (patch) | |
| tree | 7d5a196d8dd34621bbdb4b80cd4b78d96ecfeb05 | |
| parent | d21701afe4230d633ae685ffeee6f5fb5a76f34d (diff) | |
Add error message support and reporting on all commands.
| -rw-r--r-- | src/Makefile.am | 2 | ||||
| -rw-r--r-- | src/errorcodes.h | 44 | ||||
| -rw-r--r-- | src/exceptions.h | 106 | ||||
| -rw-r--r-- | src/message.h | 9 | ||||
| -rw-r--r-- | src/messagehandler.cc | 79 | ||||
| -rw-r--r-- | src/messageparser.cc | 119 | ||||
| -rw-r--r-- | src/messageparser.h | 20 | ||||
| -rw-r--r-- | src/munia_proto.cc | 60 | ||||
| -rw-r--r-- | src/nodemanager.cc | 297 | ||||
| -rw-r--r-- | src/nodemanager.h | 172 | ||||
| -rw-r--r-- | src/nodetree.cc | 266 | ||||
| -rw-r--r-- | src/nodetree.h | 49 | 
12 files changed, 600 insertions, 623 deletions
| diff --git a/src/Makefile.am b/src/Makefile.am index d70301c..c8a6560 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -31,6 +31,8 @@ muniacli_SOURCES = \  EXTRA_DIST = \  	connectionhandler.h \ +	errorcodes.h \ +	exceptions.h \  	http.h \  	message.h \  	messageparser.h \ diff --git a/src/errorcodes.h b/src/errorcodes.h new file mode 100644 index 0000000..e305441 --- /dev/null +++ b/src/errorcodes.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + *            errorcodes.h + * + *  Fri Jul  3 13:19:18 CEST 2020 + *  Copyright 2020 Bent Bisballe Nyeng + *  deva@aasimon.org + ****************************************************************************/ + +/* + *  This file is part of Munia. + * + *  Munia is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  Munia is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with Munia; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. + */ +#pragma once + +enum class ErrorCode +{ +	Ok                     =  0, +	LoginFailed            =  1, +	Unauthorized           =  2, +	MissingParent          =  4, // create +	NoSuchId               =  6, // create  remove +	IdAlreadyExists        =  7, // create +	ProtectedNode          =  8, //         remove +	NewParentIsSelf        =  9, // move +	NewParentIsChildOfSelf = 10, // move +	WrongNumberOfArguments = 11, +	System                 = 41, +	Unknown                = 42, +}; diff --git a/src/exceptions.h b/src/exceptions.h new file mode 100644 index 0000000..79f1113 --- /dev/null +++ b/src/exceptions.h @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + *            exceptions.h + * + *  Fri Jul  3 13:36:49 CEST 2020 + *  Copyright 2020 Bent Bisballe Nyeng + *  deva@aasimon.org + ****************************************************************************/ + +/* + *  This file is part of Munia. + * + *  Munia is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  Munia is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with Munia; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. + */ +#pragma once + +#include "message.h" +#include "errorcodes.h" + +namespace Error +{ + +struct MissingParent +	: public ErrorMessage +{ +	MissingParent() +	{ +		code = ErrorCode::MissingParent; +		msg = "Parent node does not exist."; +	} +}; + +struct NoSuchId +	: public ErrorMessage +{ +	NoSuchId() +	{ +		code = ErrorCode::NoSuchId; +		msg = "Node does not exist."; +	} +}; + +struct IdAlreadyExists +	: public ErrorMessage +{ +	IdAlreadyExists() +	{ +		code = ErrorCode::IdAlreadyExists; +		msg = "Id already exists."; +	} +}; + +struct ProtectedNode +	: public ErrorMessage +{ +	ProtectedNode() +	{ +		code = ErrorCode::ProtectedNode; +		msg = "Node is protected."; +	} +}; + +struct NewParentIsSelf +	: public ErrorMessage +{ +	NewParentIsSelf() +	{ +		code = ErrorCode::NewParentIsSelf; +		msg = "New parent is the node itself."; +	} +}; +struct NewParentIsChildOfSelf +	: public ErrorMessage +{ +	NewParentIsChildOfSelf() +	{ +		code = ErrorCode::NewParentIsChildOfSelf; +		msg = "New parent is a child of node itself."; +	} +}; + +struct System +	: public ErrorMessage +{ +	System(const char* message) +	{ +		code = ErrorCode::System; +		msg = "Unknown error occurred: "; +		msg += message; +	} +}; + +} // ::Error diff --git a/src/message.h b/src/message.h index 3a6afdc..8d2d12f 100644 --- a/src/message.h +++ b/src/message.h @@ -32,6 +32,7 @@  #include <vector>  #include "node.h" +#include "errorcodes.h"  enum class cmd  { @@ -99,6 +100,13 @@ struct update_t  	std::string value;  }; +struct ErrorMessage +{ +	ErrorCode code; +	std::string msg; +	struct lws* wsi; +}; +  struct message_t  {  	cmd_t cmd; @@ -111,6 +119,7 @@ struct message_t  	remove_t remove;  	move_t move;  	update_t update; +	ErrorMessage error;  	NodeIdList nodes; diff --git a/src/messagehandler.cc b/src/messagehandler.cc index 9a00e46..d20c963 100644 --- a/src/messagehandler.cc +++ b/src/messagehandler.cc @@ -34,6 +34,8 @@  #include "messageparser.h" +#include "errorcodes.h" +  MessageList handle_msg(MessageList msgList, clientid_t wsi)  { @@ -47,11 +49,19 @@ MessageList handle_msg(MessageList msgList, clientid_t wsi)  		if(m.cmd == cmd::login)  		{  			connection_handler.login(wsi, m.login.user, m.login.password); +			if(!connection_handler.authenticated(wsi)) +			{ +				outmsgs.push_back(create_msg_error(ErrorCode::LoginFailed, +				                                   "Bad username or password.", wsi)); +				continue; +			}  		}  		// If client is not authenticated; do not continue beyond this point...  		if(!connection_handler.authenticated(wsi))  		{ +			outmsgs.push_back(create_msg_error(ErrorCode::Unauthorized, +			                                   "Not authorized.", wsi));  			continue;  		} @@ -59,12 +69,19 @@ MessageList handle_msg(MessageList msgList, clientid_t wsi)  		{  		case cmd::login:  			// Already handled, before this switch ... case +			INFO(messagehandler, "Handling login command\n");  			break;  		case cmd::logout: +			INFO(messagehandler, "Handling logout command\n");  			connection_handler.logout(wsi);  			break; +		case cmd::create_with_attributes: +			// Never sent to the server +			INFO(messagehandler, "Handling create_with_attributes command\n"); +			break; +  		case cmd::create:  			{  				INFO(messagehandler, "Handling create command\n"); @@ -74,9 +91,15 @@ MessageList handle_msg(MessageList msgList, clientid_t wsi)  					                                  m.create.insertbeforeid);  					outmsgs.push_back(m);  				} -				catch (std::exception& e) +				catch (const ErrorMessage& e)  				{ -					DEBUG(messagehandler, "Error creating node\n"); +					// Set client id (wsi) and forward upstream +					outmsgs.push_back(create_msg_error(e, wsi)); +				} +				catch (...) +				{ +					outmsgs.push_back(create_msg_error(ErrorCode::Unknown, +					                                   "Unknown create error", wsi));  				}  			}  			break; @@ -99,9 +122,15 @@ MessageList handle_msg(MessageList msgList, clientid_t wsi)  						id++;  					}  				} -				catch (std::exception& e) +				catch (const ErrorMessage& e) +				{ +					// Set client id (wsi) and forward upstream +					outmsgs.push_back(create_msg_error(e, wsi)); +				} +				catch (...)  				{ -					DEBUG(messagehandler, "Error remove node\n"); +					outmsgs.push_back(create_msg_error(ErrorCode::Unknown, +					                                   "Unknown remove error", wsi));  				}  			}  			break; @@ -113,7 +142,8 @@ MessageList handle_msg(MessageList msgList, clientid_t wsi)  				{  					node_t removenode = node_manager.node(m.move.id);  					NodeIdListPair tilpair = -						node_manager.moveNode(m.move.id, m.move.parentid, m.move.insertbeforeid); +						node_manager.moveNode(m.move.id, m.move.parentid, +						                      m.move.insertbeforeid);  					node_t createnode = node_manager.node(m.move.id);  					message_t removemsg = create_msg_remove(removenode); @@ -143,24 +173,27 @@ MessageList handle_msg(MessageList msgList, clientid_t wsi)  					outmsgs.push_back(removemsg);  					outmsgs.push_back(createmsg);  				} -				catch (std::exception& e) +				catch (const ErrorMessage& e)  				{ -					DEBUG(messagehandler, "Error moving node\n"); +					// Set client id (wsi) and forward upstream +					outmsgs.push_back(create_msg_error(e, wsi)); +				} +				catch (...) +				{ +					outmsgs.push_back(create_msg_error(ErrorCode::Unknown, +					                                   "Unknown move error", wsi));  				}  			}  			break;  		case cmd::subscribe: -			{ -				//connection_handler.subscribe(wsi, m.subscribe.id); -				outmsgs.push_back(m); -			} +			INFO(messagehandler, "Handling subscribe command\n"); +			outmsgs.push_back(m);  			break;  		case cmd::unsubscribe: -			//connection_handler.unsubscribe(wsi, m.subscribe.id); +			INFO(messagehandler, "Handling unsubscribe command\n");  			outmsgs.push_back(m); -			DEBUG(handler, "unsubscribe: %d\n", (int)m.unsubscribe.id);  			break;  		case cmd::update: @@ -173,24 +206,24 @@ MessageList handle_msg(MessageList msgList, clientid_t wsi)  					                                  m.update.value);  					outmsgs.push_back(m);  				} -				catch (std::exception& e) +				catch (const ErrorMessage& e)  				{ -					DEBUG(messagehandler, "Error updating node\n"); +					// Set client id (wsi) and forward upstream +					outmsgs.push_back(create_msg_error(e, wsi)); +				} +				catch (...) +				{ +					outmsgs.push_back(create_msg_error(ErrorCode::Unknown, +					                                   "Unknown update error", wsi));  				}  			}  			break;  		case cmd::error: -			ERR(messagehandler, "An error occurred.\n"); -			break; - -		default: -			WARN(messagehandler, "!!! Unknown command %d\n", m.cmd); +			INFO(messagehandler, "Handling error command\n"); +			outmsgs.push_back(m); // Just forward the error message  			break;  		} -		node_manager.tree.toStdOut(); -		DEBUG(messagehandler, "%d affected nodes registered\n", -		      (int)m.nodes.size());  	}  	return outmsgs; diff --git a/src/messageparser.cc b/src/messageparser.cc index 7393c5c..b0a2a6f 100644 --- a/src/messageparser.cc +++ b/src/messageparser.cc @@ -30,6 +30,7 @@  #include <list>  #include <vector>  #include <map> +#include <cassert>  #include <hugin.hpp> @@ -156,7 +157,8 @@ static nodeid_t getId(std::map<std::string, nodeid_t> &sym, std::string token)  inline static void create_msg_list(MsgTokensList& msgTokensList,                                     MessageList& msgList, -                                   bool clientmode) +                                   bool clientmode, +                                   struct lws* wsi)  {  	size_t origin = 0;  	if(clientmode) @@ -174,6 +176,8 @@ inline static void create_msg_list(MsgTokensList& msgTokensList,  		//malformed msg  		if(t.size() < origin+1)  		{ +			msgList.push_back(create_msg_error(ErrorCode::Unknown, +			                                   "malformed message", wsi));  			continue;  		} @@ -192,7 +196,13 @@ inline static void create_msg_list(MsgTokensList& msgTokensList,  		else if(t[origin] == "remove") m.cmd = cmd::remove;  		else if(t[origin] == "move") m.cmd = cmd::move;  		else if(t[origin] == "update") m.cmd = cmd::update; -		else m.cmd = cmd::error; +		else if(t[origin] == "error") m.cmd = cmd::error; +		else +		{ +			msgList.push_back(create_msg_error(ErrorCode::Unknown, +			                                   "unknown command", wsi)); +			continue; +		}  		switch(m.cmd)  		{ @@ -200,7 +210,9 @@ inline static void create_msg_list(MsgTokensList& msgTokensList,  			{  				if(t.size() != origin+1+1)  				{ -					DEBUG(msgparser, "Wrong number of parameters\n"); +					msgList.push_back( +						create_msg_error(ErrorCode::WrongNumberOfArguments, +						                 "Wrong number of arguments.", wsi));  					continue;  				}  				m.subscribe.id = getId(sym, t[origin+1]); @@ -211,7 +223,9 @@ inline static void create_msg_list(MsgTokensList& msgTokensList,  			{  				if(t.size() != origin+1+1)  				{ -					DEBUG(msgparser, "Wrong number of parameters\n"); +					msgList.push_back( +						create_msg_error(ErrorCode::WrongNumberOfArguments, +						                 "Wrong number of arguments.", wsi));  					continue;  				}  				m.unsubscribe.id = getId(sym, t[origin+1]); @@ -223,7 +237,9 @@ inline static void create_msg_list(MsgTokensList& msgTokensList,  			{  				if(t.size() != origin+1+2)  				{ -					DEBUG(msgparser, "Wrong number of parameters\n"); +					msgList.push_back( +						create_msg_error(ErrorCode::WrongNumberOfArguments, +						                 "Wrong number of arguments.", wsi));  					continue;  				}  				m.login.user = t[origin+1]; @@ -235,23 +251,27 @@ inline static void create_msg_list(MsgTokensList& msgTokensList,  		case cmd::logout:  			if(t.size() != origin+1)  			{ -				DEBUG(msgparser, "Wrong number of parameters\n"); +				msgList.push_back( +					create_msg_error(ErrorCode::WrongNumberOfArguments, +					                 "Wrong number of arguments.", wsi));  				continue;  			}  			break; +		case cmd::create_with_attributes: +			// Never sent to the server +			break; +  		case cmd::create:  			{ -				if(!clientmode && t.size() != origin+1+2+1) +				if(t.size() != origin+1+2+1)  				{ -					DEBUG(msgparser, "Wrong number of parameters\n"); -					continue; -				} -				if(clientmode && t.size() != origin+1+2+1) -				{ -					DEBUG(msgparser, "Wrong number of parameters\n"); +					msgList.push_back( +						create_msg_error(ErrorCode::WrongNumberOfArguments, +						                 "Wrong number of arguments.", wsi));  					continue;  				} +  				if(clientmode)  				{  					m.create.id = getId(sym, t[origin+1]); @@ -264,23 +284,29 @@ inline static void create_msg_list(MsgTokensList& msgTokensList,  					m.create.parentid = getId(sym, t[origin+2]);  					m.create.insertbeforeid = getId(sym, t[origin+3]);  				} -				break;  			} +			break; +  		case cmd::remove:  			{  				if(t.size() != origin+1+1)  				{ -					DEBUG(msgparser, "Wrong number of parameters\n"); +					msgList.push_back( +						create_msg_error(ErrorCode::WrongNumberOfArguments, +						                 "Wrong number of arguments.", wsi));  					continue;  				}  				m.remove.id = getId(sym, t[origin+1]);  			}  			break; +  		case cmd::move:  			{  				if(t.size() != origin+2+1+1)  				{ -					DEBUG(msgparser, "Wrong number of parameters\n"); +					msgList.push_back( +						create_msg_error(ErrorCode::WrongNumberOfArguments, +						                 "Wrong number of arguments.", wsi));  					continue;  				}  				m.move.id = getId(sym, t[origin+1]); @@ -288,11 +314,14 @@ inline static void create_msg_list(MsgTokensList& msgTokensList,  				m.move.insertbeforeid = getId(sym, t[origin+3]);  			}  			break; +  		case cmd::update:  			{  				if(t.size() != origin+3+1)  				{ -					DEBUG(msgparser, "Wrong number of parameters\n"); +					msgList.push_back( +						create_msg_error(ErrorCode::WrongNumberOfArguments, +						                 "Wrong number of arguments.", wsi));  					continue;  				}  				m.update.id = getId(sym, t[origin+1]); @@ -300,14 +329,27 @@ inline static void create_msg_list(MsgTokensList& msgTokensList,  				m.update.value = t[origin+3];  			}  			break; -		default: + +		case cmd::error: +			{ +				if(t.size() != origin+2+1) +				{ +					msgList.push_back( +						create_msg_error(ErrorCode::WrongNumberOfArguments, +						                 "Wrong number of arguments.", wsi)); +					continue; +				} +				m.error.code = static_cast<ErrorCode>(atoi(t[origin+1].data())); +				m.error.msg = t[origin+2]; +			}  			break;  		}; +  		msgList.push_back(m);  	}  } -MessageList parse_msg(std::string data) +MessageList parse_msg(std::string data, struct lws* wsi)  {  	DEBUG(msgparser, "Parsing: '%s'\n", data.c_str()); @@ -315,19 +357,19 @@ MessageList parse_msg(std::string data)  	parse_into_msg_tokens(data, msgTokensList);  	MessageList msgList; -	create_msg_list(msgTokensList, msgList, false); +	create_msg_list(msgTokensList, msgList, false, wsi);  	return msgList;  } -MessageList parse_msg_client(std::string data) +MessageList parse_msg_client(std::string data, struct lws* wsi)  {  	DEBUG(msgparser, "Parsing: '%s'\n", data.c_str());  	MsgTokensList msgTokensList;  	parse_into_msg_tokens(data, msgTokensList);  	MessageList msgList; -	create_msg_list(msgTokensList, msgList, true); +	create_msg_list(msgTokensList, msgList, true, wsi);  	return msgList;  } @@ -392,7 +434,18 @@ std::vector<std::string> msg_tostring(message_t m)  			m.update.attribute + "\" \"" + m.update.value + "\";";  		msgs.push_back(msg);  		break; -	default: +	case cmd::error: +		msg = "error " + +			std::to_string(static_cast<int>(m.error.code)) + " \"" + +			m.error.msg + "\";"; +		msgs.push_back(msg); +		break; +	case cmd::login: +	case cmd::logout: +	case cmd::subscribe: +	case cmd::unsubscribe: +		assert(false); +		// The server never sends these messages so no need to serialise them.  		break;  	} @@ -444,3 +497,23 @@ message_t create_msg_move(nodeid_t id, nodeid_t to, nodeid_t insertbeforeid)  	m.move.insertbeforeid = insertbeforeid;  	return m;  } + +message_t create_msg_error(ErrorCode code, const std::string &msg, +                           struct lws* wsi) +{ +	message_t m; +	m.cmd = cmd::error; +	m.error.wsi = wsi; +	m.error.code = code; +	m.error.msg = msg; +	return m; +} + +message_t create_msg_error(const ErrorMessage &error, struct lws* wsi) +{ +	message_t m; +	m.cmd = cmd::error; +	m.error = error; +	m.error.wsi = wsi; +	return m; +} diff --git a/src/messageparser.h b/src/messageparser.h index 218f3a8..030c77b 100644 --- a/src/messageparser.h +++ b/src/messageparser.h @@ -27,13 +27,13 @@   */  #pragma once -#include "message.h" -  #include <string>  #include <vector> -MessageList parse_msg(std::string msg); -MessageList parse_msg_client(std::string msg); +#include "message.h" + +MessageList parse_msg(std::string msg, struct lws* wsi); +MessageList parse_msg_client(std::string msg, struct lws* wsi);  //message_t create_msg(cmd::cmd_t type, node_t node); @@ -52,3 +52,15 @@ message_t create_msg_create_with_attributes(node_t node,  message_t create_msg_update(node_t node, const std::string &attr);  message_t create_msg_remove(node_t node);  message_t create_msg_move(nodeid_t id, nodeid_t to, nodeid_t insertbeforeid); + +//! Create new error message. +//! \param code is the ErrorCode for this error message. +//! \param msg is the error in textural form for easy presentation on the +//!  clients. +//! \param wsi is the client id that the error relates to (usually the one +//!  that sent the command resulting in the error) +message_t create_msg_error(ErrorCode code, const std::string &msg, +                           struct lws* wsi); + +//! Convenience function. +message_t create_msg_error(const ErrorMessage &error, struct lws* wsi); diff --git a/src/munia_proto.cc b/src/munia_proto.cc index 0508f9f..f0ec5be 100644 --- a/src/munia_proto.cc +++ b/src/munia_proto.cc @@ -98,8 +98,6 @@ int callback_lws_node(struct lws *wsi,                        enum lws_callback_reasons reason,                        void *user, void *in, size_t len)  { -	node_manager.tree.toStdOut(); -  	DEBUG(proto, "Callback on %p\n", wsi);  	switch (reason) @@ -119,7 +117,8 @@ int callback_lws_node(struct lws *wsi,  			// the position of the remove msg.  			//  			msgqueue_t::iterator i = msgqueue[wsi].begin(); -			while(i != msgqueue[wsi].end()) { +			while(i != msgqueue[wsi].end()) +			{  				message_t &msg = *i;  				if(msg.cmd == cmd::remove)  				{ @@ -168,10 +167,21 @@ int callback_lws_node(struct lws *wsi,  					{  						msgstr += " ";  					} -					auto msgs = msg_tostring(msg); -					for(const auto& msg_string : msgs) +					if(msg.cmd == cmd::error) +					{ +						auto msgs = msg_tostring(msg); +						for(const auto& msg_string : msgs) +						{ +							msgstr += msg_string; +						} +					} +					else  					{ -						msgstr += std::to_string(msg.tid) + " " + msg_string; +						auto msgs = msg_tostring(msg); +						for(const auto& msg_string : msgs) +						{ +							msgstr += std::to_string(msg.tid) + " " + msg_string; +						}  					}  				} @@ -216,7 +226,7 @@ int callback_lws_node(struct lws *wsi,  			std::string data;  			data.append((char*)in, len); -			MessageList mlst = parse_msg(data); +			MessageList mlst = parse_msg(data, wsi);  			DEBUG(proto, "Handling %d incoming message\n", (int)mlst.size());  			MessageList omsgs = handle_msg(mlst, wsi);  			DEBUG(proto, "Handling %d outgoing messages\n", (int)omsgs.size()); @@ -224,21 +234,31 @@ int callback_lws_node(struct lws *wsi,  			MessageList::iterator omi = omsgs.begin();  			while(omi != omsgs.end())  			{ -				DEBUG(proto, "Message\n"); +				DEBUG(proto, "Message %d\n", (int)omi->cmd);  				if(omi->cmd == cmd::subscribe)  				{ -					connection_handler.subscribe(wsi, omi->subscribe.id);  					NodeIdList ids;  					try  					{  						ids = node_manager.subNodes(omi->subscribe.id); +						connection_handler.subscribe(wsi, omi->subscribe.id); +					} +					catch (const ErrorMessage& e) +					{ +						// Set client id (wsi) and forward upstream +						msgqueue[wsi].push_back(create_msg_error(e, wsi)); +						omi++; +						continue;  					} -					catch(...) +					catch (...)  					{ -						DEBUG(proto, "No such node %d\n", (int)omi->subscribe.id); +						msgqueue[wsi].push_back( +							create_msg_error(ErrorCode::Unknown, +							                 "Unknown subscribe error", wsi));  						omi++;  						continue;  					} +  					NodeIdList::iterator id = ids.begin();  					while(id != ids.end())  					{ @@ -282,12 +302,22 @@ int callback_lws_node(struct lws *wsi,  					{  						ids = node_manager.subNodes(omi->unsubscribe.id);  					} -					catch(...) +					catch (const ErrorMessage& e) +					{ +						// Set client id (wsi) and forward upstream +						msgqueue[wsi].push_back(create_msg_error(e, wsi)); +						omi++; +						continue; +					} +					catch (...)  					{ -						DEBUG(proto, "No such node %d\n", (int)omi->unsubscribe.id); +						msgqueue[wsi].push_back( +							create_msg_error(ErrorCode::Unknown, +							                 "Unknown subscribe error", wsi));  						omi++;  						continue;  					} +  					NodeIdList::reverse_iterator id = ids.rbegin();  					while(id != ids.rend())  					{ @@ -302,6 +332,10 @@ int callback_lws_node(struct lws *wsi,  					}  				} +				else if(omi->cmd == cmd::error) +				{ +					msgqueue[omi->error.wsi].push_back(*omi); +				}  				else  				{  					DEBUG(proto, "%d nodes affected by command\n", diff --git a/src/nodemanager.cc b/src/nodemanager.cc index e94c798..e10b64d 100644 --- a/src/nodemanager.cc +++ b/src/nodemanager.cc @@ -27,10 +27,10 @@   */  #include "nodemanager.h" -#include <stdio.h> -  #include "hugin.hpp" +#include "exceptions.h" +  // Global NodeManager object.  NodeManager node_manager; @@ -41,21 +41,15 @@ NodeManager node_manager;  #define PROJECTS_ID 4  #define FIRST_NODE_ID 10 -static bool isProtected(nodeid_t id) -{ -	return id < FIRST_NODE_ID; -} -  NodeManager::NodeManager()  { -	idCount = FIRST_NODE_ID;  }  NodeManager::~NodeManager()  {  } -void NodeManager::init(std::string filename) +void NodeManager::init(const std::string& filename)  {  	DEBUG(nodemgr, "Reading nodes from file: %s\n", filename.c_str());  	file = filename; @@ -103,182 +97,93 @@ void NodeManager::init(std::string filename)  	tree.toStdOut();  } -node_t NodeManager::node(nodeid_t t) -{ -	return tree.data(t); -} - -nodeid_t NodeManager::createId() -{ -	return tree.createId(); -} - -bool NodeManager::hasId(nodeid_t id) +NodeIdList NodeManager::createNode(nodeid_t parentid, nodeid_t id, +                                   nodeid_t insertbeforeid)  { -	return tree.hasId(id); -} - -NodeIdListPair NodeManager::moveNode(nodeid_t id, nodeid_t to, nodeid_t beforeId) -	throw (std::exception) -{ -	if(isProtected(id)) -	{ -		return NodeIdListPair(); -	} - -	if(id == to) -	{ -		throw std::exception(); // Node and new parent are the same node. -	} - -	//node_t t = tree.data(id); - -	// Make sure the new parent exists. This will throw an exception if it doesn't -	//node_t t_ = tree.data(to); - -	//t.parentid = to; - -	//NodeIdList tilremove = tree.remove(id); -	NodeIdList tilremove; -	tilremove.push_back(id); -	NodeIdList ancestors = tree.ancestorList(id); -	tilremove.insert(tilremove.end(), ancestors.begin(), ancestors.end()); - -	//  NodeIdList tilcreate = tree.insertAsChild(to, id, t); -	NodeIdList tilcreate; -	tilcreate.push_back(to); -	ancestors = tree.ancestorList(to); -	tilcreate.insert(tilcreate.end(), ancestors.begin(), ancestors.end()); - -	tree.move(id, to, beforeId); +	NodeIdList affectedNodes; -	NodeIdListPair tilpair; -	tilpair.first = tilremove; -	tilpair.second = tilcreate; +	node_t t; +	t.attributes["title"] = ""; +	t.id = id; +	affectedNodes = tree.insertAsChild(parentid, id, t, insertbeforeid);  	flushNodes(); -	return tilpair; +	return affectedNodes;  } -NodeIdList NodeManager::removeNode(nodeid_t id) -	throw (std::exception) +NodeIdList NodeManager::updateNode(nodeid_t id, const std::string &name, +                                   const std::string &value)  {  	if(isProtected(id))  	{ -		return NodeIdList(); +		throw Error::ProtectedNode();  	}  	NodeIdList affectedNodes; -	if(tree.bfs(id).size() > 1) -	{ -		throw std::exception(); -	} - -	try -	{ -		affectedNodes = tree.remove(id); -	} -	catch(std::exception& e) -	{ -		throw e; -	} +	affectedNodes = tree.updateData(id, name, value);  	flushNodes();  	return affectedNodes;  } -NodeIdList NodeManager::updateNode(nodeid_t id, const std::string &name, -                                   const std::string &value) -	throw (std::exception) +NodeIdList NodeManager::removeNode(nodeid_t id)  {  	if(isProtected(id))  	{ -		return NodeIdList(); +		throw Error::ProtectedNode();  	}  	NodeIdList affectedNodes; - -	try -	{ -		affectedNodes = tree.updateData(id, name, value); -	} -	catch(std::exception& e) -	{ -		throw e; -	} - +	affectedNodes = tree.remove(id);  	flushNodes();  	return affectedNodes;  } -NodeIdList NodeManager::createNode(nodeid_t parentid, nodeid_t id, nodeid_t insertbeforeid) -	throw (std::exception) +NodeIdListPair NodeManager::moveNode(nodeid_t id, nodeid_t to, +                                     nodeid_t beforeId)  { -	if(hasId(id)) +	if(isProtected(id))  	{ -		// Id alerady in tree, ignore -		return {}; +		throw Error::ProtectedNode();  	} -	NodeIdList affectedNodes; +	NodeIdList tilremove; +	tilremove.push_back(id); +	NodeIdList ancestors = tree.ancestorList(id); +	tilremove.insert(tilremove.end(), ancestors.begin(), ancestors.end()); -	node_t t; -	t.attributes["title"] = ""; -	t.id = id; +	NodeIdList tilcreate; +	tilcreate.push_back(to); +	ancestors = tree.ancestorList(to); +	tilcreate.insert(tilcreate.end(), ancestors.begin(), ancestors.end()); -	try -	{ -		affectedNodes = tree.insertAsChild(parentid, id, t, insertbeforeid); -	} -	catch(std::exception& e) -	{ -		throw e; -	} +	tree.move(id, to, beforeId); // TODO: Use node list pair from return value  	flushNodes(); -	return affectedNodes; +	return {tilremove, tilcreate};  }  NodeIdList NodeManager::subNodes(nodeid_t t) -	throw (std::exception)  {  	NodeIdList affectedNodes; - -	try -	{ -		affectedNodes = tree.bfs(t); -	} -	catch(std::exception& e) -	{ -		throw e; -	} - +	affectedNodes = tree.bfs(t);  	return affectedNodes;  } -//NodeIdList NodeManager::ancestorList(nodeid_t id) -//	throw (std::exception) -//{ -//	NodeIdList ancestors; -// -//	try -//	{ -//		ancestors = tree.ancestorList(id); -//		goto finish; -//	} -//	catch(std::exception& e) -//	{ -//		throw e; -//	} -// -//finish: -//	return ancestors; -//} +node_t NodeManager::node(nodeid_t t) +{ +	return tree.data(t); +} + +nodeid_t NodeManager::createId() +{ +	return tree.createId(); +}  void NodeManager::flushNodes()  { @@ -292,122 +197,12 @@ void NodeManager::flushNodes()  	fclose(fp);  } -#if 0 -NodeList nodelist; - -node_t create_node(std::string title, std::string desc) -{ -	node_t t; -	t.parent_id = current_id_count(); -	t.attributes["title"] = title; -	t.desc = desc; -	t.id = id_count; id_count++; - -	return t; -} - -NodeList load_nodelist_from_file(std::string file) -{ -	NodeList list; - -	// create MuniaDb class which handles nodes, db-flush and db-init. - -	return list; -} - -bool save_nodelist_to_file(NodeList list, std::string file) -{ -	FILE* fp; - -	if(! (fp = fopen(file.c_str(), "w"))) -	{ -		return false; -	} - -	if(!fprintf(fp, "<nodelist>\n")) -	{ -		fclose(fp); -		return false; -	} - -	NodeList::iterator it; -	for(it = nodelist.begin(); it != nodelist.end(); it++) -	{ -		node_t t = *it; -		int r = 1; - -		//printf("Flushing node %d\n", t.id); -		r |= fprintf(fp, "  <node id=\"%d\" parent_id=\"%d\">\n", t.id, t.parent_id); -		r |= fprintf(fp, "    <title>%s</title>\n", xml_encode(t.attributes["title"]).c_str()); -		r |= fprintf(fp, "    <desc>%s</desc>\n", xml_encode(t.attributes["description"]).c_str()); -		r |= fprintf(fp, "  </node>)\n"); - -		if(!r) -		{ -			fclose(fp); -			return false; -		} -	} - -	if(!fprintf(fp, "</nodelist>\n")) -	{ -		fclose(fp); -		return false; -	} - -	fclose(fp); -	return true; -} - -static void delete_node(node_t t, NodeList& graveyard); - -static void delete_children(node_t t, NodeList& graveyard) -{ -	NodeList::iterator it; -	for(it = nodelist.begin(); it != nodelist.end(); it++) -	{ -		if(it->parent_id == t.id) { -			delete_node(*it, graveyard); -		} -	} -} - -static void delete_node(node_t t, NodeList& graveyard) +bool NodeManager::hasId(nodeid_t id)  { -	NodeList::iterator it; -	for(it = nodelist.begin(); it != nodelist.end(); it++) -	{ -		if(it->id == t.id) -		{ -			break; -		} -	} - -	if(it != nodelist.end()) -	{ -		graveyard.push_back(*it); -		delete_children(*it, graveyard); -	} +	return tree.hasId(id);  } -void delete_node(int id, NodeList& graveyard) +bool NodeManager::isProtected(nodeid_t id) const  { -	node_t t; -	t.id = id; -	delete_node(t, graveyard); - -	for(NodeList::iterator it = graveyard.begin(); -	    it != graveyard.end(); it++) -	{ -		for(NodeList::iterator it_tl = nodelist.begin(); -		    it_tl != nodelist.end(); it_tl++) -		{ -			if(it_tl->id == it->id) -			{ -				nodelist.erase(it_tl); -				break; -			} -		} -	} +	return id < FIRST_NODE_ID;  } -#endif diff --git a/src/nodemanager.h b/src/nodemanager.h index 85b7955..8909eb1 100644 --- a/src/nodemanager.h +++ b/src/nodemanager.h @@ -27,10 +27,8 @@   */  #pragma once -#include <list>  #include <string> -#include <stdio.h> -#include <exception> +#include <utility>  #include "node.h"  #include "nodetree.h" @@ -43,173 +41,31 @@ public:  	NodeManager();  	~NodeManager(); -	void init(std::string filename); +	void init(const std::string& filename); -	NodeIdList createNode(nodeid_t parentid, nodeid_t id, nodeid_t insertbeforeid) throw (std::exception); -	NodeIdList updateNode(nodeid_t id, const std::string &name, -	                      const std::string &value) throw (std::exception); -	NodeIdList removeNode(nodeid_t id) throw (std::exception); +	NodeIdList createNode(nodeid_t parentid, nodeid_t id, +	                      nodeid_t insertbeforeid); -	NodeIdListPair moveNode(nodeid_t id, nodeid_t newParent, nodeid_t beforeId) throw (std::exception); +	NodeIdList updateNode(nodeid_t id, const std::string& name, +	                      const std::string& value); -	NodeIdList subNodes(nodeid_t) throw (std::exception); +	NodeIdList removeNode(nodeid_t id); -	NodeTree tree; +	NodeIdListPair moveNode(nodeid_t id, nodeid_t newParent, nodeid_t beforeId); -	node_t node(nodeid_t t); +	NodeIdList subNodes(nodeid_t id); -	void flushNodes(); +	node_t node(nodeid_t t);  	nodeid_t createId(); -	bool hasId(nodeid_t id);  private: -	//  NodeIdList ancestorList(nodeid_t node); -	nodeid_t idCount; -	node_t nextNode(); +	void flushNodes(); +	bool hasId(nodeid_t id); +	bool isProtected(nodeid_t id) const;  	std::string file; +	NodeTree tree;  }; -#ifndef FOOBAR  extern NodeManager node_manager; -#endif - - -#if 0 - -/* -Node: -  id -  subnodes -//  tags -  title -  description -//  primary_assignment -//  secondary_assignment - - -Protocol: - -Server -> client: - update [id] [title] [description]; - move [id] [x] [y]; - add [id] [title] [description] [x] [y]; - del [id] - -Client -> server: - update [id] [title] [description]; - move [id] [x] [y]; - add [title] [description] [x] [y]; - del [id] - -title and description are " encapsulated utf-8 string with " escaped with a backslash. -x and y are integers as strings -id are an integer as a string - */ - -/* -typedef struct { -  int x, y; -  int id; -  std::string title; -  std::string desc; -} node_t; -*/ -/* -protocol: -  add_node title description parent_id -  del_node id -  update_node id title description -  move_node id parent -  copy_node id parent -*/ - - - -//typedef std::list<node_t> NodeList; - -class CompareByParentid -{ -public: -	bool operator()(const node_t &a, const node_t &b) const -	{ -		return a.parent_id < b.parent_id; -	} -}; - -class NodeList -	: public std::list<node_t> -{ -public: -	NodeList() {} -	~NodeList(){} - -	void insert(node_t t) -	{ -		if(t.id == t.parent_id) -		{ -			return; -		} -		printf("inserting node %d with parent %d\n", t.id, t.parent_id); - -		if(t.parent_id == -1) -		{ -			std::list<node_t>::push_front(t); -			return; -		} - -		std::list<node_t>::iterator it; -		for(it = begin(); it != end(); ++it) -		{ -			printf("\tcomparing %d and %d\n", t.parent_id, it->id); -			if(t.parent_id == it->id) -			{ -				break; -			} -		} -		assert(it != end()); - -		std::list<node_t>::insert(++it, t); - -		//std::list<node_t>::push_back(t); -		//std::list<node_t>::sort(CompareByParentid()); -	} - -	void move(node_t t) -	{ -		std::list<node_t>::iterator it; -		for(it = begin(); it != end(); it++) -		{ -			if(t.id == it->id) -			{ -				break; -			} -		} -		assert(it != end()); -		//if(it != end()) -		//{ -		std::list<node_t>::erase(it); -		//} -		insert(t); -	} - -	void push_back(node_t t) -	{ -		insert(t); -	} - -private: -	std::list<node_t> list; -}; - - -extern NodeList nodelist; - -//typedef std::priority_queue<node_t, std::vector<node_t>, CompareByParentid> NodeList; - -node_t create_node(std::string title, std::string desc, /*int x, int y*/ int parent_id); - -NodeList load_nodelist_from_file(std::string file); -bool save_nodelist_to_file(NodeList t, std::string file); -#endif/*0*/ diff --git a/src/nodetree.cc b/src/nodetree.cc index a2499ea..f0877ff 100644 --- a/src/nodetree.cc +++ b/src/nodetree.cc @@ -34,6 +34,7 @@  #include "hugin.hpp"  #include "xml_encode_decode.h" +#include "exceptions.h"  #define ROOT_PARENT_ID -1 @@ -75,22 +76,14 @@ std::string Node::toXML(std::string prefix)  static void concatNodeIdLists(NodeIdList& pre, NodeIdList& post)  {  	pre.insert(pre.end(), post.begin(), post.end()); -	//for(NodeIdList::iterator it = post.begin(); -	//it != post.end(); it++) -	//{ -	//  pre.push_back( -	//}  }  NodeTree::NodeTree()  { -	root = NULL; -	nextid = 10;  }  NodeTree::~NodeTree()  { -	// cleanup tree  }  nodeid_t NodeTree::createId() @@ -106,7 +99,7 @@ nodeid_t NodeTree::createId()  	return nodeid;  } -bool NodeTree::hasId(nodeid_t nodeid) +bool NodeTree::hasId(nodeid_t nodeid) const  {  	return id2node.find(nodeid) != id2node.end();  } @@ -115,11 +108,15 @@ static nodeid_t rootid = -1;  NodeIdList NodeTree::insertAsChild(nodeid_t parentid, nodeid_t id,                                     node_t data, nodeid_t insertBeforeId) -	throw (std::exception)  {  	NodeIdList affectedNodes; -	// Initialize +	if(parentid == id) +	{ +		throw Error::NewParentIsSelf(); // Node and new parent are the same node. +	} + +	// Initialized?  	if(!root)  	{  		rootid = id; @@ -130,62 +127,46 @@ NodeIdList NodeTree::insertAsChild(nodeid_t parentid, nodeid_t id,  	}  	else  	{ -		try +		if(!hasId(parentid))  		{ -			Node* parent = id2node.at(parentid); -			Node* child = createNode(id); -			//DEBUG(nodetree, "!!!!!!!id in insert: %d\n", data.id); -			child->data = data; -			insertChild(parent, child, insertBeforeId); - -			//affectedNodes.push_back(parentid); -			affectedNodes.push_back(id); -			NodeIdList ancestors = ancestorList(id); -			concatNodeIdLists(affectedNodes, ancestors); -		} -		catch(std::exception& e) -		{ -			throw e; +			throw Error::MissingParent();  		} + +		Node* parent = id2node.at(parentid); +		Node* child = createNode(id); + +		child->data = data; +		insertChild(parent, child, insertBeforeId); +		affectedNodes.push_back(id); + +		NodeIdList ancestors = ancestorList(id); +		concatNodeIdLists(affectedNodes, ancestors);  	} -	//DEBUG(nodetree, "Child %d added to %d, affecting %d nodes\n", -	//      id, parentid, affectedNodes.size());  	return affectedNodes;  }  NodeIdList NodeTree::remove(nodeid_t id) -	throw (std::exception)  { +	if(!hasId(id)) +	{ +		throw Error::NoSuchId(); +	} +  	NodeIdList affectedNodes;  	affectedNodes.push_back(id);  	NodeIdList ancestors = ancestorList(id);  	concatNodeIdLists(affectedNodes, ancestors); -	//DEBUG(nodetree, "Removing %d\n", id); -	//DEBUG(nodetree, "!!!!!affected nodes %d\n", affectedNodes.size()); - -	Node* node = id2node[id]; - -	//DEBUG(nodetree, "node: %p, id %d, parent %p\n", node, node->data.id, node->parent); +	Node* node = id2node.at(id); -	//DEBUG(nodetree, "!!!!!size %d\n", node->parent->children.size());  	node->parent->children.remove(node); -	for(NodeList::iterator it = node->parent->children.begin(); -	    it != node->parent->children.end(); -	    it++) -	{ -		//DEBUG(nodetree, "%p\n", *it); -	} -	//DEBUG(nodetree, "!!!!!size %d\n", node->parent->children.size());  	NodeIdList idlist = bfs(id);  	NodeIdList::reverse_iterator it = idlist.rbegin();  	while(it != idlist.rend())  	{  		node_t node = data(*it); -		//Node* n = id2node[node.id]; -		//delete(n);  		it++;  	} @@ -208,112 +189,114 @@ static bool findNode(Node *needle, Node *haystack)  }  NodeIdList NodeTree::move(nodeid_t id, nodeid_t toid, nodeid_t beforeId) -	throw (std::exception)  {  	NodeIdList affectedNodes; -	try +	if(id == toid)  	{ -		Node* child = id2node.at(id); -		Node* newparent = id2node.at(toid); +		throw Error::NewParentIsSelf(); // Node and new parent are the same node. +	} -		// Test if new parent is a child of the node itself... -		if(findNode(newparent, child)) -		{ -			throw std::exception(); -		} +	if(!hasId(id)) +	{ +		throw Error::NoSuchId(); +	} -		if(!child->parent) -		{ -			throw std::exception(); -		} +	Node* child = id2node.at(id); -		child->parent->children.remove(child); -		bool inserted{false}; -		for(auto it = newparent->children.begin(); -		    it != newparent->children.end(); -		    ++it) -		{ -			if((*it)->id == beforeId) -			{ -				newparent->children.insert(it, child); -				inserted = true; -			} -		} -		if(!inserted) -		{ -			// beforeId was not found in parent - inserting last instead. -			newparent->children.push_back(child); -		} +	if(!hasId(toid)) +	{ +		throw Error::MissingParent(); +	} -		child->parent = newparent; +	Node* newparent = id2node.at(toid); -		affectedNodes.push_back(id); -		//    affectedNodes.push_back(child->parent->id); -		NodeIdList ancestors = ancestorList(id); -		concatNodeIdLists(affectedNodes, ancestors); -		affectedNodes.push_back(toid); -		ancestors = ancestorList(toid); +	// Test if new parent is a child of the node itself... +	if(findNode(newparent, child)) +	{ +		throw Error::NewParentIsChildOfSelf(); +	} + +	if(!child->parent) +	{ +		throw Error::System("Node does not have a parent."); +	} + +	child->parent->children.remove(child); +	bool inserted{false}; +	for(auto it = newparent->children.begin(); +	    it != newparent->children.end(); +	    ++it) +	{ +		if((*it)->id == beforeId) +		{ +			newparent->children.insert(it, child); +			inserted = true; +		}  	} -	catch(std::exception& e) +	if(!inserted)  	{ -		throw e; +		// beforeId was not found in parent - inserting last instead. +		newparent->children.push_back(child);  	} +	child->parent = newparent; + +	affectedNodes.push_back(id); + +	NodeIdList ancestors = ancestorList(id); +	concatNodeIdLists(affectedNodes, ancestors); +	affectedNodes.push_back(toid); +	ancestors = ancestorList(toid); +  	return affectedNodes;  }  NodeIdList NodeTree::updateData(nodeid_t id, const std::string &name,                                  const std::string &value) -  throw (std::exception)  { +	if(!hasId(id)) +	{ +		throw Error::NoSuchId(); +	} +  	NodeIdList affectedNodes; -	try -	{ -		Node* node = id2node.at(id); -		node->data.attributes[name] = value; +	Node* node = id2node.at(id); +	node->data.attributes[name] = value; -		affectedNodes.push_back(id); -		NodeIdList ancestors = ancestorList(id); -		concatNodeIdLists(affectedNodes, ancestors); -	} -	catch(std::exception& e) -	{ -		throw e; -	} +	affectedNodes.push_back(id); +	NodeIdList ancestors = ancestorList(id); +	concatNodeIdLists(affectedNodes, ancestors);  	return affectedNodes;  }  node_t NodeTree::data(nodeid_t id) -	throw (std::exception)  { +	if(!hasId(id)) +	{ +		throw Error::NoSuchId(); +	} +  	node_t t; -	try +	Node* node = id2node.at(id); +	node_t tmp = node->data; +	t.id = node->id; +	t.attributes = tmp.attributes; + +	if(node->parent)  	{ -		Node* node = id2node.at(id); -		node_t tmp = node->data; -		t.id = node->id; -		t.attributes = tmp.attributes; -		//DEBUG(nodetree, "!!!!t.id and tmp.id in data: %d and %d\n", t.id, tmp.id); -		if(node->parent) -		{ -			t.parentid = node->parent->id; -		} -		else -		{ -			if(t.id != rootid) -			{ -				throw std::exception(); -			} -			t.parentid = -1; -		} +		t.parentid = node->parent->id;  	} -	catch(std::exception& e) +	else  	{ -		throw e; +		if(t.id != rootid) +		{ +			throw Error::System("Node has no parent, but node is not root."); +		} +		t.parentid = -1;  	}  	return t; @@ -321,8 +304,12 @@ node_t NodeTree::data(nodeid_t id)  // bfs search from id in tree  NodeIdList NodeTree::bfs(nodeid_t id) -	throw (std::exception)  { +	if(!hasId(id)) +	{ +		throw Error::NoSuchId(); +	} +  	NodeIdList lst;  	lst.push_back(id); @@ -353,35 +340,36 @@ NodeIdList NodeTree::bfs(nodeid_t id)  }  NodeIdList NodeTree::ancestorList(nodeid_t id) -	throw (std::exception)  {  	NodeIdList ancestors; -	try +	if(!hasId(id))  	{ -		Node* current = id2node.at(id); -		while(current->parent) -		{ -			ancestors.push_back(current->parent->id); -			current = current->parent; -		} +		throw Error::NoSuchId();  	} -	catch(std::exception& e) + +	Node* current = id2node.at(id); +	auto origin = current; +	while(current->parent)  	{ -		throw e; +		ancestors.push_back(current->parent->id); +		current = current->parent; +		if(current == origin) +		{ +			throw Error::System("Cycle detected."); +		}  	} -	//DEBUG(nodetree, "Collected %d ancestors to %u\n", ancestors.size(), id); -	//for(NodeIdList::iterator it = ancestors.begin(); -	//    it != ancestors.end(); it++) -	//{ -	//	DEBUG(nodetree, "\tancestor %u\n", *it); -	//}  	return ancestors;  }  Node* NodeTree::createNode(nodeid_t id)  { +	if(hasId(id)) +	{ +		throw Error::IdAlreadyExists(); +	} +  	Node* node = new Node();  	node->parent = NULL;  	node->id = id; @@ -425,6 +413,7 @@ static void printNode(Node* node, std::string prefix)  	{  	  return;  	} +  	node_t t = node->data;  	DEBUG(nodetree, "%s- %u - %s (%p)\n", prefix.c_str(), (int)node->id,  	      t.attributes["title"].c_str(), node); @@ -444,12 +433,13 @@ void NodeTree::toStdOut()  std::string NodeTree::toXML()  { -	Node *root = id2node.at(rootid); -  	std::string xml;  	xml += "<?xml version='1.0' encoding='UTF-8'?>\n";  	xml += "<nodetree nextid=\""+id2str(nextid)+"\">\n"; -	xml += root->toXML("  "); +	if(root) +	{ +		xml += root->toXML("  "); +	}  	xml += "</nodetree>";  	return xml; diff --git a/src/nodetree.h b/src/nodetree.h index f2f4600..41f7272 100644 --- a/src/nodetree.h +++ b/src/nodetree.h @@ -29,7 +29,6 @@  #include <list>  #include <map> -#include <exception>  #include "node.h" @@ -54,33 +53,57 @@ public:  	~NodeTree();  	nodeid_t createId(); -	bool hasId(nodeid_t nodeid); +	bool hasId(nodeid_t nodeid) const; +	//! May throw: +	//! - Error::MissingParent if the parent node id does not exist in the tree. +	//! - Error::NoSuchId if the ancestorList cannot be made from the supplied id. +	//! - Error::IdAlreadyExists if the supplied id already exists in the tree. +	//! - Error::NewParentIsSelf if id and parentid are the same.  	NodeIdList insertAsChild(nodeid_t parentid, nodeid_t id, node_t data, -	                         nodeid_t insertBeforeId) throw (std::exception); -	NodeIdList remove(nodeid_t id) throw (std::exception); -	NodeIdList move(nodeid_t id, nodeid_t newParentId, -	                nodeid_t insertBeforeId) throw (std::exception); +	                         nodeid_t insertBeforeId); + +	//! May throw: +	//! - Error::NoSuchId if node id does not exist. +	//! - Error::ProtectedNode if node is protected and cannot be removed. +	NodeIdList remove(nodeid_t id); + +	//! May throw: +	//! - Error::NewParentIsSelf if id and parentid are the same. +	//! - Error::NoSuchId if node id does not exist. +	//! - Error::MissingParent if new parent node does not exist. +	//! - Error::ProtectedNode if node is protected and cannot be (re)moved. +	NodeIdList move(nodeid_t id, nodeid_t newParentId, nodeid_t insertBeforeId); + +	//! May throw: +	//! - Error::NoSuchId if node id does not exist.  	NodeIdList updateData(nodeid_t id, const std::string &name, -	                      const std::string &value) throw (std::exception); -	node_t data(nodeid_t id) throw (std::exception); +	                      const std::string &value); -	NodeIdList bfs(nodeid_t id) throw (std::exception); +	//! May throw: +	//! - Error::NoSuchId if node id does not exist. +	node_t data(nodeid_t id); -	NodeIdList ancestorList(nodeid_t id) throw (std::exception); +	//! May throw: +	//! - Error::NoSuchId if node id does not exist. +	NodeIdList bfs(nodeid_t id); + +	//! May throw: +	//! - Error::NoSuchId if node id does not exist. +	NodeIdList ancestorList(nodeid_t id);  	void toStdOut();  	std::string toXML(); -	void fromXML(const std::string& xml); -	nodeid_t nextid; +	void fromXML(const std::string& xml);  private:  	friend class XmlParser;  	Node* createNode(nodeid_t id);  	void insertChild(Node* parent, Node* child, nodeid_t insertBeforeId); -	Node* root; +	nodeid_t nextid{10}; +	Node* root{nullptr};  	std::map<int, Node*> id2node;  }; | 
