summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2020-07-04 16:58:08 +0200
committerBent Bisballe Nyeng <deva@aasimon.org>2020-07-04 17:03:52 +0200
commit8db5ff97ffe34aa42f71b5c8aebfa0878e5fde89 (patch)
tree7d5a196d8dd34621bbdb4b80cd4b78d96ecfeb05
parentd21701afe4230d633ae685ffeee6f5fb5a76f34d (diff)
Add error message support and reporting on all commands.
-rw-r--r--src/Makefile.am2
-rw-r--r--src/errorcodes.h44
-rw-r--r--src/exceptions.h106
-rw-r--r--src/message.h9
-rw-r--r--src/messagehandler.cc79
-rw-r--r--src/messageparser.cc119
-rw-r--r--src/messageparser.h20
-rw-r--r--src/munia_proto.cc60
-rw-r--r--src/nodemanager.cc297
-rw-r--r--src/nodemanager.h172
-rw-r--r--src/nodetree.cc266
-rw-r--r--src/nodetree.h49
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;
};