diff --git a/source/ddbus/router.d b/source/ddbus/router.d index 58499e5..91414cb 100644 --- a/source/ddbus/router.d +++ b/source/ddbus/router.d @@ -128,7 +128,7 @@ class MessageRouter { formattedWrite(app,introspectHeader,path); foreach(iface; ifaces) { formattedWrite(app,``,iface.front.iface); - foreach(methodPatt; iface) { + foreach(methodPatt; iface.array()) { formattedWrite(app,``,methodPatt.method); auto handler = callTable[methodPatt]; foreach(arg; handler.argSig) { @@ -149,7 +149,7 @@ class MessageRouter { auto children = callTable.byKey().filter!(a => (a.path.startsWith(childPath)) && !a.signal)() .map!((s) => s.path.chompPrefix(childPath)) .map!((s) => s.splitter('/').front) - .uniq(); + .array().sort().uniq(); foreach(child; children) { formattedWrite(app,``,child); } @@ -199,9 +199,12 @@ unittest{ router.setHandler!(void,int,string)(patt,(int p, string p2) {}); patt = MessagePattern("/root/wat","ca.thume.tester","lolwut"); 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 = ` `; router.introspectXML("/root").assertEqual(introspectResult); - router.introspectXML("/").assertEndsWith(``); + router.introspectXML("/").assertEndsWith(``); } diff --git a/source/ddbus/simple.d b/source/ddbus/simple.d index 71ec8cf..1532667 100644 --- a/source/ddbus/simple.d +++ b/source/ddbus/simple.d @@ -3,7 +3,9 @@ module ddbus.simple; import ddbus.thin; import ddbus.util; import ddbus.c_lib; +import ddbus.router; import std.string; +import std.traits; class PathIface { this(Connection conn, string dest, string path, string iface) { @@ -41,3 +43,45 @@ unittest { names.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"]); +}