Add basic server functionality.
This commit is contained in:
parent
5905d50e1a
commit
1457b249b7
25
source/app.d
25
source/app.d
|
@ -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
39
source/ddbus/bus.d
Normal 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();
|
||||
}
|
||||
|
|
@ -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");
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue