Files
DorkNet/launcher/Program.cs
T
Alexa df9dac053d launcher: v0.1 — PhotinoNET shell + multi-version orchestration
Single-download .NET 9 self-contained launcher for hosting / joining
DorkNet servers. Reads versions.json from main to discover supported
client builds, fetches the matching server binary + client patcher
from GitHub Releases per branch, manages the server subprocess +
Cloudflare quick-tunnel, and wraps it all in a PhotinoNET window.

Code layout:
- Program.cs           PhotinoNET window + message bridge bootstrap
- Backend/             AppPaths, AppState, VersionsManifest,
                       ReleaseDownloader, ServerProcess, ClientPatcher,
                       Tunnel, RecRoomPicker, JoinCode, MessageBridge
- ui/                  index.html + style.css + app.js (no build step)
- RELEASES.md          GitHub Releases artifact contract per-version
                       branches must publish to

Per-version branches need to ship two release assets per tag:
- dorknet-server-{version_key}-win-x64.zip
- dorknet-clientpatch-{version_key}.zip
(see launcher/RELEASES.md for the full naming + arg contract)

Photon AppIds, JWT secret, and the picked Rec Room path stay
per-machine; the launcher never bundles them.
2026-05-26 20:54:16 +03:00

71 lines
2.4 KiB
C#

using Photino.NET;
using DorkNet.Launcher.Backend;
using System.Text.Json;
namespace DorkNet.Launcher;
/// <summary>Entry point + the host↔JS message bridge. The window is a
/// PhotinoNET wrapper around WebView2, loading ui/index.html from the
/// app's directory. Every JS ↔ C# call goes through one JSON-tagged
/// envelope so we can route by command/event name without per-call
/// glue.</summary>
public static class Program
{
[STAThread]
public static void Main(string[] args)
{
AppPaths.EnsureDirectoriesExist();
var indexPath = Path.Combine(AppContext.BaseDirectory, "ui", "index.html");
if (!File.Exists(indexPath))
{
// First-aid: if the UI files didn't ship next to the binary,
// the window would be blank with no hint why. Surface the
// missing-file path before opening anything.
MessageBox.Error(
"DorkNet UI files missing",
$"Could not find {indexPath}. Reinstall the launcher.");
return;
}
var window = new PhotinoWindow()
.SetTitle("DorkNet")
.SetUseOsDefaultSize(false)
.SetSize(900, 640)
.SetResizable(true)
.Center()
.Load(new Uri(indexPath));
var bridge = new MessageBridge(window);
window.RegisterWebMessageReceivedHandler((sender, message) =>
{
// JS sends JSON envelopes: {"type":"command-name","payload":{...},"requestId":"..."}
// Reply path is bridge.SendEvent — fire-and-forget unless requestId is set.
try
{
bridge.HandleAsync(message).GetAwaiter().GetResult();
}
catch (Exception ex)
{
bridge.SendEvent("error", new { source = "bridge", message = ex.Message });
}
});
window.WaitForClose();
}
}
/// <summary>Minimal MessageBox helper — DorkNet won't pop these often,
/// but a missing-UI-file failure mode needs a visible signal before the
/// PhotinoNET window opens.</summary>
internal static class MessageBox
{
public static void Error(string title, string body)
{
System.Windows.Forms.MessageBox.Show(
body, title,
System.Windows.Forms.MessageBoxButtons.OK,
System.Windows.Forms.MessageBoxIcon.Error);
}
}