Add routing infrastructure.

This commit is contained in:
Tristan Hume 2015-04-30 19:22:08 -04:00
parent 9a73bcaad2
commit e370a57a42
3 changed files with 137 additions and 4 deletions

80
source/ddbus/router.d Normal file
View file

@ -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");
}

View file

@ -5,6 +5,7 @@ import ddbus.conv;
import ddbus.util; import ddbus.util;
import std.string; import std.string;
import std.typecons; import std.typecons;
import std.exception;
class DBusException : Exception { class DBusException : Exception {
this(DBusError *err) { this(DBusError *err) {
@ -24,6 +25,11 @@ T wrapErrors(T)(T delegate(DBusError *err) del) {
return ret; return ret;
} }
enum MessageType {
Invalid = 0,
Call, Return, Error, Signal
}
class Message { class Message {
this(string dest, string path, string iface, string method) { this(string dest, string path, string iface, string method) {
msg = dbus_message_new_method_call(dest.toStringz(), path.toStringz(), iface.toStringz(), method.toStringz()); msg = dbus_message_new_method_call(dest.toStringz(), path.toStringz(), iface.toStringz(), method.toStringz());
@ -64,22 +70,67 @@ class Message {
return ret; return ret;
} }
const(char)[] signature() { Message createReturn() {
const(char)* cSig = dbus_message_get_signature(msg); return new Message(dbus_message_new_method_return(msg));
return fromStringz(cSig); }
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; DBusMessage *msg;
} }
unittest {
import dunit.toolkit;
auto msg = new Message("org.example.test", "/test","org.example.testing","testMethod");
msg.path().assertEqual("/test");
}
class Connection { class Connection {
DBusConnection *conn; DBusConnection *conn;
this(DBusConnection *connection) { this(DBusConnection *connection) {
conn = connection; conn = connection;
} }
void sendBlocking(Message msg) { void send(Message msg) {
dbus_connection_send(conn,msg.msg, null); dbus_connection_send(conn,msg.msg, null);
}
void sendBlocking(Message msg) {
send(msg);
dbus_connection_flush(conn); dbus_connection_flush(conn);
} }

View file

@ -64,6 +64,8 @@ string typeSig(T)() if(canDBus!T) {
return "d"; return "d";
} else static if(is(T == string)) { } else static if(is(T == string)) {
return "s"; return "s";
} else static if(is(T == void)) {
return "";
} else static if(isTuple!T) { } else static if(isTuple!T) {
string sig = "("; string sig = "(";
foreach(i, S; T.Types) { foreach(i, S; T.Types) {