mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-17 11:37:59 +00:00
Migrated the entire boot sequence to use the runtime API server
This commit is contained in:
4 files changed
+232
-68
No files matched your search
@@ -11,7 +11,15 @@ using System.Reflection;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
#endif
|
||||
|
||||
var port = args.Length > 0 ? args[0] : "5000";
|
||||
var rustApiPort = args.Length > 0 ? args[0] : "5000";
|
||||
using var rust = new Rust(rustApiPort);
|
||||
var appPort = await rust.GetAppPort();
|
||||
if(appPort == 0)
|
||||
{
|
||||
Console.WriteLine("Failed to get the app port from Rust.");
|
||||
return;
|
||||
}
|
||||
|
||||
var builder = WebApplication.CreateBuilder();
|
||||
builder.Services.AddMudServices(config =>
|
||||
{
|
||||
@@ -27,7 +35,7 @@ builder.Services.AddMudServices(config =>
|
||||
|
||||
builder.Services.AddMudMarkdownServices();
|
||||
builder.Services.AddSingleton(MessageBus.INSTANCE);
|
||||
builder.Services.AddSingleton<Rust>();
|
||||
builder.Services.AddSingleton(rust);
|
||||
builder.Services.AddMudMarkdownClipboardService<MarkdownClipboardService>();
|
||||
builder.Services.AddSingleton<SettingsManager>();
|
||||
builder.Services.AddSingleton<ThreadSafeRandom>();
|
||||
@@ -46,10 +54,10 @@ builder.Services.AddRazorComponents()
|
||||
|
||||
builder.Services.AddSingleton(new HttpClient
|
||||
{
|
||||
BaseAddress = new Uri($"http://localhost:{port}")
|
||||
BaseAddress = new Uri($"http://localhost:{appPort}")
|
||||
});
|
||||
|
||||
builder.WebHost.UseUrls($"http://localhost:{port}");
|
||||
builder.WebHost.UseUrls($"http://localhost:{appPort}");
|
||||
|
||||
#if DEBUG
|
||||
builder.WebHost.UseWebRoot("wwwroot");
|
||||
@@ -79,5 +87,5 @@ app.MapRazorComponents<App>()
|
||||
|
||||
var serverTask = app.RunAsync();
|
||||
|
||||
Console.WriteLine("RUST/TAURI SERVER STARTED");
|
||||
await rust.AppIsReady();
|
||||
await serverTask;
|
||||
@@ -3,8 +3,65 @@ namespace AIStudio.Tools;
|
||||
/// <summary>
|
||||
/// Calling Rust functions.
|
||||
/// </summary>
|
||||
public sealed class Rust
|
||||
public sealed class Rust(string apiPort) : IDisposable
|
||||
{
|
||||
private readonly HttpClient http = new()
|
||||
{
|
||||
BaseAddress = new Uri($"http://127.0.0.1:{apiPort}"),
|
||||
};
|
||||
|
||||
public async Task<int> GetAppPort()
|
||||
{
|
||||
Console.WriteLine("Trying to get app port from Rust runtime...");
|
||||
|
||||
//
|
||||
// Note I: In the production environment, the Rust runtime is already running
|
||||
// and listening on the given port. In the development environment, the IDE
|
||||
// starts the Rust runtime in parallel with the .NET runtime. Since the
|
||||
// Rust runtime needs some time to start, we have to wait for it to be ready.
|
||||
//
|
||||
const int MAX_TRIES = 160;
|
||||
var tris = 0;
|
||||
var wait4Try = TimeSpan.FromMilliseconds(250);
|
||||
var url = new Uri($"http://127.0.0.1:{apiPort}/system/dotnet/port");
|
||||
while (tris++ < MAX_TRIES)
|
||||
{
|
||||
//
|
||||
// Note II: We use a new HttpClient instance for each try to avoid
|
||||
// .NET is caching the result. When we use the same HttpClient
|
||||
// instance, we would always get the same result (403 forbidden),
|
||||
// without even trying to connect to the Rust server.
|
||||
//
|
||||
using var initialHttp = new HttpClient();
|
||||
var response = await initialHttp.GetAsync(url);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
Console.WriteLine($" Try {tris}/{MAX_TRIES}");
|
||||
await Task.Delay(wait4Try);
|
||||
continue;
|
||||
}
|
||||
|
||||
var appPortContent = await response.Content.ReadAsStringAsync();
|
||||
var appPort = int.Parse(appPortContent);
|
||||
Console.WriteLine($" Received app port from Rust runtime: '{appPort}'");
|
||||
return appPort;
|
||||
}
|
||||
|
||||
Console.WriteLine("Failed to receive the app port from Rust runtime.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task AppIsReady()
|
||||
{
|
||||
const string URL = "/system/dotnet/ready";
|
||||
Console.WriteLine($"Notifying Rust runtime that the app is ready.");
|
||||
var response = await this.http.PostAsync(URL, new StringContent(string.Empty));
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
Console.WriteLine($"Failed to notify Rust runtime that the app is ready: '{response.StatusCode}'");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to copy the given text to the clipboard.
|
||||
/// </summary>
|
||||
@@ -51,4 +108,13 @@ public sealed class Rust
|
||||
var cts = new CancellationTokenSource();
|
||||
await jsRuntime.InvokeVoidAsync("window.__TAURI__.invoke", cts.Token, "install_update");
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.http.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in new issue
Block a user