matrix_csharp 1.0.1

dotnet add package matrix_csharp --version 1.0.1
                    
NuGet\Install-Package matrix_csharp -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="matrix_csharp" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="matrix_csharp" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="matrix_csharp" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add matrix_csharp --version 1.0.1
                    
#r "nuget: matrix_csharp, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package matrix_csharp@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=matrix_csharp&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=matrix_csharp&version=1.0.1
                    
Install as a Cake Tool

matrix-dotnet

matrix-dotnet is a ✨modern✨ C# library for the matrix protocol focused on code brevity. It features a two-layered approach with a Refit-based raw API interface and a fully featured client class. Modern language features (like the goto keyword) are used to make the code readable and succinct. Also we indent with tabs.

Installation

NuGet

There is a NuGet package you can install by with dotnet:

dotnet add package matrix_csharp

Submodule

You can also add this library as a git submodule:

git submodule add https://gitlab.com/Greenscreener/matrix-dotnet

and then add a reference to your csproj file:

dotnet add reference ../matrix-dotnet/matrix-dotnet.csproj

Preface

It is highly recommended to consult relevant parts of the Matrix Specification when working with this library as many design decisions follow the specification's rationale.

Usage

You start by initializing the MatrixClient:

using matrix_dotnet.Client;

var client = new MatrixClient("https://example.com");
await client.PasswordLogin(Secrets.username, Secrets.password, initialDeviceDisplayName: "FreeReal development");

After that, the client will receive an access token and an optional refresh token. The client does not keep your password. Each time the short-lived access token expires, it will be automatically refreshed using the long-lived refresh token. The login API is rate limited, so you might want to store the access and refresh tokens somewhere externally, if you need to run your program many times.

using (FileStream stream = File.Create("client.json")) {
	await JsonSerializer.SerializeAsync(stream, client.ToLoginData());
}

And afterwards:

matrix_dotnet.Client.LoginData? loginData = null;
using (FileStream stream = File.OpenRead("client.json")) {
	loginData = await JsonSerializer.DeserializeAsync<matrix_dotnet.Client.LoginData>(stream);
};

MatrixClient? client = new MatrixClient(loginData.Value);

Using this technique, you will also be able to keep the same device_id. If you don't, you will add a new device to the users logged-in devices each time you login. Logging in with a password each time is discouraged.

Receiving messages

First, you should start by calling the Sync method:

await client.Sync();

This calls the server's /sync endpoint to establish basic information about all rooms. To get messages for a room, you can just fetch them directly from its Timeline:

var roomTimeline = client.JoinedRooms[new RoomID("<room_id>")].timeline;
await foreach (var timelineEvent in roomTimeline.First.EnumerateForward()) {
	EventWithState ev = timelineEvent.Value;
	if (ev.Event.content is Message message)
		Console.WriteLine($"{ev.GetSender()?.displayname ?? ev.Event.sender}: {message.body}");
}

The Timeline is a linked list (you'll see why in a bit). The values are Events with state. In matrix, rooms have state that can change as the room evolves. This state for instance contains user's display names, which can change dynamically. The client automatically resolves this state and attaches the correct state dictionary to each event, so if a user in the example above changes their displayname mid-conversation, the shown displayname will change accordingly.

Now, the Timeline is incomplete, in the beginning, it only contains events received from the Sync call (usually around 10). The Timeline.First property doesn't give you the first ever event in the room, but the first currently cached one. To get earlier events, you want to use await Timeline.First.Previous(). This is an asynchronous method and will automatically fetch more events when needed, so it can be used to iterate through the entire history of the room. This is also true for .Next() and .EnumerateFroward() and .EnumerateBackward(). If this is not desired, .NextOffline() and other -Offline() methods are available. In most cases however, you don't want to use them as syncing might cause holes in the timeline, which the async methods automatically fill in.

To get new messages, you should call the Sync method again. If you supply the optional timeout argument, the server will wait for the specified time before responding. If however a new event arrives, it will respond immediately with the new event.

The following code can be used to display new messages as they arrive:

while (true) {
	if ((await lastSeen?.Next()) is not null) {
		await foreach (var timelineEvent in (await lastSeen.Next()).EnumerateForward()) {
			EventWithState ev = timelineEvent.Value;
			if (ev.Event.content is Message message)
				Console.WriteLine($"{ev.GetSender()?.displayname ?? ev.Event.sender}: {message.body}");
			lastSeen = timelineEvent;
		}
	}
	await client.Sync(30000); // Wait for at most 30 seconds or return immediately if new events are received.
}

It is highly recommended to read the Syncing section of the Matrix Specification as it clearly explains most of what was mentioned above.

Sending messages

Sending messages is much simpler, you can just use the following method:

var id = await client.SendTextMessage(client.JoinedRooms.Keys.First(), "Hello World!");

See in-code documentation for usage of other MatrixClient methods.

Advanced usage

You can call API endpoints directly using the MatrixClient.ApiClient property. This gives you access to the Refit-generated API client.

Contributing

The library is very incomplete so far, and somewhat on purpose. A lot of functionality can be added just by adding more event types. If you need anything not-yet supported, feel free to add it to the Api/EventContent.cs file. I'll be glad to help with any contributions so even unfinished pull requests are very welcome.

Known issues, missing features

  • event relationships and all related APIs are not implemented
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 351 8/16/2024
1.0.0 182 8/16/2024