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 get name owner synchronization issue #347

Closed
Show file tree
Hide file tree
Changes from all 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
26 changes: 26 additions & 0 deletions README.lg.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
The orignal dbus.dart library was forked and and extended with the following
functionalities:
- support for communicating over the ApplicationServices websocket (dbus
bridge over websocket, data encapsulated in json)
- support for deserializing the JSON data into the DBusValue objects. This is
required to have common API for purposes of switching between dbus-socket
and websocket.
- annotation DBusReplySignature was added to generated methods code.
DBusReplySignature brings the reply signature and names of output arguments
into the dart code. This is required to generated the sound types in API
instead of providing the List<DBusValue>.
DBusSignalSignature was added to generated signal classes. This is not
required for library generation purposes, but is needed to generate the testing
code. This signature bring the signal signature and interface name into the dart code.
Generator was extended with --annotations option for this purpose
- types required for dbus_annotations were added to the library.

Example of annotations:
```
33 @DBusAPI()
34 class SampleClass extends DBusRemoteObject {
35 @DBusReplySignature('iasss',['value','names','resource_name','type'])
36 Future<List<DBusValue>> callGetParams() async { ... }
37 }
```

8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ $ dart-dbus generate-remote-object test-object.xml -o test-remote-object.dart
You can then use the generated `test-remote-object.dart` to access that remote object from your program:

```dart
import 'package:dbus/dbus.dart';
import 'package:dbus_onemw/dbus.dart';
import 'test-remote-object.dart';

Future<void> main() async {
Expand All @@ -55,7 +55,7 @@ $ dart-dbus generate-object test-object.xml -o test-object.dart
You can then use the generated `test-object.dart` in your program:

```dart
import 'package:dbus/dbus.dart';
import 'package:dbus_onemw/dbus.dart';
import 'test-object.dart';

class TestObject extends ComExampleTestObject {
Expand Down Expand Up @@ -86,7 +86,7 @@ This requires writing more code and handing more error cases.
The following code shows how to access the remote object in the above examples:

```dart
import 'package:dbus/dbus.dart';
import 'package:dbus_onemw/dbus.dart';

Future<void> main() async {
var client = DBusClient.session();
Expand All @@ -104,7 +104,7 @@ Future<void> main() async {
And the following shows how to export that object:

```dart
import 'package:dbus/dbus.dart';
import 'package:dbus_onemw/dbus.dart';

class TestObject extends DBusObject {
TestObject() : super(DBusObjectPath('/com/example/Test/Object'));
Expand Down
7 changes: 4 additions & 3 deletions bin/dart_dbus.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'dart:io';
import 'package:args/command_runner.dart';
import 'package:dbus/code_generator.dart';
import 'package:dbus/dbus.dart';
import 'package:dbus_onemw/code_generator.dart';
import 'package:dbus_onemw/dbus.dart';

/// Command that generates a DBusObject class from an introspection XML file.
class GenerateObjectCommand extends Command {
Expand Down Expand Up @@ -49,6 +49,7 @@ class GenerateRemoteObjectCommand extends Command {
abbr: 'o', valueHelp: 'filename', help: 'Dart file to write to');
argParser.addOption('class-name',
valueHelp: 'ClassName', help: 'Class name to use');
argParser.addFlag('annotations', help: 'whether to use annotations (default: no)');
}

@override
Expand All @@ -62,7 +63,7 @@ class GenerateRemoteObjectCommand extends Command {
var comment =
'This file was generated using the following command and may be overwritten.\ndart-dbus $name $filename';
var source = DBusCodeGenerator(node,
comment: comment, className: argResults?['class-name'])
comment: comment, className: argResults?['class-name'], withAnnotations:argResults?['annotations'])
.generateClientSource();
await writeSource(source, argResults?['output']);
}
Expand Down
2 changes: 1 addition & 1 deletion example/credentials.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'dart:math';

import 'package:dbus/dbus.dart';
import 'package:dbus_onemw/dbus.dart';

void main() async {
var client = DBusClient.system();
Expand Down
2 changes: 1 addition & 1 deletion example/example.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:dbus/dbus.dart';
import 'package:dbus_onemw/dbus.dart';

void main() async {
var client = DBusClient.session();
Expand Down
2 changes: 1 addition & 1 deletion example/file_descriptor.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'dart:convert';
import 'dart:io';

import 'package:dbus/dbus.dart';
import 'package:dbus_onemw/dbus.dart';

class TestObject extends DBusObject {
TestObject() : super(DBusObjectPath('/com/canonical/DBusDart'));
Expand Down
2 changes: 1 addition & 1 deletion example/hostname.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:dbus/dbus.dart';
import 'package:dbus_onemw/dbus.dart';

void main() async {
var client = DBusClient.system();
Expand Down
2 changes: 1 addition & 1 deletion example/object_manager.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:dbus/dbus.dart';
import 'package:dbus_onemw/dbus.dart';

void main() async {
var client = DBusClient.system();
Expand Down
2 changes: 1 addition & 1 deletion example/properties.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:dbus/dbus.dart';
import 'package:dbus_onemw/dbus.dart';

void main() async {
var client = DBusClient.system();
Expand Down
2 changes: 1 addition & 1 deletion example/register_object.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:dbus/dbus.dart';
import 'package:dbus_onemw/dbus.dart';

// Test with:
// $ gdbus call --session --dest com.canonical.DBusDart --object-path /com/canonical/DBusDart --method com.canonical.DBusDart.Test
Expand Down
2 changes: 1 addition & 1 deletion example/request_name.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:dbus/dbus.dart';
import 'package:dbus_onemw/dbus.dart';

Future<void> acquireName(
DBusClient client, String name, Set<DBusRequestNameFlag> flags) async {
Expand Down
2 changes: 1 addition & 1 deletion example/server.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'dart:io';

import 'package:dbus/dbus.dart';
import 'package:dbus_onemw/dbus.dart';

void main() async {
var server = DBusServer();
Expand Down
2 changes: 1 addition & 1 deletion example/signals.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'dart:async';

import 'package:dbus/dbus.dart';
import 'package:dbus_onemw/dbus.dart';

class TestObject extends DBusObject {
TestObject() : super(DBusObjectPath('/com/canonical/DBusDart'));
Expand Down
2 changes: 2 additions & 0 deletions lib/dbus.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ export 'src/dbus_remote_object_manager.dart';
export 'src/dbus_server.dart';
export 'src/dbus_signal.dart';
export 'src/dbus_value.dart';
export 'src/dbus_annotations.dart';
export 'src/dbus_ws_read_buffer.dart';
15 changes: 15 additions & 0 deletions lib/src/dbus_annotations.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class DBusReplySignature {
final String signature;
final List<String> fieldNames;
const DBusReplySignature(this.signature, this.fieldNames);
}

class DBusSignalSignature {
final String signature;
final String interface;
const DBusSignalSignature(this.signature, this.interface);
}

class DBusAPI {
const DBusAPI();
}
97 changes: 66 additions & 31 deletions lib/src/dbus_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ import 'dbus_value.dart';
import 'dbus_write_buffer.dart';
import 'getuid.dart';

// begin: dbus over websocket
import 'package:meta/meta.dart';
import 'dbus_ws_write_buffer.dart';
import 'dbus_ws_read_buffer.dart';
import 'dbus_ws_message.dart';
import 'package:web_socket_channel/web_socket_channel.dart';
import 'package:stream_channel/stream_channel.dart';

part 'dbus_ws_client.dart';
// end: dbus over websocket

/// Reply received when calling [DBusClient.requestName].
enum DBusRequestNameReply { primaryOwner, inQueue, exists, alreadyOwner }

Expand Down Expand Up @@ -203,6 +214,57 @@ 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>{};
Future? nameOwnersFutureResponse;

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

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

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

var uniqueName_ = DBusBusName(uniqueName);
_nameOwners[name] = uniqueName_;
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 nameOwnersFutureResponse;
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 @@ -222,7 +284,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 @@ -442,26 +504,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 @@ -622,14 +664,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 @@ -1003,7 +1038,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 @@ -1014,7 +1049,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
Loading