Add a simple method of routing to an object.

This commit is contained in:
Tristan Hume 2015-05-03 22:07:49 -04:00
parent 8771b8b2b1
commit d60a78cde8
2 changed files with 50 additions and 3 deletions

View file

@ -128,7 +128,7 @@ class MessageRouter {
formattedWrite(app,introspectHeader,path); formattedWrite(app,introspectHeader,path);
foreach(iface; ifaces) { foreach(iface; ifaces) {
formattedWrite(app,`<interface name="%s">`,iface.front.iface); formattedWrite(app,`<interface name="%s">`,iface.front.iface);
foreach(methodPatt; iface) { foreach(methodPatt; iface.array()) {
formattedWrite(app,`<method name="%s">`,methodPatt.method); formattedWrite(app,`<method name="%s">`,methodPatt.method);
auto handler = callTable[methodPatt]; auto handler = callTable[methodPatt];
foreach(arg; handler.argSig) { foreach(arg; handler.argSig) {
@ -149,7 +149,7 @@ class MessageRouter {
auto children = callTable.byKey().filter!(a => (a.path.startsWith(childPath)) && !a.signal)() auto children = callTable.byKey().filter!(a => (a.path.startsWith(childPath)) && !a.signal)()
.map!((s) => s.path.chompPrefix(childPath)) .map!((s) => s.path.chompPrefix(childPath))
.map!((s) => s.splitter('/').front) .map!((s) => s.splitter('/').front)
.uniq(); .array().sort().uniq();
foreach(child; children) { foreach(child; children) {
formattedWrite(app,`<node name="%s"/>`,child); formattedWrite(app,`<node name="%s"/>`,child);
} }
@ -199,9 +199,12 @@ unittest{
router.setHandler!(void,int,string)(patt,(int p, string p2) {}); router.setHandler!(void,int,string)(patt,(int p, string p2) {});
patt = MessagePattern("/root/wat","ca.thume.tester","lolwut"); patt = MessagePattern("/root/wat","ca.thume.tester","lolwut");
router.setHandler!(int,int)(patt,(int p) {return 6;}); router.setHandler!(int,int)(patt,(int p) {return 6;});
patt = MessagePattern("/troll","ca.thume.tester","wow");
router.setHandler!(void)(patt,{return;});
// TODO: these tests rely on nondeterministic hash map ordering
static string introspectResult = `<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> static string introspectResult = `<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/root"><interface name="ca.thume.test"><method name="test"><arg type="i" direction="in"/><arg type="i" direction="out"/></method></interface><interface name="ca.thume.tester"><method name="lolwut"><arg type="i" direction="in"/><arg type="s" direction="in"/></method></interface><node name="wat"/></node>`; <node name="/root"><interface name="ca.thume.test"><method name="test"><arg type="i" direction="in"/><arg type="i" direction="out"/></method></interface><interface name="ca.thume.tester"><method name="lolwut"><arg type="i" direction="in"/><arg type="s" direction="in"/></method></interface><node name="wat"/></node>`;
router.introspectXML("/root").assertEqual(introspectResult); router.introspectXML("/root").assertEqual(introspectResult);
router.introspectXML("/").assertEndsWith(`<node name="/"><node name="root"/></node>`); router.introspectXML("/").assertEndsWith(`<node name="/"><node name="root"/><node name="troll"/></node>`);
} }

View file

@ -3,7 +3,9 @@ module ddbus.simple;
import ddbus.thin; import ddbus.thin;
import ddbus.util; import ddbus.util;
import ddbus.c_lib; import ddbus.c_lib;
import ddbus.router;
import std.string; import std.string;
import std.traits;
class PathIface { class PathIface {
this(Connection conn, string dest, string path, string iface) { this(Connection conn, string dest, string path, string iface) {
@ -41,3 +43,45 @@ unittest {
names.assertEqual("org.freedesktop.DBus"); names.assertEqual("org.freedesktop.DBus");
obj.call!string("GetNameOwner","org.freedesktop.DBus").assertEqual("org.freedesktop.DBus"); obj.call!string("GetNameOwner","org.freedesktop.DBus").assertEqual("org.freedesktop.DBus");
} }
/**
Registers all *possible* methods of an object in a router.
It will not register methods that use types that ddbus can't handle.
The implementation is rather hacky and uses the compiles trait to check for things
working so if some methods randomly don't seem to be added, you should probably use
setHandler on the router directly. It is also not efficient and creates a closure for every method.
TODO: replace this with something that generates a wrapper class who's methods take and return messages
and basically do what MessageRouter.setHandler does but avoiding duplication. Then this DBusWrapper!Class
could be instantiated with any object efficiently and placed in the router table with minimal duplication.
*/
void registerMethods(T : Object)(MessageRouter router, string path, string iface, T obj) {
MessagePattern patt = MessagePattern(path,iface,"",false);
foreach(member; __traits(allMembers, T)) {
static if (__traits(compiles, __traits(getOverloads, obj, member))
&& __traits(getOverloads, obj, member).length > 0
&& __traits(compiles, router.setHandler(patt, &__traits(getOverloads,obj,member)[0]))) {
patt.method = member;
router.setHandler(patt, &__traits(getOverloads,obj,member)[0]);
}
}
}
unittest {
import dunit.toolkit;
class Tester {
int lol(int x, string s) {return 5;}
void wat() {}
}
auto o = new Tester;
auto router = new MessageRouter;
registerMethods(router, "/","ca.thume.test",o);
MessagePattern patt = MessagePattern("/","ca.thume.test","wat");
router.callTable.assertHasKey(patt);
patt.method = "lol";
router.callTable.assertHasKey(patt);
auto res = router.callTable[patt];
res.argSig.assertEqual(["i","s"]);
res.retSig.assertEqual(["i"]);
}