Skip to content
Merged
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
15 changes: 7 additions & 8 deletions docs/tool.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,9 @@ The `Tmds.DBus.Tool` packages extends the dotnet cli to facilitate developing .N
The tool supports:
- [codegen](#codegen): generate C# code for consuming D-Bus services.
- [list](#list): list the available objects, interfaces and services.
- [monitor](#monitor): prints message bus messages.

The tool can be added by using a `DotNetCliToolReference` in the project file.

```xml
<ItemGroup>
<DotNetCliToolReference Include="Tmds.DBus.Tool" Version="0.5.0" />
</ItemGroup>
```
The tool can be installed using `dotnet tool install -g Tmds.DBus.Tool`

Now it can be invoked from the command line:
```
Expand Down Expand Up @@ -77,4 +72,8 @@ The `list` command can also be used to list interfaces from XML files.

```
$ dotnet dbus list interfaces /usr/share/dbus-1/interfaces/*.xml
```
```

## monitor

The `monitor` command registers the tool as a bus monitor and prints out the message bus messages.
14 changes: 0 additions & 14 deletions samples/Monitor/Monitor.csproj

This file was deleted.

11 changes: 0 additions & 11 deletions samples/Monitor/Program.cs

This file was deleted.

6 changes: 6 additions & 0 deletions src/Tmds.DBus.Protocol/Reader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ public bool HasNext(ArrayEnd iterator)
}
return true;
}

public void SkipTo(ArrayEnd end)
{
int advance = end.EndOfArray - (int)_reader.Consumed;
_reader.Advance(advance);
}
}

public ref struct ArrayEnd
Expand Down
317 changes: 317 additions & 0 deletions src/Tmds.DBus.Tool/MonitorCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,317 @@
using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.CommandLineUtils;
using Tmds.DBus.Protocol;

namespace Tmds.DBus.Tool;

class MonitorCommand : Command
{
CommandOption _busOption;

public MonitorCommand(CommandLineApplication parent) :
base("monitor", parent)
{ }

public override void Configure()
{
_busOption = AddBusOption();
}

public override void Execute()
{
var address = ParseBusAddress(_busOption);
MonitorBusAsync(address).Wait();
}

private async Task MonitorBusAsync(string address)
{
StringBuilder sb = new StringBuilder();

await foreach (DisposableMessage dmsg in Tmds.DBus.Protocol.Connection.MonitorBusAsync(address))
{
using var _ = dmsg;
Message msg = dmsg.Message;

FormatMessage(sb, msg);

Print(sb);

sb.Clear();
}
}

static void Print(StringBuilder sb)
{
foreach (var chunk in sb.GetChunks())
{
Console.Write(chunk);
}
}

private const string ItemPrefix = "- ";

static void FormatMessage(StringBuilder sb, Message msg)
{
switch (msg.MessageType)
{
case MessageType.MethodCall:
sb.Append("CAL ");
break;
case MessageType.MethodReturn:
sb.Append("RET ");
break;
case MessageType.Error:
sb.Append("ERR ");
break;
case MessageType.Signal:
sb.Append("SIG ");
break;
default:
throw new ArgumentOutOfRangeException(msg.MessageType.ToString());
}

sb.Append(msg.SenderAsString);
sb.Append($"({msg.Serial})");
sb.Append("->");
if (msg.DestinationIsSet)
{
sb.Append(msg.DestinationAsString);
}
if (msg.ReplySerial.HasValue)
{
sb.Append($"({msg.ReplySerial.Value})");
}
sb.Append(' ');

if (msg.PathIsSet)
{
sb.Append(msg.PathAsString);
sb.Append(' ');
}

if (msg.InterfaceIsSet)
{
sb.Append(msg.InterfaceAsString);
sb.Append('.');
}
if (msg.MemberIsSet)
{
sb.Append(msg.MemberAsString);
sb.Append(' ');
}

if (msg.ErrorNameIsSet)
{
sb.Append(msg.ErrorNameAsString);
sb.Append(' ');
}

if (msg.SignatureIsSet)
{
sb.Append(msg.SignatureAsString);
}
sb.AppendLine();

SignatureReader sigReader = new(msg.Signature);
Reader reader = msg.GetBodyReader();
while (sigReader.TryRead(out DBusType type, out ReadOnlySpan<byte> innerSignature))
{
int indent = 2;
Indent(sb, indent);
sb.Append(ItemPrefix);
AppendValue(sb, indent + ItemPrefix.Length, ref reader, type, innerSignature);
}
}

static void AppendValue(StringBuilder sb, int indent, ref Reader reader, DBusType type, ReadOnlySpan<byte> innerSignature, bool addNewLine = true, bool isDictEntryValue = false)
{
SignatureReader sigReader;
switch (type)
{
case DBusType.Byte:
sb.Append(reader.ReadByte());
break;
case DBusType.Bool:
sb.Append(reader.ReadBool());
break;
case DBusType.Int16:
sb.Append(reader.ReadInt16());
break;
case DBusType.UInt16:
sb.Append(reader.ReadUInt16());
break;
case DBusType.Int32:
sb.Append(reader.ReadInt32());
break;
case DBusType.UInt32:
sb.Append(reader.ReadUInt32());
break;
case DBusType.Int64:
sb.Append(reader.ReadInt64());
break;
case DBusType.UInt64:
sb.Append(reader.ReadUInt64());
break;
case DBusType.Double:
sb.Append(reader.ReadDouble());
break;
case DBusType.String:
sb.Append(reader.ReadString());
break;
case DBusType.ObjectPath:
sb.Append(reader.ReadObjectPath());
break;
case DBusType.Signature:
sb.Append(reader.ReadSignatureAsString());
break;
case DBusType.UnixFd:
sb.Append(reader.ReadHandleRaw());
break;
case DBusType.Array:
sigReader = new(innerSignature);
sigReader.TryRead(out type, out innerSignature);
bool isDictionary = type == DBusType.DictEntry;

// Print these types on a single line.
bool printSingleLine = type is DBusType.Byte or
DBusType.Bool or
DBusType.Int16 or
DBusType.UInt16 or
DBusType.Int32 or
DBusType.UInt32 or
DBusType.Int64 or
DBusType.UInt64 or
DBusType.Double or
DBusType.UnixFd;

// Only print first 16 elements of an array.
int remaining = isDictionary ? int.MaxValue : 16;

ArrayEnd arrayEnd = reader.ReadArrayStart(type);
bool isEmpty = true;
while (reader.HasNext(arrayEnd))
{
if (printSingleLine)
{
if (isEmpty) // first
{
sb.Append("[");
}
else
{
sb.Append(", ");
}
}
else
{
if (isEmpty) // first
{
if (isDictEntryValue)
{
sb.AppendLine();
Indent(sb, indent);
}
}
else
{
Indent(sb, indent);
}

if (!isDictionary)
{
sb.Append(ItemPrefix);
}
}
isEmpty = false;

if (remaining-- == 0)
{
if (printSingleLine)
{
sb.Append("...");
}
else
{
sb.AppendLine("...");
}
reader.SkipTo(arrayEnd);
break;
}

AppendValue(sb, isDictionary ? indent : indent + ItemPrefix.Length, ref reader, type, innerSignature, addNewLine: !printSingleLine);
}
if (isEmpty)
{
sb.AppendLine(isDictionary ? "{}" : "[]");
}
else if (printSingleLine)
{
sb.AppendLine("]");
}

addNewLine = false;
break;
case DBusType.Struct:
if (isDictEntryValue)
{
sb.AppendLine();
Indent(sb, indent);
}

reader.AlignStruct();
sigReader = new(innerSignature);

bool isFirst = true;
while (sigReader.TryRead(out type, out innerSignature))
{
if (!isFirst)
{
Indent(sb, indent);
}
isFirst = false;

sb.Append(ItemPrefix);
AppendValue(sb, indent + ItemPrefix.Length, ref reader, type, innerSignature);
}

addNewLine = false;
break;
case DBusType.Variant:
innerSignature = reader.ReadSignature().Span;
sigReader = new(innerSignature);
sigReader.TryRead(out type, out innerSignature);
AppendValue(sb, indent, ref reader, type, innerSignature, isDictEntryValue: isDictEntryValue);

addNewLine = false;
break;
case DBusType.DictEntry:
reader.AlignStruct();
sigReader = new(innerSignature);

sigReader.TryRead(out type, out innerSignature);
AppendValue(sb, indent, ref reader, type, innerSignature, addNewLine: false);

sb.Append(": ");

sigReader.TryRead(out type, out innerSignature);
AppendValue(sb, indent + 2 /* indent value */, ref reader, type, innerSignature, isDictEntryValue: true);

addNewLine = false;
break;
default:
throw new InvalidOperationException();
}

if (addNewLine)
{
sb.AppendLine();
}
}

private static void Indent(StringBuilder sb, int indent)
{
sb.Append(' ', indent);
}
}
1 change: 1 addition & 0 deletions src/Tmds.DBus.Tool/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public static void Main(string[] args)
commandLineApp.HelpOption(Command.HelpTemplate);
new CodeGenCommand(commandLineApp);
new ListCommand(commandLineApp);
new MonitorCommand(commandLineApp);
commandLineApp.OnExecute(() => { commandLineApp.ShowHelp(); return 0; });
commandLineApp.Execute(args);
}
Expand Down