116 lines
4.3 KiB
C#
116 lines
4.3 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Net.Http;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.AspNetCore.Builder;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Hosting;
|
|
using SNote.Server.Data;
|
|
using SNote.Server.Endpoints;
|
|
using SNote.Server.Security;
|
|
|
|
namespace SNote.Server;
|
|
|
|
public class Program
|
|
{
|
|
public static void Main(string[] args)
|
|
{
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
|
|
// Add Configuration & DB Context (SQLite)
|
|
var dbPath = Path.Combine(AppContext.BaseDirectory, "snote_server.db");
|
|
builder.Services.AddDbContext<ServerDbContext>(options =>
|
|
options.UseSqlite($"Data Source={dbPath}"));
|
|
|
|
// Register custom security managers & HTTP utilities
|
|
builder.Services.AddSingleton<CertificateManager>();
|
|
builder.Services.AddSingleton<PeerCache>();
|
|
builder.Services.AddSingleton<HttpClient>();
|
|
|
|
// Register OpenAPI explorer
|
|
builder.Services.AddOpenApi();
|
|
|
|
var app = builder.Build();
|
|
|
|
// 1. Initialize SQLite Database Schema
|
|
using (var scope = app.Services.CreateScope())
|
|
{
|
|
var db = scope.ServiceProvider.GetRequiredService<ServerDbContext>();
|
|
db.Database.EnsureCreated();
|
|
}
|
|
|
|
// Configure Development Tools
|
|
if (app.Environment.IsDevelopment())
|
|
{
|
|
app.MapOpenApi();
|
|
}
|
|
|
|
// 2. Map Modular API Endpoint Classes
|
|
app.MapAuthEndpoints();
|
|
app.MapNodeEndpoints();
|
|
app.MapSyncEndpoints();
|
|
|
|
// Welcome / Healthcheck root
|
|
app.MapGet("/", () => Results.Ok(new
|
|
{
|
|
service = "SNote Server",
|
|
status = "Online",
|
|
time = DateTime.UtcNow
|
|
}));
|
|
|
|
// 3. Start Background Sync Runner
|
|
var hostApplicationLifetime = app.Services.GetRequiredService<IHostApplicationLifetime>();
|
|
var services = app.Services;
|
|
|
|
// Dynamic Bootstrapping check on startup
|
|
var config = app.Configuration;
|
|
var bootstrapUrl = config["BootstrapFromPeer"];
|
|
if (!string.IsNullOrEmpty(bootstrapUrl))
|
|
{
|
|
Task.Run(async () =>
|
|
{
|
|
// Wait briefly for server startup
|
|
await Task.Delay(2000);
|
|
using var scope = services.CreateScope();
|
|
var db = scope.ServiceProvider.GetRequiredService<ServerDbContext>();
|
|
var certManager = scope.ServiceProvider.GetRequiredService<CertificateManager>();
|
|
var client = scope.ServiceProvider.GetRequiredService<HttpClient>();
|
|
await SyncEndpoints.BootstrapFromPeerServerAsync(bootstrapUrl, db, certManager, client);
|
|
});
|
|
}
|
|
|
|
// Dynamic Handshake: Connect to target destination server and register local address on startup
|
|
var destUrl = config["Sync:DestinationServerUrl"];
|
|
var localUrl = config["Sync:LocalServerUrl"];
|
|
if (!string.IsNullOrEmpty(destUrl) && !string.IsNullOrEmpty(localUrl))
|
|
{
|
|
Task.Run(async () =>
|
|
{
|
|
// Wait briefly for server startup
|
|
await Task.Delay(2000);
|
|
using var scope = services.CreateScope();
|
|
var certManager = scope.ServiceProvider.GetRequiredService<CertificateManager>();
|
|
var client = scope.ServiceProvider.GetRequiredService<HttpClient>();
|
|
await SyncEndpoints.RegisterPeerWithDestinationAsync(destUrl, localUrl, certManager, client);
|
|
});
|
|
}
|
|
|
|
// Heartbeat Loop: Periodic Downstream Heartbeat pinger pings downstream peers every 30 seconds
|
|
Task.Run(async () =>
|
|
{
|
|
var token = hostApplicationLifetime.ApplicationStopping;
|
|
using var scope = services.CreateScope();
|
|
var peerCache = scope.ServiceProvider.GetRequiredService<PeerCache>();
|
|
var certManager = scope.ServiceProvider.GetRequiredService<CertificateManager>();
|
|
var client = scope.ServiceProvider.GetRequiredService<HttpClient>();
|
|
await SyncEndpoints.StartHeartbeatPingerAsync(peerCache, certManager, client, token);
|
|
});
|
|
|
|
app.Run();
|
|
}
|
|
}
|