Initial commit: Client Doc docs Server Tools
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace XWorld.Server.Gateway
|
||||
{
|
||||
// 独立内网 CDN:Kestrel 静态文件服务,HTTP 根 = root(发布产物 client/ 目录)。
|
||||
// 仿 GameServerHost 的 Start/Stop 形态;缺失文件返回 404,无目录浏览。
|
||||
public sealed class StaticFileServer
|
||||
{
|
||||
private readonly string _root;
|
||||
private readonly int _port;
|
||||
private readonly bool _bindAll;
|
||||
private WebApplication _app;
|
||||
|
||||
public string HttpBaseUrl { get; private set; } // 例如 http://127.0.0.1:15081
|
||||
|
||||
public StaticFileServer(string root, int port = 15081, bool bindAllInterfaces = false)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(root)) throw new ArgumentException("root 不能为空", nameof(root));
|
||||
_root = Path.GetFullPath(root);
|
||||
_port = port;
|
||||
_bindAll = bindAllInterfaces;
|
||||
}
|
||||
|
||||
public async Task StartAsync()
|
||||
{
|
||||
Directory.CreateDirectory(_root); // 根目录不存在则建空目录(GET 全 404,而非启动崩溃)
|
||||
|
||||
var builder = WebApplication.CreateBuilder();
|
||||
builder.Logging.ClearProviders();
|
||||
builder.WebHost.ConfigureKestrel(o =>
|
||||
o.Listen(_bindAll ? System.Net.IPAddress.Any : System.Net.IPAddress.Loopback, _port)); // 0 = 临时端口
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
var provider = new PhysicalFileProvider(_root);
|
||||
var opts = new StaticFileOptions
|
||||
{
|
||||
FileProvider = provider,
|
||||
ServeUnknownFileTypes = true, // .bytes/.unity3d/.sig 等无标准 MIME 也要发
|
||||
DefaultContentType = "application/octet-stream",
|
||||
};
|
||||
app.UseStaticFiles(opts); // 仅静态文件,不开目录浏览;未命中落到下面的 404
|
||||
|
||||
await app.StartAsync();
|
||||
_app = app;
|
||||
|
||||
string http = app.Services.GetRequiredService<IServer>()
|
||||
.Features.Get<IServerAddressesFeature>().Addresses.FirstOrDefault()
|
||||
?? throw new InvalidOperationException("Kestrel 已启动但未注册任何监听地址");
|
||||
HttpBaseUrl = http;
|
||||
}
|
||||
|
||||
public async Task StopAsync()
|
||||
{
|
||||
if (_app == null) return;
|
||||
await _app.StopAsync();
|
||||
await _app.DisposeAsync();
|
||||
_app = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user