diff --git a/BugMine.DevTools.CLI/BugMine.DevTools.CLI.csproj b/BugMine.DevTools.CLI/BugMine.DevTools.CLI.csproj
new file mode 100644
index 0000000..f07ebda
--- /dev/null
+++ b/BugMine.DevTools.CLI/BugMine.DevTools.CLI.csproj
@@ -0,0 +1,17 @@
+<Project Sdk="Microsoft.NET.Sdk.Worker">
+
+ <PropertyGroup>
+ <TargetFramework>net8.0</TargetFramework>
+ <Nullable>enable</Nullable>
+ <ImplicitUsings>enable</ImplicitUsings>
+ <UserSecretsId>dotnet-BugMine.DevTools.CLI-68C1536A-FE5E-4724-8406-B1B1430F105A</UserSecretsId>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0"/>
+ </ItemGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\BugMine.Sdk\BugMine.Sdk.csproj" />
+ </ItemGroup>
+</Project>
diff --git a/BugMine.DevTools.CLI/Program.cs b/BugMine.DevTools.CLI/Program.cs
new file mode 100644
index 0000000..6e5bead
--- /dev/null
+++ b/BugMine.DevTools.CLI/Program.cs
@@ -0,0 +1,9 @@
+using BugMine.DevTools.CLI;
+using BugMine.Web.Classes;
+
+var builder = Host.CreateApplicationBuilder(args);
+builder.Services.AddBugMine(new() { AppName = "BugMine DevTools CLI" });
+builder.Services.AddHostedService<Worker>();
+
+var host = builder.Build();
+host.Run();
\ No newline at end of file
diff --git a/BugMine.DevTools.CLI/Properties/launchSettings.json b/BugMine.DevTools.CLI/Properties/launchSettings.json
new file mode 100644
index 0000000..43460c6
--- /dev/null
+++ b/BugMine.DevTools.CLI/Properties/launchSettings.json
@@ -0,0 +1,12 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "BugMine.DevTools.CLI": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "environmentVariables": {
+ "DOTNET_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/BugMine.DevTools.CLI/Worker.cs b/BugMine.DevTools.CLI/Worker.cs
new file mode 100644
index 0000000..8cd931e
--- /dev/null
+++ b/BugMine.DevTools.CLI/Worker.cs
@@ -0,0 +1,123 @@
+using System.Text.Json;
+using ArcaneLibs.Extensions;
+using BugMine.Web.Classes;
+using LibMatrix.EventTypes.Spec.State;
+using LibMatrix.Responses;
+using LibMatrix.Services;
+
+namespace BugMine.DevTools.CLI;
+
+public class Worker(ILogger<Worker> logger, HomeserverProviderService hsProvider) : BackgroundService {
+ private readonly ILogger<Worker> _logger = logger;
+ private BugMineClient? Client { get; set; }
+
+ protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
+ if (!File.Exists("auth.json")) {
+ Console.Write("Homeserver: ");
+ var homeserver = Console.ReadLine()!;
+ Console.Write("Username: ");
+ var username = Console.ReadLine()!;
+ Console.Write("Password: ");
+ var password = Console.ReadLine()!;
+
+ var login = await hsProvider.Login(homeserver, username, password);
+ await File.WriteAllTextAsync("auth.json", login.ToJson(), stoppingToken);
+ }
+
+ var auth = await JsonSerializer.DeserializeAsync<LoginResponse>(File.OpenRead("auth.json"));
+ Client = new BugMineClient(await hsProvider.GetAuthenticatedWithToken(auth.Homeserver, auth.AccessToken, useGeneric: true));
+
+ while (!stoppingToken.IsCancellationRequested) {
+ Console.WriteLine("""
+ 1) List all projects
+ 2) Create 500 projects
+ 3) Destroy all projects
+ 4) Get room count
+ """);
+
+ var input = Console.ReadKey();
+ Console.WriteLine();
+ switch (input.Key) {
+ case ConsoleKey.D1: {
+ if (Client is null) {
+ _logger.LogError("No client available.");
+ break;
+ }
+
+ var projects = Client.GetProjects();
+ await foreach (var project in projects) {
+ Console.WriteLine(project.ToJson(indent: false));
+ }
+
+ break;
+ }
+ case ConsoleKey.D2: {
+ if (Client is null) {
+ _logger.LogError("No client available.");
+ break;
+ }
+
+ await MassCreateProjects();
+ break;
+ }
+ case ConsoleKey.D3: {
+ if (Client is null) {
+ _logger.LogError("No client available.");
+ break;
+ }
+
+ await DestroyAllProjects();
+ break;
+ }
+ case ConsoleKey.D4: {
+ if (Client is null) {
+ _logger.LogError("No client available.");
+ break;
+ }
+
+ var rooms = await Client.Homeserver.GetJoinedRooms();
+ Console.WriteLine(rooms.Count());
+ break;
+ }
+ }
+ }
+ }
+
+ private async Task DestroyAllProjects() {
+ var ss = new SemaphoreSlim(4, 4);
+ await foreach (var proj in Client.Homeserver.GetJoinedRoomsByType(null!)) {
+ if (proj.RoomId == "!UktPWOzit8gmms5FQ6:conduit.matrixunittests.rory.gay") continue;
+ Task.Run(async () => {
+ // await ss.WaitAsync();
+ await proj.SendStateEventAsync(RoomNameEventContent.EventId, new RoomNameEventContent() {
+ Name = "Disbanded BugMine project."
+ });
+ await proj.SendStateEventAsync(RoomJoinRulesEventContent.EventId, new RoomJoinRulesEventContent() {
+ JoinRule = RoomJoinRulesEventContent.JoinRules.Private
+ });
+ await proj.SendStateEventAsync(RoomCanonicalAliasEventContent.EventId, new RoomCanonicalAliasEventContent() {
+ Alias = null
+ });
+ await proj.LeaveAsync("Disbanded room.");
+ // ss.Release();
+ });
+ }
+ }
+
+ private async Task MassCreateProjects() {
+ // var rooms = await Client.Homeserver.GetJoinedRooms();
+ // List<string> roomNames = (await Task.WhenAll(rooms.Select(x => x.GetNameAsync()))).Where(x => x != null).ToList();
+ for (int i = 0; i < 500; i++) {
+ Task.Run(async () => {
+ // var randomName = roomNames[Random.Shared.Next(roomNames.Count)];
+ var proj = await Client.CreateProject(new() {
+ Name = /*randomName + */Guid.NewGuid().ToString()[..8]
+ });
+
+ // await proj.CreateIssue(new() {
+ // Name = "meow"
+ // });
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/BugMine.DevTools.CLI/appsettings.Development.json b/BugMine.DevTools.CLI/appsettings.Development.json
new file mode 100644
index 0000000..b2dcdb6
--- /dev/null
+++ b/BugMine.DevTools.CLI/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
+}
diff --git a/BugMine.DevTools.CLI/appsettings.json b/BugMine.DevTools.CLI/appsettings.json
new file mode 100644
index 0000000..b2dcdb6
--- /dev/null
+++ b/BugMine.DevTools.CLI/appsettings.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
+}
diff --git a/BugMine.DevTools.CLI/auth.json b/BugMine.DevTools.CLI/auth.json
new file mode 100644
index 0000000..e42970e
--- /dev/null
+++ b/BugMine.DevTools.CLI/auth.json
@@ -0,0 +1,6 @@
+{
+ "access_token": "wODFOcoMnoruFaUGrjWibY80sVVEqSUg",
+ "device_id": "VHX31Cw6jz",
+ "home_server": "conduit.matrixunittests.rory.gay",
+ "user_id": "@meow:conduit.matrixunittests.rory.gay"
+}
\ No newline at end of file
diff --git a/BugMine.Sdk/BugMineClient.cs b/BugMine.Sdk/BugMineClient.cs
index be80c3a..db47b85 100644
--- a/BugMine.Sdk/BugMineClient.cs
+++ b/BugMine.Sdk/BugMineClient.cs
@@ -1,15 +1,18 @@
using System.Text.RegularExpressions;
using ArcaneLibs.Extensions;
+using BugMine.Web.Classes.Exceptions;
+using LibMatrix;
using LibMatrix.Homeservers;
using LibMatrix.Responses;
+using LibMatrix.RoomTypes;
namespace BugMine.Web.Classes;
public class BugMineClient(AuthenticatedHomeserverGeneric homeserver) {
public AuthenticatedHomeserverGeneric Homeserver { get; } = homeserver;
-
+
public async IAsyncEnumerable<BugMineProject> GetProjects() {
- List<Task<BugMineProject>> tasks = [];
+ List<Task<BugMineProject>> tasks = [];
await foreach (var room in homeserver.GetJoinedRoomsByType(BugMineProject.RoomType)) {
tasks.Add(room.AsBugMineProject());
}
@@ -21,35 +24,58 @@ public class BugMineClient(AuthenticatedHomeserverGeneric homeserver) {
}
public async Task<BugMineProject> CreateProject(ProjectInfo request) {
- var alias = string.Join('_', Regex.Matches(request.Name, @"[a-zA-Z0-9]+").Select(x => x.Value))+"-bugmine";
-
+ var alias = string.Join('_', Regex.Matches(request.Name, @"[a-zA-Z0-9]+").Select(x => x.Value)) + "-bugmine";
+
var crr = new CreateRoomRequest() {
CreationContent = new() {
["type"] = "gay.rory.bugmine.project"
},
Name = $"{request.Name} (BugMine project)",
- RoomAliasName = alias
+ RoomAliasName = alias,
+ InitialState = [
+ new StateEvent() {
+ Type = "m.room.join_rules",
+ RawContent = new() {
+ ["join_rule"] = "public"
+ }
+ },
+ new StateEvent() {
+ Type = ProjectInfo.EventId,
+ TypedContent = request
+ }
+ ]
};
-
+
var response = await Homeserver.CreateRoom(crr);
- await response.SendStateEventAsync(ProjectInfo.EventId, request);
-
+ // await response.SendStateEventAsync(ProjectInfo.EventId, request);
+
return await response.AsBugMineProject();
}
public async Task<BugMineProject?> GetProject(string projectSlug) {
- if (projectSlug.StartsWith('!')) {
- var room = homeserver.GetRoom(projectSlug);
- if (room == null) return null;
+ var room = await ResolveProjectSlug(projectSlug);
+
+ if (room == null) return null;
- return await (await room.AsBugMineProject()).InitializeAsync();
+ var rooms = await Homeserver.GetJoinedRooms();
+ if (!rooms.Any(r => r.RoomId == room.RoomId)) throw new BugMineException(BugMineException.ErrorCodes.UserNotInRoom);
+
+ return await (await room.AsBugMineProject()).InitializeAsync();
+ }
+
+ public async Task<GenericRoom?> ResolveProjectSlug(string projectSlug) {
+ GenericRoom? room;
+ if (projectSlug.StartsWith('!')) {
+ room = homeserver.GetRoom(projectSlug);
}
else {
var alias = $"#{projectSlug}";
var resolveResult = await Homeserver.ResolveRoomAliasAsync(alias);
if (string.IsNullOrEmpty(resolveResult?.RoomId)) return null; //TODO: fallback to finding via joined rooms' canonical alias event?
-
- return await (await homeserver.GetRoom(resolveResult.RoomId).AsBugMineProject()).InitializeAsync();
+
+ room = homeserver.GetRoom(resolveResult.RoomId);
}
+
+ return room;
}
}
\ No newline at end of file
diff --git a/BugMine.Sdk/BugMineProject.cs b/BugMine.Sdk/BugMineProject.cs
index c90ba6e..babb680 100644
--- a/BugMine.Sdk/BugMineProject.cs
+++ b/BugMine.Sdk/BugMineProject.cs
@@ -1,4 +1,5 @@
using System.Text.Json.Nodes;
+using LibMatrix.EventTypes.Spec.State;
using LibMatrix.Homeservers;
using LibMatrix.RoomTypes;
@@ -13,27 +14,34 @@ public class BugMineProject(GenericRoom room) {
public async Task<BugMineProject> InitializeAsync() {
Info = (await Room.GetStateAsync<ProjectInfo>(ProjectInfo.EventId))!;
var alias = await room.GetCanonicalAliasAsync();
-
+
if (alias != null)
ProjectSlug = alias.Alias?[1..] ?? room.RoomId;
else ProjectSlug = room.RoomId;
-
+
return this;
}
public async Task<BugMineIssue> CreateIssue(BugMineIssueData issue) {
// add relation to room creation event
issue.RelatesTo = new() {
- EventId = (await Room.GetStateEventAsync("m.room.create")).EventId,
+ EventId = await room.GetStateEventIdAsync(RoomCreateEventContent.EventId),
RelationType = "gay.rory.bugmine.issue"
};
var eventId = await Room.SendTimelineEventAsync(BugMineIssueData.EventId, issue);
-
+
// return new BugMineIssueAccessor(Room, await Room.GetEventAsync<>(eventId));
var evt = await room.GetEventAsync(eventId.EventId);
Console.WriteLine(evt);
return new BugMineIssue(Room, evt);
}
+
+ public async IAsyncEnumerable<BugMineIssue> GetIssues() {
+ var creationEventId = await room.GetStateEventIdAsync(RoomCreateEventContent.EventId);
+ await foreach (var evt in room.GetRelatedEventsAsync(creationEventId, "gay.rory.bugmine.issue", BugMineIssueData.EventId)) {
+ yield return new BugMineIssue(Room, evt);
+ }
+ }
}
public static class ProjectRoomExtensions {
diff --git a/BugMine.Sdk/Events/State/BugMineRoomMetadata.cs b/BugMine.Sdk/Events/State/BugMineRoomMetadata.cs
new file mode 100644
index 0000000..a6686d3
--- /dev/null
+++ b/BugMine.Sdk/Events/State/BugMineRoomMetadata.cs
@@ -0,0 +1,11 @@
+using LibMatrix.EventTypes;
+
+namespace BugMine.Web.Classes;
+
+[MatrixEvent(EventName = EventId)]
+public class BugMineRoomMetadata : EventContent {
+ public const string EventId = "gay.rory.bugmine.room_metadata";
+
+ public string RoomCreationEventId { get; set; }
+
+}
\ No newline at end of file
diff --git a/BugMine.Sdk/Exceptions/BugMineException.cs b/BugMine.Sdk/Exceptions/BugMineException.cs
new file mode 100644
index 0000000..7e843b3
--- /dev/null
+++ b/BugMine.Sdk/Exceptions/BugMineException.cs
@@ -0,0 +1,23 @@
+using System.Diagnostics.CodeAnalysis;
+using LibMatrix;
+
+namespace BugMine.Web.Classes.Exceptions;
+
+public class BugMineException : MatrixException {
+ [SetsRequiredMembers]
+ public BugMineException(string errorCode, string? message = null) {
+ ErrorCode = errorCode;
+ Error = message ?? Message;
+ }
+
+ public sealed override string Message =>
+ $"{ErrorCode}: {ErrorCode switch {
+ // common
+ ErrorCodes.UserNotInRoom => "User is not in the room",
+ _ => base.Message
+ }}";
+
+ public new static class ErrorCodes {
+ public const string UserNotInRoom = "BUGMINE_USER_NOT_IN_ROOM";
+ }
+}
\ No newline at end of file
diff --git a/BugMine.Web/Classes/BugMineStorage.cs b/BugMine.Web/Classes/BugMineStorage.cs
index 73b46b5..3c838c7 100644
--- a/BugMine.Web/Classes/BugMineStorage.cs
+++ b/BugMine.Web/Classes/BugMineStorage.cs
@@ -74,7 +74,7 @@ public class BugMineStorage(
return session;
}
- public async Task<BugMineClient?> GetCurrentSessionOrNull() {
+ public async Task<BugMineClient?> GetCurrentSessionOrNull(bool navigateOnInvalid = true) {
BugMineClient? session = null;
try {
@@ -85,7 +85,7 @@ public class BugMineStorage(
if (e.ErrorCode == "M_UNKNOWN_TOKEN") {
var token = await GetCurrentToken();
logger.LogWarning("Encountered invalid token for {user} on {homeserver}", token.UserId, token.Homeserver);
- navigationManager.NavigateTo("/InvalidSession?ctx=" + token.AccessToken);
+ if (navigateOnInvalid) navigationManager.NavigateTo("/InvalidSession?ctx=" + token.AccessToken);
return null;
}
diff --git a/BugMine.Web/Components/IssueImportWorker.razor b/BugMine.Web/Components/IssueImportWorker.razor
index bc72156..b53daf7 100644
--- a/BugMine.Web/Components/IssueImportWorker.razor
+++ b/BugMine.Web/Components/IssueImportWorker.razor
@@ -15,7 +15,7 @@
private string Status { get; set; } = "";
protected override async Task OnInitializedAsync() {
while(Client == null) {
- Client = await BugMineStorage.GetCurrentSessionOrNull();
+ Client = await BugMineStorage.GetCurrentSessionOrNull(false);
if(Client == null) {
await Task.Delay(1000);
}
diff --git a/BugMine.Web/Pages/Auth/LegacyLogin.razor b/BugMine.Web/Pages/Auth/LegacyLogin.razor
index 5257028..eec381a 100644
--- a/BugMine.Web/Pages/Auth/LegacyLogin.razor
+++ b/BugMine.Web/Pages/Auth/LegacyLogin.razor
@@ -23,7 +23,7 @@
<br/>
<LinkButton OnClick="@(() => LoginWithAuth(authData))">Log in</LinkButton>
-<h4>Continue as guest</h4>
+<h4>Continue as guest (doesn't work)</h4>
<hr/>
<LinkButton OnClick="@(() => LoginWithAuth(new LoginStruct { Homeserver = "matrix.org", Username = "guest", Password = "guest" }))">Log in as guest</LinkButton>
diff --git a/BugMine.Web/Pages/Auth/Login.razor b/BugMine.Web/Pages/Auth/Login.razor
index 7b457ec..bea449e 100644
--- a/BugMine.Web/Pages/Auth/Login.razor
+++ b/BugMine.Web/Pages/Auth/Login.razor
@@ -61,7 +61,6 @@
Homeserver = await hsProvider.GetRemoteHomeserver(HomeserverName);
CurrentStage = await Homeserver.Auth.GetAvailableFlowsAsync(enableRegister: true, enableGuest: true);
-
StateHasChanged();
}
diff --git a/BugMine.Web/Pages/DevTools.razor b/BugMine.Web/Pages/DevTools.razor
index f8fc408..afed0cc 100644
--- a/BugMine.Web/Pages/DevTools.razor
+++ b/BugMine.Web/Pages/DevTools.razor
@@ -15,10 +15,10 @@
}
private async Task DestroyAllProjects() {
- var ss = new SemaphoreSlim(16, 16);
+ var ss = new SemaphoreSlim(4, 4);
await foreach (var proj in Client.Homeserver.GetJoinedRoomsByType(BugMineProject.RoomType)) {
- Task.Run(async () => {
- await ss.WaitAsync();
+ // Task.Run(async () => {
+ // await ss.WaitAsync();
await proj.SendStateEventAsync(RoomNameEventContent.EventId, new RoomNameEventContent() {
Name = "Disbanded BugMine project."
});
@@ -29,15 +29,15 @@
Alias = null
});
await proj.LeaveAsync("Disbanded room.");
- ss.Release();
- });
+ // ss.Release();
+ // });
}
}
private async Task MassCreateProjects() {
// var rooms = await Client.Homeserver.GetJoinedRooms();
// List<string> roomNames = (await Task.WhenAll(rooms.Select(x => x.GetNameAsync()))).Where(x => x != null).ToList();
- for (int i = 0; i < 5; i++) {
+ for (int i = 0; i < 20; i++) {
Task.Run(async () => {
// var randomName = roomNames[Random.Shared.Next(roomNames.Count)];
var proj = await Client.CreateProject(new() {
diff --git a/BugMine.Web/Pages/Projects/Index.razor b/BugMine.Web/Pages/Projects/Index.razor
index eaf8dc1..47c2f4a 100644
--- a/BugMine.Web/Pages/Projects/Index.razor
+++ b/BugMine.Web/Pages/Projects/Index.razor
@@ -2,7 +2,13 @@
@using LibMatrix.Homeservers
<h3>Projects</h3>
-@if (Projects.Count == 0) {
+@if (Client == null) {
+ <p>Authenticating... <SimpleSpinner/></p>
+}
+else if (Projects is null) {
+ <p>Loading projects... <SimpleSpinner/></p>
+}
+else if (Projects.Count == 0) {
<p>There are no projects to display.</p>
}
else {
@@ -28,7 +34,7 @@ else {
@code {
private BugMineClient? Client { get; set; }
- private List<BugMineProject> Projects { get; set; } = [];
+ private List<BugMineProject>? Projects { get; set; }
private CancellationTokenSource? _cts = new();
protected override async Task OnInitializedAsync() {
@@ -36,12 +42,17 @@ else {
if (Client == null) {
return;
}
-
+ StateHasChanged();
+
await foreach (var project in Client.GetProjects()) {
+ Projects ??= [];
Projects.Add(project);
StateHasChanged();
// await Task.Delay(100);
}
+
+ Projects ??= [];
+ StateHasChanged();
}
private async Task Navigate(BugMineProject project) {
diff --git a/BugMine.Web/Pages/Projects/ViewProject.razor b/BugMine.Web/Pages/Projects/ViewProject.razor
index de94c79..a778728 100644
--- a/BugMine.Web/Pages/Projects/ViewProject.razor
+++ b/BugMine.Web/Pages/Projects/ViewProject.razor
@@ -1,33 +1,114 @@
@page "/Projects/{ProjectSlug}/"
+@using LibMatrix
+@using BugMine.Web.Classes.Exceptions
<ProgressLog ></ProgressLog>
@if (Client is null) {
<p>Authenticating</p>
}
-else if(Project is null) {
- <p>Loading</p>
+else if (Project is null) {
+ @if (Progress == "loading") {
+ <p>Loading project <SimpleSpinner/></p>
+ }
+ else if (Progress == "not-in-room") {
+ <p>You are not in the project room.</p>
+ <p>You must join before you can view or interact with this project.</p>
+ <LinkButton OnClick="TryJoin">Attempt to join</LinkButton>
+ }
}
else {
<h1>@Project.Info.Name</h1>
+
+ @if (Constants.Debug) {
+ <p>Debug, beware: here be dragons!</p>
+ <LinkButton OnClick="@Project.Room.PermanentlyBrickRoomAsync">Dispose room</LinkButton>
+ }
+
+ @if (Progress == "loading-issues") {
+ <p>Loading issues, got @(Issues?.Count ?? 0) so far... <SimpleSpinner/></p>
+ }
@* <p>@Project.Description</p> *@
}
@code {
- [Parameter] public string ProjectSlug { get; set; }
-
+ private string? _progress = "loading";
+
+ [Parameter]
+ public string ProjectSlug { get; set; } = null!;
+
private BugMineClient? Client { get; set; }
private BugMineProject? Project { get; set; }
+
+ private List<BugMineIssue>? Issues { get; set; }
+
+ private string? Progress {
+ get => _progress;
+ set {
+ _progress = value;
+ StateHasChanged();
+ }
+ }
protected override async Task OnInitializedAsync() {
- Client = await BugMineStorage.GetCurrentSessionOrNavigate();
+ Client ??= await BugMineStorage.GetCurrentSessionOrNavigate();
if (Client == null) {
return;
}
+
+ Progress = "loading";
StateHasChanged();
+
+ try {
+ Project = await Client.GetProject(ProjectSlug);
+ }
+ catch (MatrixException e) {
+ if (e.ErrorCode == BugMineException.ErrorCodes.UserNotInRoom) {
+ Progress = "not-in-room";
+ StateHasChanged();
+ return;
+ }
+
+ throw;
+ }
- Project = await Client.GetProject(ProjectSlug);
+ Progress = "loading-issues";
+ await foreach (var issue in Project.GetIssues()) {
+ Issues ??= new List<BugMineIssue>();
+ Issues.Add(issue);
+ StateHasChanged();
+ }
+
+
+ StateHasChanged();
}
-}
\ No newline at end of file
+ private async Task TryJoin() {
+ var room = await Client.ResolveProjectSlug(ProjectSlug);
+ bool success = false;
+ while (!success) {
+ try {
+ await room.JoinAsync();
+ if (!string.IsNullOrWhiteSpace(room.RoomId)) {
+ success = true;
+ }
+ else {
+ await Task.Delay(1000);
+ }
+ }
+ catch (MatrixException e) {
+ // if (e.ErrorCode == MatrixException.ErrorCodes.) {
+ // await Task.Delay(1000);
+ // continue;
+ // }
+
+ throw;
+ }
+ }
+
+ await OnInitializedAsync();
+ }
+
+}
+
diff --git a/BugMine.sln b/BugMine.sln
index 5ad7b35..c6b4a4b 100644
--- a/BugMine.sln
+++ b/BugMine.sln
@@ -16,6 +16,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BugMine.Web", "BugMine.Web\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BugMine.Sdk", "BugMine.Sdk\BugMine.Sdk.csproj", "{EC02CDCE-8DDD-42AF-80AE-92A15A9B5AC4}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BugMine.DevTools.CLI", "BugMine.DevTools.CLI\BugMine.DevTools.CLI.csproj", "{E4E398A6-98CE-4B78-9E80-42A03765CE07}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -42,6 +44,10 @@ Global
{EC02CDCE-8DDD-42AF-80AE-92A15A9B5AC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC02CDCE-8DDD-42AF-80AE-92A15A9B5AC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC02CDCE-8DDD-42AF-80AE-92A15A9B5AC4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E4E398A6-98CE-4B78-9E80-42A03765CE07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E4E398A6-98CE-4B78-9E80-42A03765CE07}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E4E398A6-98CE-4B78-9E80-42A03765CE07}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E4E398A6-98CE-4B78-9E80-42A03765CE07}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{F4E241C3-0300-4B87-8707-BCBDEF1F0185} = {8F4F6BEC-0C66-486B-A21A-1C35B2EDAD33}
diff --git a/LibMatrix b/LibMatrix
-Subproject 440807e02393410327cd86d5ffa007dee98f895
+Subproject 5ca0a45606ad2ca7e1ca45a3b27be08e9640dd9
|