mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-27 16:08:47 -07:00
launcher: DORKNET_LOCAL_* env-var overrides for dev testing
Set DORKNET_LOCAL_MANIFEST and/or DORKNET_LOCAL_RELEASES to point
the launcher at on-disk artifacts instead of the public repo:
- DORKNET_LOCAL_MANIFEST: full path to a versions.json file.
VersionsManifest.FetchAsync reads it from disk and skips the
GitHub round-trip.
- DORKNET_LOCAL_RELEASES: path to a directory laid out as
{root}/{version_key}/server/ + .../patcher/. EnsureServerAsync /
EnsurePatcherAsync return those paths in-place — no download,
no copy, no marker files.
Both are silent no-ops when unset / missing on disk, so it's safe
to leave them set permanently in a dev profile. When at least one
is active, the Settings view surfaces a "Dev overrides active"
panel listing the paths so it's obvious the launcher isn't using
the public manifest.
Lets contributors iterate on per-version branch changes against
the launcher UI without needing to tag a public Release.
This commit is contained in:
@@ -0,0 +1,80 @@
|
|||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace DorkNet.Launcher.Backend;
|
||||||
|
|
||||||
|
/// <summary>Local dev-time overrides that bypass the GitHub-backed
|
||||||
|
/// manifest + releases fetches. Set via environment variables before
|
||||||
|
/// launching <c>dorknet.exe</c>:
|
||||||
|
///
|
||||||
|
/// <list type="bullet">
|
||||||
|
/// <item><c>DORKNET_LOCAL_MANIFEST</c> = full path to a
|
||||||
|
/// <c>versions.json</c> file. When set + exists,
|
||||||
|
/// <see cref="VersionsManifest.FetchAsync"/> reads it from disk and
|
||||||
|
/// skips the GitHub round-trip.</item>
|
||||||
|
/// <item><c>DORKNET_LOCAL_RELEASES</c> = path to a directory whose
|
||||||
|
/// children are <c>{version_key}/server/</c> and
|
||||||
|
/// <c>{version_key}/patcher/</c>. When the launcher would normally
|
||||||
|
/// download a server / patcher zip, it points at these in-place
|
||||||
|
/// instead — no copying, no markers, just read the dir.</item>
|
||||||
|
/// </list>
|
||||||
|
///
|
||||||
|
/// <para>Both overrides are no-ops when the env var is unset or the
|
||||||
|
/// path doesn't exist on disk, so they're safe to leave set
|
||||||
|
/// permanently in a dev profile.</para></summary>
|
||||||
|
public static class LocalOverrides
|
||||||
|
{
|
||||||
|
public const string ManifestEnvVar = "DORKNET_LOCAL_MANIFEST";
|
||||||
|
public const string ReleasesEnvVar = "DORKNET_LOCAL_RELEASES";
|
||||||
|
|
||||||
|
/// <summary>Returns the configured manifest path if the env var is
|
||||||
|
/// set AND the file exists; null otherwise. Caller decides whether
|
||||||
|
/// to fall back to the network.</summary>
|
||||||
|
public static string? GetLocalManifestPath()
|
||||||
|
{
|
||||||
|
var path = Environment.GetEnvironmentVariable(ManifestEnvVar);
|
||||||
|
if (string.IsNullOrEmpty(path)) return null;
|
||||||
|
return File.Exists(path) ? path : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Returns the configured releases-root if the env var is
|
||||||
|
/// set AND the directory exists; null otherwise.</summary>
|
||||||
|
public static string? GetLocalReleasesRoot()
|
||||||
|
{
|
||||||
|
var path = Environment.GetEnvironmentVariable(ReleasesEnvVar);
|
||||||
|
if (string.IsNullOrEmpty(path)) return null;
|
||||||
|
return Directory.Exists(path) ? path : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Returns the local server-dir for <paramref name="versionKey"/>
|
||||||
|
/// if the releases-root override is set and the subfolder exists.
|
||||||
|
/// Convention: <c>{root}/{version_key}/server/</c>.</summary>
|
||||||
|
public static string? GetLocalServerDir(string versionKey)
|
||||||
|
{
|
||||||
|
var root = GetLocalReleasesRoot();
|
||||||
|
if (root is null) return null;
|
||||||
|
var dir = Path.Combine(root, versionKey, "server");
|
||||||
|
return Directory.Exists(dir) ? dir : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Same as <see cref="GetLocalServerDir"/> but for the
|
||||||
|
/// client patcher. Convention: <c>{root}/{version_key}/patcher/</c>.</summary>
|
||||||
|
public static string? GetLocalPatcherDir(string versionKey)
|
||||||
|
{
|
||||||
|
var root = GetLocalReleasesRoot();
|
||||||
|
if (root is null) return null;
|
||||||
|
var dir = Path.Combine(root, versionKey, "patcher");
|
||||||
|
return Directory.Exists(dir) ? dir : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Single-line description of what overrides are active,
|
||||||
|
/// for surfacing in the Settings view. Empty string if none.</summary>
|
||||||
|
public static string DescribeActive()
|
||||||
|
{
|
||||||
|
var parts = new List<string>();
|
||||||
|
var m = GetLocalManifestPath();
|
||||||
|
if (m is not null) parts.Add($"manifest -> {m}");
|
||||||
|
var r = GetLocalReleasesRoot();
|
||||||
|
if (r is not null) parts.Add($"releases -> {r}");
|
||||||
|
return string.Join("\n", parts);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,6 +44,11 @@ public sealed class ReleaseDownloader
|
|||||||
IProgress<DownloadProgress>? progress,
|
IProgress<DownloadProgress>? progress,
|
||||||
CancellationToken ct = default)
|
CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
|
// Dev-time override — use a local server build in-place rather
|
||||||
|
// than downloading from GitHub. Skips cache entirely.
|
||||||
|
var local = LocalOverrides.GetLocalServerDir(version.VersionKey);
|
||||||
|
if (local is not null) return local;
|
||||||
|
|
||||||
var dir = Path.Combine(AppPaths.ServersRoot, version.VersionKey);
|
var dir = Path.Combine(AppPaths.ServersRoot, version.VersionKey);
|
||||||
var marker = Path.Combine(dir, ".dorknet-version");
|
var marker = Path.Combine(dir, ".dorknet-version");
|
||||||
// If the marker file exists, the server is already unpacked
|
// If the marker file exists, the server is already unpacked
|
||||||
@@ -73,6 +78,11 @@ public sealed class ReleaseDownloader
|
|||||||
IProgress<DownloadProgress>? progress,
|
IProgress<DownloadProgress>? progress,
|
||||||
CancellationToken ct = default)
|
CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
|
// Dev-time override — same as EnsureServerAsync but for the
|
||||||
|
// client-patcher dir.
|
||||||
|
var local = LocalOverrides.GetLocalPatcherDir(version.VersionKey);
|
||||||
|
if (local is not null) return local;
|
||||||
|
|
||||||
var dir = Path.Combine(AppPaths.PatchersRoot, version.VersionKey);
|
var dir = Path.Combine(AppPaths.PatchersRoot, version.VersionKey);
|
||||||
var marker = Path.Combine(dir, ".dorknet-version");
|
var marker = Path.Combine(dir, ".dorknet-version");
|
||||||
if (File.Exists(marker)) return dir;
|
if (File.Exists(marker)) return dir;
|
||||||
|
|||||||
@@ -30,6 +30,23 @@ public sealed class VersionsManifest
|
|||||||
|
|
||||||
public async Task<VersionsManifest?> FetchAsync(CancellationToken ct = default)
|
public async Task<VersionsManifest?> FetchAsync(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
|
// Dev-time override: read manifest from a local file instead of
|
||||||
|
// GitHub. Used for testing branch changes before they're public.
|
||||||
|
var localPath = LocalOverrides.GetLocalManifestPath();
|
||||||
|
if (localPath is not null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var json = await File.ReadAllTextAsync(localPath, ct);
|
||||||
|
return JsonSerializer.Deserialize<VersionsManifest>(json);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Bad local file — fall through to the network so the
|
||||||
|
// user gets a real error instead of silent emptiness.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var m = await Http.GetFromJsonAsync<VersionsManifest>(ManifestUrl, ct);
|
var m = await Http.GetFromJsonAsync<VersionsManifest>(ManifestUrl, ct);
|
||||||
|
|||||||
@@ -661,6 +661,24 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
<!-- Dev-mode overrides — visible only when at least one
|
||||||
|
env var is set so end users never see it. -->
|
||||||
|
<Border x:Name="LocalOverridesPanel" Visibility="Collapsed"
|
||||||
|
Style="{StaticResource Panel}" Margin="0,0,0,16"
|
||||||
|
Background="{StaticResource CardBgHost}">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Style="{StaticResource SectionTitle}"
|
||||||
|
Text="🛠 Dev overrides active" />
|
||||||
|
<TextBlock Foreground="{StaticResource InkSoft}" FontSize="12"
|
||||||
|
Margin="0,-6,0,8" TextWrapping="Wrap"
|
||||||
|
Text="The launcher is reading from local paths instead of GitHub. Unset DORKNET_LOCAL_MANIFEST / DORKNET_LOCAL_RELEASES to return to normal mode." />
|
||||||
|
<TextBlock x:Name="LocalOverridesText"
|
||||||
|
Foreground="{StaticResource Ink}"
|
||||||
|
FontSize="12" TextWrapping="Wrap"
|
||||||
|
FontFamily="Cascadia Mono, Consolas" />
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
<Border Style="{StaticResource Panel}">
|
<Border Style="{StaticResource Panel}">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock Style="{StaticResource SectionTitle}" Text="About" />
|
<TextBlock Style="{StaticResource SectionTitle}" Text="About" />
|
||||||
|
|||||||
@@ -166,6 +166,17 @@ public partial class MainWindow : Window
|
|||||||
$"Patchers: {AppPaths.PatchersRoot}\n" +
|
$"Patchers: {AppPaths.PatchersRoot}\n" +
|
||||||
$"Logs: {AppPaths.LogsRoot}";
|
$"Logs: {AppPaths.LogsRoot}";
|
||||||
|
|
||||||
|
var overrides = LocalOverrides.DescribeActive();
|
||||||
|
if (!string.IsNullOrEmpty(overrides))
|
||||||
|
{
|
||||||
|
LocalOverridesPanel.Visibility = Visibility.Visible;
|
||||||
|
LocalOverridesText.Text = overrides;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LocalOverridesPanel.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
|
||||||
RefreshJoinReadiness();
|
RefreshJoinReadiness();
|
||||||
ShowView(PickRoutingTarget());
|
ShowView(PickRoutingTarget());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user