Skip to content

Commit

Permalink
Allow clients and server to not have a message bus
Browse files Browse the repository at this point in the history
  • Loading branch information
robert-ancell committed Sep 22, 2023
1 parent d81dc8a commit 6234d48
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 27 deletions.
28 changes: 22 additions & 6 deletions lib/src/dbus_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,18 @@ class DBusSignalStream extends Stream<DBusSignal> {

void _onListen() {
_client._signalStreams.add(this);
if (_rule.sender != null) {
_client._findUniqueName(_rule.sender!);
if (_client._messageBus) {
if (_rule.sender != null) {
_client._findUniqueName(_rule.sender!);
}
_client._addMatch(_rule.toDBusString());
}
_client._addMatch(_rule.toDBusString());
}

Future<void> _onCancel() async {
await _client._removeMatch(_rule.toDBusString());
if (_client._messageBus) {
await _client._removeMatch(_rule.toDBusString());
}
_client._signalStreams.remove(this);
}
}
Expand Down Expand Up @@ -226,15 +230,22 @@ class DBusClient {
// Names owned by this client. e.g. [ 'com.example.Foo', 'com.example.Bar' ].
final _ownedNames = <DBusBusName>{};

// True if this client is connecting to a message bus.
final bool _messageBus;

// Unique name of this client, e.g. ':42'.
DBusBusName? _uniqueName;

/// True if this client allows other clients to introspect it.
final bool introspectable;

/// Creates a new DBus client to connect on [address].
DBusClient(DBusAddress address, {this.introspectable = true})
: _address = address;
/// If [messageBus] is false, then the server is not running a message bus and
/// no adresses or client to client communication is suported.
DBusClient(DBusAddress address,
{this.introspectable = true, bool messageBus = true})
: _address = address,
_messageBus = messageBus;

/// Creates a new DBus client to communicate with the system bus.
factory DBusClient.system({bool introspectable = true}) {
Expand Down Expand Up @@ -794,6 +805,11 @@ class DBusClient {
return;
}

if (!_messageBus) {
_connectCompleter?.complete();
return;
}

// The first message to the bus must be this call, note requireConnect is
// false as the _connect call hasn't yet completed and would otherwise have
// been called again.
Expand Down
61 changes: 40 additions & 21 deletions lib/src/dbus_server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ class _DBusRemoteClient {
// If the subscription is for an owned name, check if that matches the unique name in the message.
var sender = message.sender;
if (rule.sender != null &&
server._messageBusObject._getClientByName(rule.sender!)?.uniqueName ==
server._messageBusObject
?._getClientByName(rule.sender!)
?.uniqueName ==
sender) {
sender = rule.sender;
}
Expand Down Expand Up @@ -224,7 +226,7 @@ class _DBusServerSocket {
/// Handle a client disconnecting.
void _clientDisconnected(_DBusRemoteClient client) {
_clients.remove(client);
server._messageBusObject._releaseAllNames(client);
server._messageBusObject?._releaseAllNames(client);
}

Future<void> close() async {
Expand Down Expand Up @@ -355,11 +357,13 @@ class DBusServer {
final _interfaces = <String>[];

/// Message bus functionality.
late final _MessageBusObject _messageBusObject;
_MessageBusObject? _messageBusObject;

/// Creates a new DBus server.
DBusServer() {
_messageBusObject = _MessageBusObject(this);
DBusServer({bool messageBus = true}) {
if (messageBus) {
_messageBusObject = _MessageBusObject(this);
}
}

/// Start a service that uses [name].
Expand Down Expand Up @@ -514,18 +518,21 @@ class DBusServer {
Future<void> _processMessage(
_DBusRemoteClient? client, DBusMessage message) async {
// Forward to any clients that are listening to this message.
var targetClient = message.destination != null
? _messageBusObject._getClientByName(message.destination!)
: null;
for (var client in _clients) {
if (client == targetClient || client.matchMessage(message)) {
client.sendMessage(message);
if (_messageBusObject != null) {
var targetClient = message.destination != null
? _messageBusObject!._getClientByName(message.destination!)
: null;
for (var client in _clients) {
if (client == targetClient || client.matchMessage(message)) {
client.sendMessage(message);
}
}
}

// Process requests for the server.
DBusMethodResponse? response;
if (client != null &&
if (_messageBusObject != null &&
client != null &&
!client.receivedHello &&
!(message.destination?.value == 'org.freedesktop.DBus' &&
message.interface?.value == 'org.freedesktop.DBus' &&
Expand All @@ -540,7 +547,7 @@ class DBusServer {
} else {
// No-one is going to handle this message.
if (message.destination != null &&
_messageBusObject._getClientByName(message.destination!) == null) {
_messageBusObject?._getClientByName(message.destination!) == null) {
response = _DBusServerErrorResponse.serviceUnknown(
'The name ${message.destination} is not registered');
}
Expand Down Expand Up @@ -568,8 +575,13 @@ class DBusServer {
sender: DBusBusName('org.freedesktop.DBus'),
values: values);
_nextSerial++;
// ignore: unawaited_futures
_processMessage(null, responseMessage);

if (_messageBusObject != null) {
// ignore: unawaited_futures
_processMessage(null, responseMessage);
} else {
client?.sendMessage(responseMessage);
}
}
}

Expand All @@ -580,19 +592,26 @@ class DBusServer {
return DBusMethodErrorResponse.failed();
}

var object = _messageBusObject;
var methodCall = _ServerMethodCall(client, message);

if (methodCall.interface == 'org.freedesktop.DBus.Peer') {
return await handlePeerMethodCall(methodCall);
} else if (methodCall.interface == 'org.freedesktop.DBus.Introspectable') {
var objectTree = DBusObjectTree();
var node = objectTree.add(message.path ?? DBusObjectPath('/'), object);
return handleIntrospectableMethodCall(node, methodCall);
} else if (methodCall.interface == 'org.freedesktop.DBus.Properties') {
return await handlePropertiesMethodCall(object, methodCall);
if (_messageBusObject != null) {
objectTree.add(message.path ?? DBusObjectPath('/'), _messageBusObject!);
}
return handleIntrospectableMethodCall(
message.path != null ? objectTree.lookup(message.path!) : null,
methodCall);
} else if (_messageBusObject != null) {
if (methodCall.interface == 'org.freedesktop.DBus.Properties') {
return await handlePropertiesMethodCall(_messageBusObject!, methodCall);
} else {
return await _messageBusObject!.handleMethodCall(methodCall);
}
} else {
return await object.handleMethodCall(methodCall);
return DBusMethodErrorResponse.unknownObject();
}
}

Expand Down
30 changes: 30 additions & 0 deletions test/dbus_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5010,6 +5010,36 @@ void main() {
throwsA(isA<DBusUnknownMethodException>()));
});

test('no message bus', () async {
var server = DBusServer(messageBus: false);
var address =
await server.listenAddress(DBusAddress.unix(dir: Directory.systemTemp));
var client = DBusClient(address, messageBus: false);
addTearDown(() async {
await client.close();
await server.close();
});

await client.ping();
});

test('no message bus - introspect', () async {
var server = DBusServer(messageBus: false);
var address =
await server.listenAddress(DBusAddress.unix(dir: Directory.systemTemp));
var client = DBusClient(address, messageBus: false);
addTearDown(() async {
await client.close();
await server.close();
});

// Read introspection data from the server.
var remoteObject = DBusRemoteObject(client,
name: 'org.freedesktop.DBus', path: DBusObjectPath('/'));
var node = await remoteObject.introspect();
expect(node.toXml().toXmlString(), equals('<node/>'));
});

test('introspect xml - empty', () {
expect(() => parseDBusIntrospectXml(''), throwsFormatException);
});
Expand Down

0 comments on commit 6234d48

Please sign in to comment.