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
|
using System.Text.Json;
using System.Text.Json.Serialization;
using ArcaneLibs;
using ArcaneLibs.Extensions;
using Microsoft.EntityFrameworkCore;
using Spacebar.ConfigModel;
using Spacebar.ConfigModel.Extensions;
using Spacebar.Interop.Authentication;
using Spacebar.Interop.Authentication.AspNetCore;
using Spacebar.Models.Db.Contexts;
using Spacebar.UApi.Services;
var builder = WebApplication.CreateBuilder(args);
if (!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("APPSETTINGS_PATH"))) {
Console.WriteLine("Loading appsettings from path: " + Environment.GetEnvironmentVariable("APPSETTINGS_PATH"));
builder.Configuration.AddJsonFile(Environment.GetEnvironmentVariable("APPSETTINGS_PATH")!);
}
// Add services to the container.
builder.Services.AddControllers(options => {
options.MaxValidationDepth = null;
// options.MaxIAsyncEnumerableBufferLimit = 1;
}).AddJsonOptions(options => {
options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
options.JsonSerializerOptions.WriteIndented = true;
options.JsonSerializerOptions.MaxDepth = 100;
// options.JsonSerializerOptions.DefaultBufferSize = ;
}).AddMvcOptions(o => { o.SuppressOutputFormatterBuffering = true; });
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();
builder.Services.AddDbContextPool<SpacebarDbContext>(options => {
options
.UseNpgsql(builder.Configuration.GetConnectionString("Spacebar"))
.EnableDetailedErrors();
}, 64);
if (!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("CONFIG_PATH")))
builder.Services.AddSingleton<Config>(sp => {
var cfgPath = Environment.GetEnvironmentVariable("CONFIG_PATH");
sp.GetService<ILogger<Program>>().LogInformation("Using config from path: {path}", cfgPath);
return JsonSerializer.Deserialize<Config>(File.ReadAllText(cfgPath));
});
else
builder.Services.AddSingleton<Config>(sp => {
sp.GetService<ILogger<Program>>().LogInformation("Using config from database...");
var db = sp.GetService<SpacebarDbContext>();
var config = db.Configs
.OrderBy(x => x.Key)
.ToDictionary(x => x.Key, x => x.Value);
var readConfig = config.ToNestedJsonObject();
return readConfig.Deserialize<Config>();
});
builder.Services.AddSingleton<UApiConfiguration>();
builder.Services.AddSingleton<SpacebarAuthenticationConfiguration>();
builder.Services.AddScoped<SpacebarAuthenticationService>();
builder.Services.AddScoped<SpacebarAspNetAuthenticationService>();
builder.Services.AddScoped<TemplateImportService>();
builder.Services.AddScoped<PermissionService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) {
app.MapOpenApi();
}
app.UseAuthorization();
app.MapControllers();
StreamingHttpClient.LogRequests = false;
app.Use((context, next) => {
context.Response.Headers["Access-Control-Allow-Origin"] =
string.IsNullOrWhiteSpace(context.Request.Headers.Origin)
? "*"
: context.Request.Headers.Origin;
context.Response.Headers["Access-Control-Allow-Methods"] =
string.IsNullOrWhiteSpace(context.Request.Headers.AccessControlRequestMethod)
? "GET, POST, PUT, DELETE, OPTIONS"
: context.Request.Headers.AccessControlRequestMethod.ToString();
context.Response.Headers["Access-Control-Allow-Headers"] =
string.IsNullOrWhiteSpace(context.Request.Headers.AccessControlRequestHeaders)
? "*, Authorization"
: context.Request.Headers.AccessControlRequestHeaders.ToString();
context.Response.Headers.AccessControlAllowCredentials = "true";
if (context.Request.Method == "OPTIONS") {
context.Response.StatusCode = 200;
return Task.CompletedTask;
}
return next();
});
// add some special sauce
app.Map("/", async context => {
var client = new StreamingHttpClient();
var cfg = context.RequestServices.GetRequiredService<UApiConfiguration>();
var requestMessage = new HttpRequestMessage(new HttpMethod(context.Request.Method), cfg.FallbackApiEndpoint);
foreach (var header in context.Request.Headers)
if (header.Key is not ("Accept-Encoding" or "Host"))
requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
var responseMessage = await client.SendUnhandledAsync(requestMessage, CancellationToken.None);
context.Response.StatusCode = (int)responseMessage.StatusCode;
foreach (var header in responseMessage.Headers) context.Response.Headers[header.Key] = header.Value.ToArray();
foreach (var header in responseMessage.Content.Headers) context.Response.Headers[header.Key] = header.Value.ToArray();
// await responseMessage.Content.CopyToAsync(context.Response.Body);
var txt = await responseMessage.Content.ReadAsStringAsync();
txt = txt.Replace("your very own Spacebar instance", "your very own Spacebar instance with μAPI");
var data = txt.AsBytes().ToArray();
context.Response.Headers.ContentLength = data.Length;
await context.Response.Body.WriteAsync(data);
});
app.MapFallback("{*_}", async context => {
var client = new StreamingHttpClient();
var cfg = context.RequestServices.GetRequiredService<UApiConfiguration>();
var requestMessage = new HttpRequestMessage(
new HttpMethod(context.Request.Method),
cfg.FallbackApiEndpoint + context.Request.Path + context.Request.QueryString
) {
Content = new StreamContent(context.Request.Body)
};
Console.WriteLine(requestMessage.RequestUri);
foreach (var header in context.Request.Headers)
if (header.Key is not ("Accept-Encoding" or "Host"))
requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
var responseMessage = await client.SendUnhandledAsync(requestMessage, CancellationToken.None);
context.Response.StatusCode = (int)responseMessage.StatusCode;
foreach (var header in responseMessage.Headers) context.Response.Headers[header.Key] = header.Value.ToArray();
foreach (var header in responseMessage.Content.Headers) context.Response.Headers[header.Key] = header.Value.ToArray();
await responseMessage.Content.CopyToAsync(context.Response.Body);
});
app.Run();
|