-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathProgram.cs
More file actions
153 lines (128 loc) · 4.55 KB
/
Program.cs
File metadata and controls
153 lines (128 loc) · 4.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
using EntglDb.Core;
using EntglDb.Core.Network;
using EntglDb.Network;
using EntglDb.Persistence.BLite;
using EntglDb.Sample.Shared;
using EntglDb.Sync;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.OpenApi;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Title = "EntglDb ASP.NET Node",
Version = "v0.8.6",
Description = "A decentralized peer-to-peer database node running on ASP.NET Core. Features P2P syncing, dynamic discovery, and vector-clock based consistency."
});
});
builder.Services.AddControllers();
// Health Checks
builder.Services.AddHealthChecks()
.AddCheck<EntglDbHealth>("EntglDb");
// Register Configuration Provider
builder.Services.AddSingleton<AspNetPeerNodeConfigurationProvider>();
// Configure EntglDb
var dataPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data");
Directory.CreateDirectory(dataPath);
var nodeName = builder.Configuration["EntglDb:NodeName"] ?? "AspNetSampleNode";
var databasePath = Path.Combine(dataPath, $"{nodeName}.blite");
builder.Services.AddEntglDbCore()
.AddEntglDbBLite<SampleDbContext, SampleDocumentStore>(sp => new SampleDbContext(databasePath), databasePath + ".meta")
.AddEntglDbNetwork<AspNetPeerNodeConfigurationProvider>() // transport only
.AddEntglDbSync(useHostedService: true); // sync handlers + node orchestrator
var app = builder.Build();
app.UseStaticFiles(); // Serve wwwroot for custom CSS
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "EntglDb API v1");
c.InjectStylesheet("/css/swagger-custom.css");
c.DocumentTitle = "EntglDb Node API";
});
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.MapHealthChecks("/health");
// API: Get Available Collections
app.MapGet("/api/collections", (SampleDbContext db) =>
{
return Results.Ok(new[] { "Users", "TodoLists" });
})
.WithName("GetCollections");
// API: Get Connected Peers
app.MapGet("/api/peers", (IDiscoveryService discovery) =>
{
var activePeers = discovery.GetActivePeers();
return Results.Ok(activePeers);
})
.WithName("GetPeers");
// API: Get Telemetry
app.MapGet("/api/telemetry", async (SampleDbContext db, EntglDb.Network.Telemetry.INetworkTelemetryService telemetry) =>
{
var counts = new Dictionary<string, int>
{
["Users"] = await db.Users.FindAllAsync().CountAsync(),
["TodoLists"] = await db.TodoLists.FindAllAsync().CountAsync()
};
return Results.Ok(new
{
DocumentCounts = counts,
NetworkStats = telemetry.GetSnapshot(),
Timestamp = DateTime.UtcNow
});
})
.WithName("GetTelemetry");
app.Run();
// Configuration Provider implementation
public class AspNetPeerNodeConfigurationProvider : IPeerNodeConfigurationProvider
{
private readonly PeerNodeConfiguration _config;
public AspNetPeerNodeConfigurationProvider(IConfiguration configuration)
{
var nodeName = configuration["EntglDb:NodeName"] ?? "AspNetCoreNode";
var portObj = configuration["EntglDb:Port"];
int port = int.TryParse(portObj, out int p) ? p : 4001;
var authToken = configuration["EntglDb:AuthToken"] ?? "Test-Cluster-Key";
_config = new PeerNodeConfiguration
{
NodeId = nodeName,
TcpPort = port,
AuthToken = authToken
};
}
public event PeerNodeConfigurationChangedEventHandler? ConfigurationChanged;
public Task<PeerNodeConfiguration> GetConfiguration()
{
return Task.FromResult(_config);
}
}
public class EntglDbHealth : IHealthCheck
{
private readonly SampleDbContext _db;
public EntglDbHealth(SampleDbContext db)
{
_db = db;
}
public async Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default)
{
try
{
_ = await _db.Users.FindAllAsync().CountAsync();
return HealthCheckResult.Healthy("EntglDb is reachable");
}
catch (Exception ex)
{
return HealthCheckResult.Unhealthy("EntglDb is unreachable", ex);
}
}
}