Add routing infrastructure.
This commit is contained in:
parent
9a73bcaad2
commit
e370a57a42
80
source/ddbus/router.d
Normal file
80
source/ddbus/router.d
Normal 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");
|
||||||
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue