diff --git a/Errors.cs b/Errors.cs
new file mode 100644
index 0000000..50d27d1
--- /dev/null
+++ b/Errors.cs
@@ -0,0 +1,17 @@
+namespace matrix_dotnet;
+
+public class LoginRequiredException : UnauthorizedAccessException { }
+
+public class MatrixApiError : Exception {
+ public string ErrorCode { get; }
+ public string ErrorMessage { get; }
+ public HttpResponseMessage Response { get; }
+
+ public MatrixApiError(string errorCode, string errorMessage, HttpResponseMessage response, Exception? innerException)
+ : base(String.Format("Request to Matrix API failed: {0}: {1}", errorCode, errorMessage), innerException) {
+ ErrorCode = errorCode;
+ ErrorMessage = errorMessage;
+ Response = response;
+ }
+}
+
diff --git a/MatrixApi.cs b/MatrixApi.cs
index 32dd060..7ce4199 100644
--- a/MatrixApi.cs
+++ b/MatrixApi.cs
@@ -2,13 +2,18 @@ namespace matrix_dotnet;
using Refit;
+///
+/// The IMatrixApi interface represents API endpoints directly and its implementation gets generated by Refit.
+///
public interface IMatrixApi {
+ public record ErrorResponse(string errcode, string error, bool? soft_logout = null);
public abstract record Identifier(string Type, string? User = null, string? Country = null, string? Phone = null, string? Medium = null, string? Address = null);
public record UserIdentifier(string user) : Identifier("m.id.user", User: user);
public record PhoneIdentifier(string country, string phone) : Identifier("m.id.phone", Country: country, Phone: phone);
public record ThirdpartyIdentifier(string medium, string address) : Identifier("m.id.thirdparty", Medium: medium, Address: address);
+ /// The return value of the function.
public record LoginResponse(
string access_token,
string device_id,
@@ -19,6 +24,7 @@ public record LoginResponse(
string user_id
);
+ ///
public abstract record LoginRequest(
string type,
Identifier identifier,
@@ -29,6 +35,7 @@ public abstract record LoginRequest(
bool refresh_token = true
);
+ ///
public record PasswordLoginRequest(
Identifier identifier,
string password,
@@ -37,6 +44,7 @@ public record PasswordLoginRequest(
bool refresh_token = true
) : LoginRequest("m.login.password", identifier, password, null, initial_device_display_name, device_id, refresh_token);
+ ///
public record TokenLoginRequest(
Identifier identifier,
string token,
@@ -67,3 +75,4 @@ public record SendEventResponse(string event_id);
[Headers("Authorization: Bearer")]
public Task SendEvent(string roomId, string eventType, string txnId, T body);
}
+
diff --git a/MatrixClient.cs b/MatrixClient.cs
index 5e0f3ae..a4a9907 100644
--- a/MatrixClient.cs
+++ b/MatrixClient.cs
@@ -26,51 +26,23 @@ public bool Expired {
get => AccessToken is not null && ExpiresAt is not null && ExpiresAt < DateTime.Now;
}
- public class LoginRequiredException : UnauthorizedAccessException { }
-
private async Task GetAccessToken(HttpRequestMessage request, CancellationToken ct) {
if (!LoggedIn) throw new LoginRequiredException();
if (Expired) await Refresh();
return AccessToken!;
}
- public record ErrorResponse(string errcode, string error, bool? soft_logout = null);
-
- public class ApiError : Exception {
- public string ErrorCode { get; }
- public string ErrorMessage { get; }
- public HttpResponseMessage Response { get; }
-
- public ApiError(string errorCode, string errorMessage, HttpResponseMessage response, Exception? innerException)
- : base(String.Format("Request to Matrix API failed: {0}: {1}", errorCode, errorMessage), innerException) {
- ErrorCode = errorCode;
- ErrorMessage = errorMessage;
- Response = response;
- }
- }
-
private RefitSettings RefitSettings;
- private class RetryException : Exception { }
-
- private static async Task RetryAsync(Func> func) {
- retry:
- try {
- return await func();
- } catch (RetryException) {
- goto retry;
- }
- }
-
private async Task ExceptionFactory(HttpResponseMessage response) {
if (response.IsSuccessStatusCode) return null;
- var errorResponse = JsonSerializer.Deserialize(await response.Content.ReadAsStringAsync());
+ var errorResponse = JsonSerializer.Deserialize(await response.Content.ReadAsStringAsync());
if (errorResponse is not null) {
if (errorResponse.errcode == "M_UNKNOWN_TOKEN") {
if (errorResponse.soft_logout is not null && errorResponse.soft_logout!.Value) {
await Refresh();
- return new RetryException();
+ return new Retry.RetryException();
} else {
AccessToken = null;
RefreshToken = null;
@@ -79,7 +51,7 @@ private static async Task RetryAsync(Func> func)
}
}
- return new ApiError(errorResponse.errcode, errorResponse.error, response, null);
+ return new MatrixApiError(errorResponse.errcode, errorResponse.error, response, null);
}
return await ApiException.Create(
@@ -119,6 +91,11 @@ public MatrixClient(Uri homeserver, ILogger? logger = null) {
Api = RestService.For(apiUrlB.Uri.ToString(), RefitSettings);
}
+ private void UpdateExpiresAt(int? expiresInMs) {
+ if (expiresInMs is null) ExpiresAt = null;
+ else ExpiresAt = DateTime.Now.AddMilliseconds((double)expiresInMs);
+ }
+
private async Task Login(IMatrixApi.LoginRequest request) {
var response = await Api.Login(request);
@@ -129,11 +106,6 @@ private async Task Login(IMatrixApi.LoginRequest request) {
UpdateExpiresAt(response.expires_in_ms);
}
- private void UpdateExpiresAt(int? expiresInMs) {
- if (expiresInMs is null) ExpiresAt = null;
- else ExpiresAt = DateTime.Now.AddMilliseconds((double)expiresInMs);
- }
-
public async Task PasswordLogin(string username, string password, string? initialDeviceDisplayName = null, string? deviceId = null)
=> await PasswordLogin(new IMatrixApi.UserIdentifier(username), password, initialDeviceDisplayName, deviceId);
@@ -157,8 +129,9 @@ public async Task Refresh() {
UpdateExpiresAt(response.expires_in_ms);
}
+
public async Task GetJoinedRooms() {
- var response = await RetryAsync(async () => await Api.GetJoinedRooms());
+ var response = await Retry.RetryAsync(async () => await Api.GetJoinedRooms());
return response.joined_rooms;
}
@@ -167,7 +140,7 @@ public abstract record Message(string body, string msgtype);
public record TextMessage(string body) : Message(body: body, msgtype: "m.text");
public async Task SendMessage(string roomId, TMessage message) where TMessage : Message {
- var response = await RetryAsync(async () => await Api.SendEvent(roomId, "m.room.message", GenerateTransactionId(), message));
+ var response = await Retry.RetryAsync(async () => await Api.SendEvent(roomId, "m.room.message", GenerateTransactionId(), message));
return response.event_id;
}
diff --git a/Util.cs b/Util.cs
new file mode 100644
index 0000000..bf26fdf
--- /dev/null
+++ b/Util.cs
@@ -0,0 +1,15 @@
+namespace matrix_dotnet;
+
+class Retry {
+ public class RetryException : Exception {}
+
+ public static async Task RetryAsync(Func> func) {
+ retry:
+ try {
+ return await func();
+ } catch (RetryException) {
+ goto retry;
+ }
+ }
+}
+