mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-25 23:18:44 -07:00
f5ad4b59ef
- Default hosting mode is now Localtunnel — public *.loca.lt URL, no account, auto-fetched on first run. Replaces the prototyped Tailscale mode. - Tailscale code purged from launcher + CLI; docs swapped to Localtunnel throughout (easy-setup, joining-a-server, server-cli, troubleshooting, faq, READMEs). - Launcher sidebar gains an Open admin panel button — opens https://admin.<apex> in the browser once the server is live. - SQLite db moves to %APPDATA%\DorkNet\dorknet.db (server reads Database__SqlitePath env var, launcher passes it). Existing dbs under <serverDir>\data\ are migrated on first run. - CLI Program.cs: --mode default flips from tailscale to localtunnel; csproj links in LocaltunnelTunnel + LocaltunnelInstaller. - New Backend files: LauncherNameServer, LocaltunnelInstaller, LocaltunnelTunnel, SingleOriginServiceMap. - .gitignore: exclude installer/out/.
82 lines
2.7 KiB
C#
82 lines
2.7 KiB
C#
using System.Net;
|
|
using System.Net.Sockets;
|
|
using System.Text;
|
|
|
|
namespace DorkNet.Launcher.Backend;
|
|
|
|
/// <summary>Minimal localhost HTTP name-server for the patched client.
|
|
/// The patcher points the hardcoded RecNet bootstrap URL at
|
|
/// http://127.0.0.1:80; this listener answers that request with the
|
|
/// service URL map for the active Easy Launcher session.</summary>
|
|
public sealed class LauncherNameServer : IAsyncDisposable
|
|
{
|
|
private TcpListener? _listener;
|
|
private CancellationTokenSource? _cts;
|
|
private Task? _loop;
|
|
private string _publicBaseUrl = "";
|
|
|
|
public void Start(string publicBaseUrl)
|
|
{
|
|
_publicBaseUrl = SingleOriginServiceMap.NormalizeBaseUrl(publicBaseUrl);
|
|
if (_listener is not null) return;
|
|
|
|
_cts = new CancellationTokenSource();
|
|
_listener = new TcpListener(IPAddress.Loopback, 80);
|
|
_listener.Start();
|
|
_loop = Task.Run(() => AcceptLoopAsync(_cts.Token));
|
|
}
|
|
|
|
public void Update(string publicBaseUrl)
|
|
=> _publicBaseUrl = SingleOriginServiceMap.NormalizeBaseUrl(publicBaseUrl);
|
|
|
|
private async Task AcceptLoopAsync(CancellationToken ct)
|
|
{
|
|
while (!ct.IsCancellationRequested && _listener is not null)
|
|
{
|
|
TcpClient client;
|
|
try { client = await _listener.AcceptTcpClientAsync(ct); }
|
|
catch (OperationCanceledException) { break; }
|
|
catch { if (ct.IsCancellationRequested) break; else continue; }
|
|
_ = Task.Run(() => HandleAsync(client, ct), ct);
|
|
}
|
|
}
|
|
|
|
private async Task HandleAsync(TcpClient client, CancellationToken ct)
|
|
{
|
|
using var clientHandle = client;
|
|
try
|
|
{
|
|
await using var stream = client.GetStream();
|
|
var buffer = new byte[2048];
|
|
_ = await stream.ReadAsync(buffer, ct);
|
|
|
|
var body = SingleOriginServiceMap.ToJson(_publicBaseUrl);
|
|
var bodyBytes = Encoding.UTF8.GetBytes(body);
|
|
var header =
|
|
"HTTP/1.1 200 OK\r\n" +
|
|
"Content-Type: application/json; charset=utf-8\r\n" +
|
|
$"Content-Length: {bodyBytes.Length}\r\n" +
|
|
"Cache-Control: no-store\r\n" +
|
|
"Connection: close\r\n\r\n";
|
|
var headerBytes = Encoding.ASCII.GetBytes(header);
|
|
await stream.WriteAsync(headerBytes, ct);
|
|
await stream.WriteAsync(bodyBytes, ct);
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
public async ValueTask DisposeAsync()
|
|
{
|
|
try { _cts?.Cancel(); } catch { }
|
|
try { _listener?.Stop(); } catch { }
|
|
if (_loop is not null)
|
|
{
|
|
try { await _loop; } catch { }
|
|
}
|
|
_cts?.Dispose();
|
|
_listener = null;
|
|
_cts = null;
|
|
_loop = null;
|
|
}
|
|
}
|