Skip to content

Commit

Permalink
Reorganisation
Browse files Browse the repository at this point in the history
  • Loading branch information
Greenscreener committed Jul 23, 2024
1 parent 9c76f67 commit 58aa429
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 38 deletions.
17 changes: 17 additions & 0 deletions Errors.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}

9 changes: 9 additions & 0 deletions MatrixApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ namespace matrix_dotnet;

using Refit;

/// <summary>
/// The IMatrixApi interface represents API endpoints directly and its implementation gets generated by Refit.
/// </summary>
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);

/// <summary>The return value of the <see cref="Login"/> function.</summary>
public record LoginResponse(
string access_token,
string device_id,
Expand All @@ -19,6 +24,7 @@ public record LoginResponse(
string user_id
);

/// <summary><see cref="Login"/></summary>
public abstract record LoginRequest(
string type,
Identifier identifier,
Expand All @@ -29,6 +35,7 @@ public abstract record LoginRequest(
bool refresh_token = true
);

/// <summary><see cref="Login"/></summary>
public record PasswordLoginRequest(
Identifier identifier,
string password,
Expand All @@ -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);

/// <summary><see cref="Login"/></summary>
public record TokenLoginRequest(
Identifier identifier,
string token,
Expand Down Expand Up @@ -67,3 +75,4 @@ public record SendEventResponse(string event_id);
[Headers("Authorization: Bearer")]
public Task<SendEventResponse> SendEvent<T>(string roomId, string eventType, string txnId, T body);
}

49 changes: 11 additions & 38 deletions MatrixClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> 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<TResult> RetryAsync<TResult>(Func<Task<TResult>> func) {
retry:
try {
return await func();
} catch (RetryException) {
goto retry;
}
}

private async Task<Exception?> ExceptionFactory(HttpResponseMessage response) {
if (response.IsSuccessStatusCode) return null;

var errorResponse = JsonSerializer.Deserialize<ErrorResponse>(await response.Content.ReadAsStringAsync());
var errorResponse = JsonSerializer.Deserialize<IMatrixApi.ErrorResponse>(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;
Expand All @@ -79,7 +51,7 @@ private static async Task<TResult> RetryAsync<TResult>(Func<Task<TResult>> func)
}
}

return new ApiError(errorResponse.errcode, errorResponse.error, response, null);
return new MatrixApiError(errorResponse.errcode, errorResponse.error, response, null);
}

return await ApiException.Create(
Expand Down Expand Up @@ -119,6 +91,11 @@ public MatrixClient(Uri homeserver, ILogger? logger = null) {
Api = RestService.For<IMatrixApi>(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);

Expand All @@ -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);

Expand All @@ -157,8 +129,9 @@ public async Task Refresh() {
UpdateExpiresAt(response.expires_in_ms);
}


public async Task<string[]> GetJoinedRooms() {
var response = await RetryAsync(async () => await Api.GetJoinedRooms());
var response = await Retry.RetryAsync(async () => await Api.GetJoinedRooms());

return response.joined_rooms;
}
Expand All @@ -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<string> SendMessage<TMessage>(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;
}
Expand Down
15 changes: 15 additions & 0 deletions Util.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace matrix_dotnet;

class Retry {
public class RetryException : Exception {}

public static async Task<TResult> RetryAsync<TResult>(Func<Task<TResult>> func) {
retry:
try {
return await func();
} catch (RetryException) {
goto retry;
}
}
}

0 comments on commit 58aa429

Please sign in to comment.