Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ONEMPERS-523 fix GetNameOwner synchronization issue #4

Open
wants to merge 4 commits into
base: lg-0.7.3
Choose a base branch
from
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 61 additions & 31 deletions lib/src/dbus_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,63 @@ class DBusNameOwnerChangedEvent {
/// Exception thrown when a request is sent and the connection to the D-Bus server is closed.
class DBusClosedException implements Exception {}

class NameOwners {
final _nameOwners = <DBusBusName, DBusBusName>{};
/* The Future is used to await in [] operator
* till name owner data will be received.
* Without this synchronization the _processSignal method
* might ignore signals received before name owner data.
*/
Future<void>? nameOwnerSet;

bool containsValue(DBusBusName? name) {
return _nameOwners.containsValue(name);
}

DBusBusName? remove(DBusBusName? name) {
return _nameOwners.remove(name);
}

Future<DBusBusName?> setNameOwner(DBusClient client, DBusBusName name) async {
nameOwnerSet = null;
var uniqueName = await getNameOwner(client, name.value);
if (uniqueName == null) {
return null;
}

var uniqueName_ = DBusBusName(uniqueName);
_nameOwners[name] = uniqueName_;
nameOwnerSet = Future<void>.value();
return uniqueName_;
}

/// Returns the unique connection name of the client that owns [name].
Future<String?> getNameOwner(DBusClient client, String name) async {
DBusMethodSuccessResponse result;
try {
result = await client.callMethod(
destination: 'org.freedesktop.DBus',
path: DBusObjectPath('/org/freedesktop/DBus'),
interface: 'org.freedesktop.DBus',
name: 'GetNameOwner',
values: [DBusString(name)],
replySignature: DBusSignature('s'));
} on DBusMethodResponseException catch (e) {
if (e.response.errorName == 'org.freedesktop.DBus.Error.NameHasNoOwner') {
return null;
}
rethrow;
}
return (result.returnValues[0] as DBusString).value;
}

Future<DBusBusName?> operator [](DBusBusName? key) async {
await nameOwnerSet;
return _nameOwners[key];
}
void operator []=(DBusBusName key, DBusBusName value) => _nameOwners[key] = value;
}

/// A client connection to a D-Bus server.
class DBusClient {
final DBusAddress _address;
Expand All @@ -233,7 +290,7 @@ class DBusClient {
final _matchRules = <String, int>{};

// Maps D-Bus names (e.g. 'org.freedesktop.DBus') to unique names (e.g. ':1').
final _nameOwners = <DBusBusName, DBusBusName>{};
final _nameOwners = NameOwners();

// Names owned by this client. e.g. [ 'com.example.Foo', 'com.example.Bar' ].
final _ownedNames = <DBusBusName>{};
Expand Down Expand Up @@ -453,26 +510,6 @@ class DBusClient {
return (result.returnValues[0] as DBusBoolean).value;
}

/// Returns the unique connection name of the client that owns [name].
Future<String?> getNameOwner(String name) async {
DBusMethodSuccessResponse result;
try {
result = await callMethod(
destination: 'org.freedesktop.DBus',
path: DBusObjectPath('/org/freedesktop/DBus'),
interface: 'org.freedesktop.DBus',
name: 'GetNameOwner',
values: [DBusString(name)],
replySignature: DBusSignature('s'));
} on DBusMethodResponseException catch (e) {
if (e.response.errorName == 'org.freedesktop.DBus.Error.NameHasNoOwner') {
return null;
}
rethrow;
}
return (result.returnValues[0] as DBusString).value;
}

/// Returns the Unix user ID of the process running the client that owns [name].
Future<int> getConnectionUnixUser(String name) async {
var result = await callMethod(
Expand Down Expand Up @@ -633,14 +670,7 @@ class DBusClient {
Future<DBusBusName?> _findUniqueName(DBusBusName name) async {
if (_nameOwners.containsValue(name)) return _nameOwners[name];

var uniqueName = await getNameOwner(name.value);
if (uniqueName == null) {
return null;
}

var uniqueName_ = DBusBusName(uniqueName);
_nameOwners[name] = uniqueName_;
return uniqueName_;
return _nameOwners.setNameOwner(this, name);
}

/// Emits a signal from a D-Bus object.
Expand Down Expand Up @@ -1014,7 +1044,7 @@ class DBusClient {
}

/// Processes a signal received from the D-Bus server.
void _processSignal(DBusMessage message) {
void _processSignal(DBusMessage message) async {
// Check has required fields.
if (message.path == null ||
message.interface == null ||
Expand All @@ -1025,7 +1055,7 @@ class DBusClient {
for (var stream in _signalStreams) {
// If the stream is for an owned name, check if that matches the unique name in the message.
var sender = message.sender;
if (_nameOwners[stream._rule.sender] == sender) {
if (await _nameOwners[stream._rule.sender] == sender) {
sender = stream._rule.sender;
}

Expand Down