Skip to content

Commit

Permalink
Allow for dbus data type aay. Add a couple of test programs.
Browse files Browse the repository at this point in the history
* test-aay.dart actually creates an Avahi service for NearbyShare advertising.
  If successful, your machine shows up as a Nearby Share device.
  I notice that canonical Avahis is a very limited implementation via dbus.
  This test would work nicely there if that package used this new DBus with aay.
* test-array-of-arrays.dart is just a rudimentary regression.

This is ready for a pull request as I would like to get eyes on as soon as possible.
If it gains any traction I will fork the avahi project and add examples from here.
  • Loading branch information
crussell42 committed Oct 4, 2023
1 parent e601409 commit 552c6ed
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 28 deletions.
72 changes: 64 additions & 8 deletions lib/src/dbus_read_buffer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,28 @@ class DBusReadBuffer extends DBusBuffer {
return null;
}

//RSC reading an aay signature
// In the case of a type aay coming from the dbus, the data will occur like this.
// Assuming a single "ay" byte array (len 10 of char 'x') inside an "a" we will get
// 14,0,0,0,10,0,0,0,x,x,x,x,x,x,x,x,x,x
// This makes sense.
// If there were multiple 'ay' inside the a it would still work...
// e.g. if we had 2 ay's in the a (1 len 4), the other (len 6)
// 18,0,0,0,4,0,0,0,x,x,x,x,6,0,0,0,y,y,y,y,y,y

//print(' <<<< RSC dbus_read_buffer.readMessage signature [${signature}]\n ${_data}\n');

// The issue here is that we need to calculate that initial length after
// iterating over the possible nested array elements to build our DBusValueType's correctly.
// e.g. we want DBusArray(DBusSignature('a'),DBusArray.bytes(bytevalues))
// instead of DBusArray(DBusSignature('a'),[]), DBusArray.byte[byte values]
// which is what it currently returns (although this works)

var dataEnd = readOffset + dataLength;
var values = <DBusValue>[];
if (signature != null) {
var signatures = signature.split();
List<DBusValue> valueStack = <DBusValue>[];
for (var s in signatures) {
var value = readDBusValue(s, endian, fdCount);
if (value == null) {
Expand All @@ -183,8 +201,37 @@ class DBusReadBuffer extends DBusBuffer {
if (readOffset > dataEnd) {
throw 'Message data of size $dataLength too small to contain ${signature.value}';
}
values.add(value);
if (s.value == 'a') {
// Specifically, this indicates an array of arrays. e.g. type='aay'
// which we need to translate into
// DBusArray(DBusSignature('a'),[DBusArray(DBusSignature(y),[DBusByte(42),DBusByte(99)])])
// -or- more succinctly
// DBusArray(DBusSignature('a'),[DBusArray.byte([42,99])])
//
// The 'a' sig value returned above is an empty DBusArray(DBusSignature('a'),[])
// This will become the outter array later when they are all combined.
valueStack.add(value);
} else {
//If valueStack has anything in it, this is the second array in an array of arrays.
if ((value is DBusArray)&&(valueStack.length>0)) {
valueStack.add(value);
}
//Unwind any array of array values before adding the value to the values
if (valueStack.length>0) {
//print(' RSC COMBINING ARRAY OF ARRAYS DATA');
DBusArray outterArr = valueStack[0] as DBusArray;
for (int ndx=1;ndx<valueStack.length;ndx++) {
outterArr.children.add(valueStack[ndx]);
}
values.add(outterArr);
valueStack.clear();
} else {
values.add(value);
}
}
}
if (valueStack.length>0) throw "SOMEONE DID NOT CLEAN THE valueStack";
//RSC REVISIT
if (readOffset != dataEnd) {
throw 'Message data of size $dataLength too large to contain ${signature.value}';
}
Expand Down Expand Up @@ -450,12 +497,15 @@ class DBusReadBuffer extends DBusBuffer {

var end = readOffset + length.value;
var children = <DBusValue>[];
while (readOffset < end) {
var child = readDBusValue(childSignature, endian, fdCount);
if (child == null) {
return null;
//RSC If it is an a then just return the empty children and they will be filled in later.
if (childSignature.value != 'a') {
while (readOffset < end) {
var child = readDBusValue(childSignature, endian, fdCount);
if (child == null) {
return null;
}
children.add(child);
}
children.add(child);
}

return DBusArray(childSignature, children);
Expand Down Expand Up @@ -532,8 +582,14 @@ class DBusReadBuffer extends DBusBuffer {
}
return readDBusDict(keySignature, valueSignature, endian, fdCount);
} else if (s.startsWith('a')) {
return readDBusArray(
DBusSignature(s.substring(1, s.length)), endian, fdCount);
// RSC aay should come in as an a then an ay
// So if this is just the 'a' then return just read that.
if (s.length==1) {
return readDBusArray(
DBusSignature(s.substring(0, s.length)), endian, fdCount);
} else
return readDBusArray(
DBusSignature(s.substring(1, s.length)), endian, fdCount);
} else if (s.startsWith('(') && s.endsWith(')')) {
return readDBusStruct(
DBusSignature(s.substring(1, s.length - 1)).split(), endian, fdCount);
Expand Down
35 changes: 30 additions & 5 deletions lib/src/dbus_value.dart
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,13 @@ class DBusSignature extends DBusValue {

/// Check [value] contains a valid signature and return the index of the end of the current child signature.
int _validate(String value, int index) {
//RSC REVISIT where this can happen
//print(' _validate called val:'+value+' index:'+index.toString());
if (index>=value.length) {
print('RSC: INDEX EXCEEDED because aa passed to constructor of DBusSignature');
return value.length-1;
}

if (value.startsWith('(', index)) {
// Struct.
var end = _findClosing(value, index, '(', ')');
Expand Down Expand Up @@ -659,10 +666,17 @@ class DBusSignature extends DBusValue {
}
return end;
} else if (value.startsWith('a', index)) {
// Array.
if (index >= value.length - 1) {
throw ArgumentError.value(value, 'value', 'Array missing child type');
//RSC commented
//if (index >= value.length - 1) {
// throw ArgumentError.value(value, 'value', 'Array missing child type');
//}
if (value.length==1) {
//RSC So it can be just an "a" with no follow on type
//print(' RSC _validate HACK ALLOW "a"');
return 1;
}
//RSC REVISIT:
// Shouldnt we else with the original code??? dbus_write_buffer.writeMessage
return _validate(value, index + 1);
} else if (value.startsWith('m', index)) {
// Maybe.
Expand All @@ -687,6 +701,14 @@ class DBusSignature extends DBusValue {
} else if (value.startsWith('a{', index)) {
return _findClosing(value, index, '{', '}');
} else if (value.startsWith('a', index)) {
//RSC check for aa as in 'aay' or 'aas'
String rest = value.substring(index);
if (rest.length>1) {
if (rest.substring(1,2)=='a') {
//print('RSC: dbus_value._findChildSignatureEnd found an array of arrays in signature [${value}] index: ${index}');
return index; //only return index because caller will add 1 to it
}
}
return _findChildSignatureEnd(value, index + 1);
} else if (value.startsWith('m', index)) {
return _findChildSignatureEnd(value, index + 1);
Expand Down Expand Up @@ -891,13 +913,16 @@ class DBusArray extends DBusValue {
/// An exception will be thrown if a DBusValue in [children] doesn't have a signature matching [childSignature].
DBusArray(this.childSignature, [Iterable<DBusValue> children = const []])
: children = children.toList() {
if (!childSignature.isSingleCompleteType) {
//RSC it could be just an 'a'
// if (!childSignature.isSingleCompleteType) {
if ((childSignature.value != 'a')&&(!childSignature.isSingleCompleteType)) {
throw ArgumentError.value(childSignature, 'childSignature',
'Array value type must be a single complete type');
}

for (var child in children) {
if (child.signature.value != childSignature.value) {
//RSC same as above
if ((childSignature.value != 'a')&&(child.signature.value != childSignature.value)) {
throw ArgumentError.value(children, 'children',
"Provided children don't match array signature ${childSignature.value}");
}
Expand Down
22 changes: 21 additions & 1 deletion lib/src/dbus_write_buffer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ class DBusWriteBuffer extends DBusBuffer {
if (message.values.isNotEmpty) {
var signature = '';
for (var value in message.values) {
signature += value.signature.value;
//RSC Build sig recursively in the case of aay
String walkVal = walkForSignature(value);
//signature += value.signature.value;
signature = signature + walkVal;
}
headers.add(_makeHeader(8, DBusSignature(signature)));
}
Expand All @@ -80,6 +83,23 @@ class DBusWriteBuffer extends DBusBuffer {
align(8);
writeBytes(valueBuffer.data);
_resourceHandles.addAll(valueBuffer.resourceHandles);
//RSC
//print(' >>>>dbus_write_buffer.writeMessage data\n[${data}]\n');
}

//RSC recurse for signature (but should only do 1 extra level) REVISIT
String walkForSignature(DBusValue dval) {
//print(' ## RSC:walk runtimeType: ${dval.runtimeType}');
if ((dval is DBusArray)&&(dval.childSignature.value == 'a')) {
//array of array..e.g. aay or aas would hit here first.
//print(' ## RSC:walk adding "a" (array of arrays)');
//In writeMessage the DBusValue array of arrays would have children.
//if not then there is an error.
if ((dval.children).isEmpty) throw "Empty Array of Arrays found...${dval}";
return 'a' + walkForSignature(dval.children[0]);
}
//Something like ay (byte array) or as (string array)
return dval.signature.value;
}

/// Makes a new message header.
Expand Down
20 changes: 11 additions & 9 deletions test/test-aay.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,20 @@ DBusClient systemDBusClient = DBusClient.system();
//These get filled in in
late DBusRemoteObject serverObject;
late DBusRemoteObject entryGroupObject;
AvahiServiceConfig serviceConfig = AvahiServiceConfig('mycoolservice',8765);
AvahiServiceConfig serviceConfig = AvahiServiceConfig('trixy',8765);

void main() async {

print('TEST new array of arrays DBus type by ADDING a NearbyShare service definition using DBus');
print('This program first attaches to Avahi Server using the Dart DBus lib.');
print('Next, it creates an Avahi EntryGroup object.');
print('Next it adds a Nearby Share style service definition.');
print('Then it polls the EntryGroup state until it is fully "Established".');
print('Finally it uses the same service configuration to resolve its self.');
print('BEGIN');
print('Platform.hostname: ${Platform.localHostname}');
print('TEST Googles NearbyShare (Advertising) using Avahi via DBus on Linux.');
print(" *This requires DBus data type='aay' (array of array of bytes).\nSteps.");

print('1. Attach to Avahi Server using the Dart DBus lib.');
print('2. Create an Avahi EntryGroup object.');
print('3. Add a NearbyShare Service definition to the new EntryGroup.');
print('4. Poll the EntryGroup status until the new service is ESTABLISHED');
print('5. Call Avahi ResolveService via DBus to print content of our');
print(' newly added NearbyShare (advertising) service.\n');
print('BEGIN TEST ON Platform.hostname: ${Platform.localHostname}');

await attachAvahiObjects();

Expand Down
11 changes: 6 additions & 5 deletions test/test-array-of-arrays.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ void main() async {
var test_both = [
DBusInt32(42),
DBusArray(DBusSignature('a'), [
DBusArray(DBusSignature('y'), [DBusByte(88), DBusByte(88), DBusByte(88)])
DBusArray(DBusSignature('y'), [DBusByte(88), DBusByte(88), DBusByte(88)]),
]),
DBusArray(DBusSignature('a'), [
DBusArray(DBusSignature('s'),
Expand Down Expand Up @@ -76,11 +76,12 @@ void main() async {

var test_fail = [
DBusInt32(42),
//DBusArray(DBusSignature('i'),[DBusInt32(42),DBusInt32(42)]),
DBusArray(DBusSignature('a'), []),
//DBusInt32(69)
DBusArray(DBusSignature('a'), [
DBusArray(DBusSignature('y'), [DBusByte(88), DBusByte(88), DBusByte(88)]),
DBusArray(DBusSignature('y'), [DBusByte(99), DBusByte(99), DBusByte(99)]),
]),
];
print('TEST Signature [iai]');
print('TEST Signature [iaay]');
dumpAsMessage(test_fail);

print('DONE\n');
Expand Down

0 comments on commit 552c6ed

Please sign in to comment.