diff --git a/source/ddbus/router.d b/source/ddbus/router.d new file mode 100644 index 0000000..63d6637 --- /dev/null +++ b/source/ddbus/router.d @@ -0,0 +1,80 @@ +module ddbus.router; + +import ddbus.thin; +import std.string; +import std.typecons; + +struct MessagePattern { + string sender; + string path; + string iface; + string method; + + this(Message msg) { + path = msg.path(); + iface = msg.iface(); + method = msg.member(); + if(msg.type()==MessageType.Signal) { + sender = msg.sender(); + } else { + sender = null; + } + } + + size_t toHash() const @safe nothrow { + size_t hash = 0; + auto stringHash = &(typeid(path).getHash); + hash += stringHash(&sender); + hash += stringHash(&path); + hash += stringHash(&iface); + hash += stringHash(&method); + return hash; + } + + bool opEquals(ref const this s) const @safe pure nothrow { + return (path == s.path) && (iface == s.iface) && (method == s.method) && (sender == s.sender); + } +} + +class MessageRouter { + alias HandlerFunc = void delegate(Message call, Connection conn); + Connection conn; + HandlerFunc[MessagePattern] callTable; + + this(Connection conn) { + this.conn = conn; + } + + bool handle(Message msg) { + MessageType type = msg.type(); + if(type != MessageType.Call && type != MessageType.Signal) + return false; + auto pattern = MessagePattern(msg); + HandlerFunc* handler = (pattern in callTable); + if(handler is null) return false; + (*handler)(msg,conn); + return true; + } + + void setHandler(Ret, Args...)(MessagePattern patt, Connection conn, Ret delegate(Args) handler) { + void handlerWrapper(Message call, Connection conn) { + Tuple!Args args = call.readTuple!(Tuple!Args)(); + Ret ret = handler(args.expand); + auto retMsg = call.createReturn(); + static if(!is(Ret == void)) { + retMsg.build(ret); + } + conn.send(retMsg); + } + callTable[patt] = &handlerWrapper; + } +} + +unittest { + import dunit.toolkit; + auto msg = new Message("org.example.test", "/test","org.example.testing","testMethod"); + auto patt= new MessagePattern(msg); + patt.assertEqual(patt); + patt.sender.assertNull(); + patt.path.assertEqual("/test"); +} diff --git a/source/ddbus/thin.d b/source/ddbus/thin.d index ad8bc76..f4802d0 100644 --- a/source/ddbus/thin.d +++ b/source/ddbus/thin.d @@ -5,6 +5,7 @@ import ddbus.conv; import ddbus.util; import std.string; import std.typecons; +import std.exception; class DBusException : Exception { this(DBusError *err) { @@ -24,6 +25,11 @@ T wrapErrors(T)(T delegate(DBusError *err) del) { return ret; } +enum MessageType { + Invalid = 0, + Call, Return, Error, Signal +} + class Message { this(string dest, string path, string iface, string method) { msg = dbus_message_new_method_call(dest.toStringz(), path.toStringz(), iface.toStringz(), method.toStringz()); @@ -64,22 +70,67 @@ class Message { return ret; } - const(char)[] signature() { - const(char)* cSig = dbus_message_get_signature(msg); - return fromStringz(cSig); + Message createReturn() { + return new Message(dbus_message_new_method_return(msg)); + } + + MessageType type() { + return cast(MessageType)dbus_message_get_type(msg); + } + + bool isCall() { + return type() == MessageType.Call; + } + + // Various string members + // TODO: make a mixin to avoid this copy-paste + string signature() { + const(char)* cStr = dbus_message_get_signature(msg); + assert(cStr != null); + return cStr.fromStringz().assumeUnique(); + } + string path() { + const(char)* cStr = dbus_message_get_path(msg); + assert(cStr != null); + return cStr.fromStringz().assumeUnique(); + } + string iface() { + const(char)* cStr = dbus_message_get_interface(msg); + assert(cStr != null); + return cStr.fromStringz().assumeUnique(); + } + string member() { + const(char)* cStr = dbus_message_get_member(msg); + assert(cStr != null); + return cStr.fromStringz().assumeUnique(); + } + string sender() { + const(char)* cStr = dbus_message_get_sender(msg); + assert(cStr != null); + return cStr.fromStringz().assumeUnique(); } DBusMessage *msg; } +unittest { + import dunit.toolkit; + auto msg = new Message("org.example.test", "/test","org.example.testing","testMethod"); + msg.path().assertEqual("/test"); +} + class Connection { DBusConnection *conn; this(DBusConnection *connection) { conn = connection; } + void send(Message msg) { + dbus_connection_send(conn,msg.msg, null); + } + void sendBlocking(Message msg) { - dbus_connection_send(conn,msg.msg,null); + send(msg); dbus_connection_flush(conn); } diff --git a/source/ddbus/util.d b/source/ddbus/util.d index 04560ef..c30bde2 100644 --- a/source/ddbus/util.d +++ b/source/ddbus/util.d @@ -64,6 +64,8 @@ string typeSig(T)() if(canDBus!T) { return "d"; } else static if(is(T == string)) { return "s"; + } else static if(is(T == void)) { + return ""; } else static if(isTuple!T) { string sig = "("; foreach(i, S; T.Types) {