Skip to content

Commit

Permalink
start server on app startup, navigate to url on app start
Browse files Browse the repository at this point in the history
  • Loading branch information
hahn-kev committed Jul 17, 2024
1 parent b538efe commit 7693869
Show file tree
Hide file tree
Showing 11 changed files with 199 additions and 128 deletions.
4 changes: 2 additions & 2 deletions backend/FwLite/FwLiteDesktop/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

public partial class App : Application
{
public App()
public App(MainPage mainPage)
{
InitializeComponent();

MainPage = new AppShell();
MainPage = mainPage;
}
}
15 changes: 0 additions & 15 deletions backend/FwLite/FwLiteDesktop/AppShell.xaml

This file was deleted.

9 changes: 0 additions & 9 deletions backend/FwLite/FwLiteDesktop/AppShell.xaml.cs

This file was deleted.

10 changes: 2 additions & 8 deletions backend/FwLite/FwLiteDesktop/MainPage.xaml
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="FwLiteDesktop.MainPage">

<ScrollView>
<VerticalStackLayout
Padding="30,0"
Spacing="25">
<WebView Source=""/>
</VerticalStackLayout>
</ScrollView>
<WebView x:Name="webView"/>

</ContentPage>
11 changes: 9 additions & 2 deletions backend/FwLite/FwLiteDesktop/MainPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
namespace FwLiteDesktop;
using Microsoft.Extensions.Options;

namespace FwLiteDesktop;

public partial class MainPage : ContentPage
{
public MainPage()
public MainPage(IOptionsMonitor<LocalWebAppConfig> options)
{
InitializeComponent();
options.OnChange(o =>
{
webView.Dispatcher.Dispatch(() => webView.Source = o.Url);
});
webView.Source = options.CurrentValue.Url;
}
}

20 changes: 13 additions & 7 deletions backend/FwLite/FwLiteDesktop/MauiProgram.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
using Microsoft.Extensions.Logging;
using FwLiteDesktop.ServerBridge;
using LocalWebApp;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Maui.LifecycleEvents;

namespace FwLiteDesktop;

Expand All @@ -15,17 +19,19 @@ public static MauiApp CreateMauiApp()
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});

builder.Services.AddSingleton<MainPage>();

builder.Services.AddOptions<LocalWebAppConfig>().Configure(config =>
{
config.Url = "http://localhost:5000";
}
);
var serverManager = new ServerManager();
builder.Services.AddSingleton(serverManager);
builder.Configuration.Add<ServerConfigSource>(source => source.ServerManager = serverManager);
builder.Services.AddOptions<LocalWebAppConfig>().BindConfiguration("LocalWebApp");

#if DEBUG
builder.Logging.AddDebug();
#endif

return builder.Build();
var app = builder.Build();
app.Services.GetRequiredService<ServerManager>().Start();
return app;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"Run": {
"commandName": "Project",
"environmentVariables": {
"COREHOST_TRACE": "1"
"COREHOST_TRACE": "0"
}
},
"Windows Machine": {
Expand Down
32 changes: 32 additions & 0 deletions backend/FwLite/FwLiteDesktop/ServerBridge/ServerConfigProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Microsoft.Extensions.Configuration;

namespace FwLiteDesktop.ServerBridge;

public class ServerConfigSource: IConfigurationSource
{
public ServerManager? ServerManager { get; set; }

public IConfigurationProvider Build(IConfigurationBuilder builder)
{
if (ServerManager is null)
throw new InvalidOperationException("ServerManager is not set");
return new ServerConfigProvider(ServerManager);
}
}

public class ServerConfigProvider : ConfigurationProvider
{
public ServerConfigProvider(ServerManager serverManager)
{
_ = serverManager.Started.ContinueWith(t =>
{
Data = new Dictionary<string, string?> { ["LocalWebApp:Url"] = t.Result.Urls.First() };
OnReload();
},
scheduler: TaskScheduler.Default);
}

public override void Load()
{
}
}
38 changes: 38 additions & 0 deletions backend/FwLite/FwLiteDesktop/ServerBridge/ServerManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using LocalWebApp;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Hosting;

namespace FwLiteDesktop;

public class ServerManager : IAsyncDisposable
{
private readonly TaskCompletionSource<WebApplication> _started = new();
public Task<WebApplication> Started => _started.Task;
private WebApplication? _webApp;

public void Start()
{
_webApp = LocalWebAppServer.SetupAppServer([]);
_ = Task.Run(async () =>
{
try
{
await _webApp.StartAsync();
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}

_started.SetResult(_webApp);
});
}

public async ValueTask DisposeAsync()
{
if (_webApp is null) return;
await _webApp.StopAsync(TimeSpan.FromSeconds(10));
await _webApp.DisposeAsync();
}
}
100 changes: 100 additions & 0 deletions backend/FwLite/LocalWebApp/LocalWebAppServer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#if !DISABLE_FW_BRIDGE
using FwDataMiniLcmBridge;
using FwDataMiniLcmBridge.LcmUtils;
#endif
using LcmCrdt;
using LocalWebApp;
using LocalWebApp.Hubs;
using LocalWebApp.Auth;
using LocalWebApp.Routes;
using LocalWebApp.Utils;
using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.StaticFiles.Infrastructure;
using Microsoft.Extensions.FileProviders;

namespace LocalWebApp;

public static class LocalWebAppServer
{
public static WebApplication SetupAppServer(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
if (!builder.Environment.IsDevelopment())
builder.WebHost.UseUrls("http://127.0.0.1:0");
if (builder.Environment.IsDevelopment())
{
#if !DISABLE_FW_BRIDGE
//do this early so we catch bugs on startup
ProjectLoader.Init();
#endif
}

builder.ConfigureDev<AuthConfig>(config =>
config.DefaultAuthority = new("https://lexbox.dev.languagetechnology.org"));
//for now prod builds will also use lt dev until we deploy oauth to prod
builder.ConfigureProd<AuthConfig>(config =>
config.DefaultAuthority = new("https://lexbox.dev.languagetechnology.org"));
builder.Services.Configure<AuthConfig>(c => c.ClientId = "becf2856-0690-434b-b192-a4032b72067f");

builder.Services.AddLocalAppServices(builder.Environment);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSignalR(options =>
{
options.AddFilter(new LockedProjectFilter());
options.EnableDetailedErrors = true;
}).AddJsonProtocol();

var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

//configure dotnet to serve static files from the embedded resources
var sharedOptions =
new SharedOptions() { FileProvider = new ManifestEmbeddedFileProvider(typeof(Program).Assembly) };
app.UseDefaultFiles(new DefaultFilesOptions(sharedOptions));
var staticFileOptions = new StaticFileOptions(sharedOptions);
app.UseStaticFiles(staticFileOptions);

app.Use(async (context, next) =>
{
var projectName = context.GetProjectName();
if (!string.IsNullOrWhiteSpace(projectName))
{
var projectsService = context.RequestServices.GetRequiredService<ProjectsService>();
projectsService.SetProjectScope(projectsService.GetProject(projectName) ??
throw new InvalidOperationException(
$"Project {projectName} not found"));
await context.RequestServices.GetRequiredService<CurrentProjectService>().PopulateProjectDataCache();
}
#if !DISABLE_FW_BRIDGE
var fwData = context.GetFwDataName();
if (!string.IsNullOrWhiteSpace(fwData))
{
var fwDataProjectContext = context.RequestServices.GetRequiredService<FwDataProjectContext>();
fwDataProjectContext.Project =
FieldWorksProjectList.GetProject(fwData) ?? throw new InvalidOperationException($"FwData {fwData} not found");
}
#endif

await next(context);
});
app.MapHub<CrdtMiniLcmApiHub>($"/api/hub/{{{CrdtMiniLcmApiHub.ProjectRouteKey}}}/lexbox");
#if !DISABLE_FW_BRIDGE
app.MapHub<FwDataMiniLcmHub>($"/api/hub/{{{FwDataMiniLcmHub.ProjectRouteKey}}}/fwdata");
#endif
app.MapHistoryRoutes();
app.MapActivities();
app.MapProjectRoutes();
app.MapFwIntegrationRoutes();
app.MapTest();
app.MapImport();
app.MapAuthRoutes();
app.MapFallbackToFile("index.html", staticFileOptions);
return app;
}
}
86 changes: 2 additions & 84 deletions backend/FwLite/LocalWebApp/Program.cs
Original file line number Diff line number Diff line change
@@ -1,89 +1,7 @@
#if !DISABLE_FW_BRIDGE
using FwDataMiniLcmBridge;
using FwDataMiniLcmBridge.LcmUtils;
#endif
using LcmCrdt;
using LocalWebApp;
using LocalWebApp.Hubs;
using LocalWebApp.Auth;
using LocalWebApp.Routes;
using LocalWebApp.Utils;
using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.StaticFiles.Infrastructure;
using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);
if (!builder.Environment.IsDevelopment())
builder.WebHost.UseUrls("http://127.0.0.1:0");
if (builder.Environment.IsDevelopment())
{
#if !DISABLE_FW_BRIDGE
//do this early so we catch bugs on startup
ProjectLoader.Init();
#endif
}
builder.ConfigureDev<AuthConfig>(config => config.DefaultAuthority = new("https://lexbox.dev.languagetechnology.org"));
//for now prod builds will also use lt dev until we deploy oauth to prod
builder.ConfigureProd<AuthConfig>(config => config.DefaultAuthority = new("https://lexbox.dev.languagetechnology.org"));
builder.Services.Configure<AuthConfig>(c => c.ClientId = "becf2856-0690-434b-b192-a4032b72067f");

builder.Services.AddLocalAppServices(builder.Environment);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSignalR(options =>
{
options.AddFilter(new LockedProjectFilter());
options.EnableDetailedErrors = true;
}).AddJsonProtocol();

var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

//configure dotnet to serve static files from the embedded resources
var sharedOptions = new SharedOptions() { FileProvider = new ManifestEmbeddedFileProvider(typeof(Program).Assembly) };
app.UseDefaultFiles(new DefaultFilesOptions(sharedOptions));
var staticFileOptions = new StaticFileOptions(sharedOptions);
app.UseStaticFiles(staticFileOptions);

app.Use(async (context, next) =>
{
var projectName = context.GetProjectName();
if (!string.IsNullOrWhiteSpace(projectName))
{
var projectsService = context.RequestServices.GetRequiredService<ProjectsService>();
projectsService.SetProjectScope(projectsService.GetProject(projectName) ??
throw new InvalidOperationException($"Project {projectName} not found"));
await context.RequestServices.GetRequiredService<CurrentProjectService>().PopulateProjectDataCache();
}
#if !DISABLE_FW_BRIDGE
var fwData = context.GetFwDataName();
if (!string.IsNullOrWhiteSpace(fwData))
{
var fwDataProjectContext = context.RequestServices.GetRequiredService<FwDataProjectContext>();
fwDataProjectContext.Project = FieldWorksProjectList.GetProject(fwData) ?? throw new InvalidOperationException($"FwData {fwData} not found");
}
#endif

await next(context);
});
app.MapHub<CrdtMiniLcmApiHub>($"/api/hub/{{{CrdtMiniLcmApiHub.ProjectRouteKey}}}/lexbox");
#if !DISABLE_FW_BRIDGE
app.MapHub<FwDataMiniLcmHub>($"/api/hub/{{{FwDataMiniLcmHub.ProjectRouteKey}}}/fwdata");
#endif
app.MapHistoryRoutes();
app.MapActivities();
app.MapProjectRoutes();
app.MapFwIntegrationRoutes();
app.MapTest();
app.MapImport();
app.MapAuthRoutes();
app.MapFallbackToFile("index.html", staticFileOptions);
using LocalWebApp;

var app = LocalWebAppServer.SetupAppServer(args);
await using (app)
{
await app.StartAsync();
Expand Down

0 comments on commit 7693869

Please sign in to comment.