Add basic server functionality.

This commit is contained in:
Tristan Hume 2015-05-01 20:36:06 -04:00
parent 5905d50e1a
commit 1457b249b7
4 changed files with 104 additions and 18 deletions

View file

@ -1,10 +1,10 @@
import std.stdio;
import ddbus.c_lib;
import ddbus.thin;
import ddbus.router;
import ddbus.bus;
void main()
{
Connection conn = connectToBus();
void testCall(Connection conn) {
for(int i = 0; i < 50; i++) {
Message msg = Message("ca.thume.transience","/ca/thume/transience/screensurface",
"ca.thume.transience.screensurface","testDot");
@ -15,5 +15,24 @@ void main()
Message res = conn.sendWithReplyBlocking(msg2,3000);
int result = res.read!int();
writeln(result);
}
void testServe(Connection conn) {
auto router = new MessageRouter();
MessagePattern patt = MessagePattern("/root","ca.thume.test","test");
router.setHandler!(int,int)(patt,(int par) {
writeln("Called with ", par);
return par;
});
registerRouter(conn, router);
writeln("Getting name...");
bool gotem = requestName(conn, "ca.thume.ddbus.test");
writeln("Got name: ",gotem);
simpleMainLoop(conn);
}
void main() {
Connection conn = connectToBus();
testServe(conn);
writeln("It worked!");
}

39
source/ddbus/bus.d Normal file
View file

@ -0,0 +1,39 @@
module ddbus.bus;
import ddbus.router;
import ddbus.thin;
import ddbus.c_lib;
import std.string;
enum BusService = "org.freedesktop.DBus";
enum BusPath = "/org/freedesktop/DBus";
enum BusInterface = "org.freedesktop.DBus";
enum NameFlags {
AllowReplace = 1, ReplaceExisting = 2, NoQueue = 4
}
/// Requests a DBus well-known name.
/// returns if the name is owned after the call.
/// Involves blocking call on a DBus method, may throw an exception on failure.
bool requestName(Connection conn, string name,
NameFlags flags = NameFlags.NoQueue | NameFlags.AllowReplace) {
auto msg = Message(BusService,BusPath,BusInterface,"RequestName");
msg.build(name,cast(uint)(flags));
auto res = conn.sendWithReplyBlocking(msg).to!uint;
return (res == 1) || (res == 4);
}
/// A simple main loop that isn't necessarily efficient
/// and isn't guaranteed to work with other tasks and threads.
/// Use only for apps that only do DBus triggered things.
void simpleMainLoop(Connection conn) {
while(dbus_connection_read_write_dispatch(conn.conn, -1)) {} // empty loop body
}
unittest {
import dunit.toolkit;
Connection conn = connectToBus();
conn.requestName("ca.thume.ddbus.testing").assertTrue();
}

View file

@ -1,14 +1,16 @@
module ddbus.router;
import ddbus.thin;
import ddbus.c_lib;
import std.string;
import std.typecons;
import core.memory;
struct MessagePattern {
string sender;
string path;
string iface;
string method;
string sender;
this(Message msg) {
path = msg.path();
@ -21,6 +23,13 @@ struct MessagePattern {
}
}
this(string path, string iface, string method, string sender = null) {
this.path = path;
this.iface = iface;
this.method = method;
this.sender = sender;
}
size_t toHash() const @safe nothrow {
size_t hash = 0;
auto stringHash = &(typeid(path).getHash);
@ -38,14 +47,9 @@ struct MessagePattern {
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) {
bool handle(Message msg, Connection conn) {
MessageType type = msg.type();
if(type != MessageType.Call && type != MessageType.Signal)
return false;
@ -56,7 +60,7 @@ class MessageRouter {
return true;
}
void setHandler(Ret, Args...)(MessagePattern patt, Connection conn, Ret delegate(Args) handler) {
void setHandler(Ret, Args...)(MessagePattern patt, Ret delegate(Args) handler) {
void handlerWrapper(Message call, Connection conn) {
Tuple!Args args = call.readTuple!(Tuple!Args)();
Ret ret = handler(args.expand);
@ -70,10 +74,34 @@ class MessageRouter {
}
}
extern(C) private DBusHandlerResult filterFunc(DBusConnection *dConn, DBusMessage *dMsg, void *routerP) {
MessageRouter router = cast(MessageRouter)routerP;
dbus_message_ref(dMsg);
Message msg = Message(dMsg);
dbus_connection_ref(dConn);
Connection conn = Connection(dConn);
bool handled = router.handle(msg, conn);
if(handled) {
return DBusHandlerResult.DBUS_HANDLER_RESULT_HANDLED;
} else {
return DBusHandlerResult.DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
}
extern(C) private void unrootUserData(void *userdata) {
GC.removeRoot(userdata);
}
void registerRouter(Connection conn, MessageRouter router) {
void *routerP = cast(void*)router;
GC.addRoot(routerP);
dbus_connection_add_filter(conn.conn, &filterFunc, routerP, &unrootUserData);
}
unittest {
import dunit.toolkit;
auto msg = Message("org.example.test", "/test","org.example.testing","testMethod");
auto patt= MessagePattern(msg);
auto patt= new MessagePattern(msg);
patt.assertEqual(patt);
patt.sender.assertNull();
patt.path.assertEqual("/test");

View file

@ -94,27 +94,27 @@ struct Message {
string signature() {
const(char)* cStr = dbus_message_get_signature(msg);
assert(cStr != null);
return cStr.fromStringz().assumeUnique();
return cStr.fromStringz().idup;
}
string path() {
const(char)* cStr = dbus_message_get_path(msg);
assert(cStr != null);
return cStr.fromStringz().assumeUnique();
return cStr.fromStringz().idup;
}
string iface() {
const(char)* cStr = dbus_message_get_interface(msg);
assert(cStr != null);
return cStr.fromStringz().assumeUnique();
return cStr.fromStringz().idup;
}
string member() {
const(char)* cStr = dbus_message_get_member(msg);
assert(cStr != null);
return cStr.fromStringz().assumeUnique();
return cStr.fromStringz().idup;
}
string sender() {
const(char)* cStr = dbus_message_get_sender(msg);
assert(cStr != null);
return cStr.fromStringz().assumeUnique();
return cStr.fromStringz().idup;
}
}
@ -151,7 +151,7 @@ struct Connection {
dbus_connection_flush(conn);
}
Message sendWithReplyBlocking(Message msg, int timeout = 100) {
Message sendWithReplyBlocking(Message msg, int timeout = -1) {
DBusMessage *dbusMsg = msg.msg;
dbus_message_ref(dbusMsg);
DBusMessage *reply = wrapErrors((err) {