Launcher 0.3.2: Updates aus Gitea-Releases, Server-Karte entfernt
Neueste Mod/Launcher-Version und Neuigkeiten kommen von git.mbm.wtf (bso-release.json mit Signatur), die Website ist nur noch Reserve (mit -dev zuerst). SPIELEN auf der Startseite startet ohne Server. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<RootNamespace>BSO.Launcher</RootNamespace>
|
<RootNamespace>BSO.Launcher</RootNamespace>
|
||||||
<AssemblyName>BSO-Launcher</AssemblyName>
|
<AssemblyName>BSO-Launcher</AssemblyName>
|
||||||
<Version>0.3.1</Version>
|
<Version>0.3.2</Version>
|
||||||
<Company>MBM.wtf</Company>
|
<Company>MBM.wtf</Company>
|
||||||
<Product>BSO Launcher</Product>
|
<Product>BSO Launcher</Product>
|
||||||
<Description>BSO Launcher - Bus Simulator Online</Description>
|
<Description>BSO Launcher - Bus Simulator Online</Description>
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
<EmbeddedResource Include="ui\**\*" LogicalName="ui/%(RecursiveDir)%(Filename)%(Extension)" />
|
<EmbeddedResource Include="ui\**\*" LogicalName="ui/%(RecursiveDir)%(Filename)%(Extension)" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- dotnet publish -c Release -o publish -p:BsoRelease=true: die neue Version signieren und auf die Website laden
|
<!-- dotnet publish -c Release -o publish -p:BsoRelease=true: die neue Version signieren und als Gitea-Release veroeffentlichen
|
||||||
(release.ps1, Changelog aus CHANGELOG.md). Ohne -p:BsoRelease=true wird nur gebaut. -->
|
(release.ps1, Changelog aus CHANGELOG.md). Ohne -p:BsoRelease=true wird nur gebaut. -->
|
||||||
<Target Name="BsoRelease" AfterTargets="Publish" Condition="'$(BsoRelease)' == 'true'">
|
<Target Name="BsoRelease" AfterTargets="Publish" Condition="'$(BsoRelease)' == 'true'">
|
||||||
<Exec Command="powershell -NoProfile -ExecutionPolicy Bypass -File "$(MSBuildProjectDirectory)\release.ps1" -Product launcher -Version $(Version) -File "$(PublishDir)BSO-Launcher.exe"" />
|
<Exec Command="powershell -NoProfile -ExecutionPolicy Bypass -File "$(MSBuildProjectDirectory)\release.ps1" -Product launcher -Version $(Version) -File "$(PublishDir)BSO-Launcher.exe"" />
|
||||||
|
|||||||
@@ -3,6 +3,10 @@
|
|||||||
Neue Version: hier einen Abschnitt `## <Version>` anlegen, `<Version>` in `BSO.Launcher.csproj` erhöhen, dann
|
Neue Version: hier einen Abschnitt `## <Version>` anlegen, `<Version>` in `BSO.Launcher.csproj` erhöhen, dann
|
||||||
`dotnet publish -c Release -o publish -p:BsoRelease=true` – der Abschnitt wird der Changelog auf der Website und im Launcher.
|
`dotnet publish -c Release -o publish -p:BsoRelease=true` – der Abschnitt wird der Changelog auf der Website und im Launcher.
|
||||||
|
|
||||||
|
## 0.3.2
|
||||||
|
- Updates kommen direkt aus den Releases auf git.mbm.wtf (Website nur noch als Reserve)
|
||||||
|
- Startseite: Server-Karte entfernt – zusammen gespielt wird über Freunde & Lobby
|
||||||
|
|
||||||
## 0.3.1
|
## 0.3.1
|
||||||
- Setup-Assistent: Sprache, Installationsordner, Desktop-/Startmenü-Verknüpfung wählen, Fortschritt, Fertig-Seite
|
- Setup-Assistent: Sprache, Installationsordner, Desktop-/Startmenü-Verknüpfung wählen, Fortschritt, Fertig-Seite
|
||||||
- Bei jedem Start fragt der Launcher, ob ein neues Update (Launcher oder Mod) installiert werden soll
|
- Bei jedem Start fragt der Launcher, ob ein neues Update (Launcher oder Mod) installiert werden soll
|
||||||
|
|||||||
+4
-2
@@ -311,6 +311,7 @@ public sealed class MainForm : Form
|
|||||||
case "lobbyStop": return await Site("POST", "/api/lobby/stop");
|
case "lobbyStop": return await Site("POST", "/api/lobby/stop");
|
||||||
case "releases":
|
case "releases":
|
||||||
{
|
{
|
||||||
|
if (!Api.TestWebsite && await GiteaReleases.List() is { Count: > 0 } fromGit) return fromGit;
|
||||||
var r = await Api.Releases();
|
var r = await Api.Releases();
|
||||||
if (!r.Ok) throw new Exception(r.Error ?? "Neuigkeiten nicht verfuegbar");
|
if (!r.Ok) throw new Exception(r.Error ?? "Neuigkeiten nicht verfuegbar");
|
||||||
return r.Json.GetProperty("releases");
|
return r.Json.GetProperty("releases");
|
||||||
@@ -442,8 +443,9 @@ public sealed class MainForm : Form
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Game.WriteModConfig(folder, settings.Username, settings.Server, settings.AutoConnect, ticket);
|
// Ohne Lobby: alleine fahren (Mehrspieler laeuft ueber Freunde & Lobby)
|
||||||
LauncherLog.Info($"Spiel gestartet (Server {settings.Server}, automatisch verbinden {settings.AutoConnect})");
|
Game.WriteModConfig(folder, settings.Username, settings.Server, false, ticket);
|
||||||
|
LauncherLog.Info("Spiel gestartet (ohne Lobby)");
|
||||||
}
|
}
|
||||||
Game.Launch();
|
Game.Launch();
|
||||||
if (!settings.KeepOpen)
|
if (!settings.KeepOpen)
|
||||||
|
|||||||
@@ -29,10 +29,14 @@ WinForms-Fenster mit WebView2, die Oberfläche (`ui\`) ist in der .exe eingebett
|
|||||||
## Bauen und veröffentlichen
|
## Bauen und veröffentlichen
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
dotnet publish -c Release -o publish # eine .exe, ohne vorinstalliertes .NET
|
dotnet publish -c Release -o publish -p:BsoRelease=true # bauen + als Gitea-Release veroeffentlichen
|
||||||
.\release.ps1 -Product launcher -Version 0.1.0 -File publish\BSO-Launcher.exe -Changelog "..."
|
.\release.ps1 -Product launcher -Version 0.3.2 -File publish\BSO-Launcher.exe # oder von Hand
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Updates kommen aus den **Gitea-Releases** auf git.mbm.wtf (Mod: `MrMaho/BSO-Mod`, Launcher: `MrMaho/BSO-Launcher`, beide
|
||||||
|
öffentlich). Jedes Release hat die Datei und `bso-release.json` (Version, SHA-256, Signatur). Ist Gitea nicht erreichbar,
|
||||||
|
fragt der Launcher die Website; mit `-dev` umgekehrt.
|
||||||
|
|
||||||
## Gegen die lokale Test-Website (`-dev`)
|
## Gegen die lokale Test-Website (`-dev`)
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
@@ -51,8 +55,9 @@ Lokale Website starten: im BSO-Website-Repo `dotnet run --urls http://localhost:
|
|||||||
|
|
||||||
`new-release-key.ps1` legt einmalig den Schlüssel an (RSA 3072, privater Teil DPAPI-verschlüsselt unter
|
`new-release-key.ps1` legt einmalig den Schlüssel an (RSA 3072, privater Teil DPAPI-verschlüsselt unter
|
||||||
`%APPDATA%\BSO\release-key.dpapi`) und trägt den öffentlichen Teil in `Services\ReleaseSignature.cs` ein.
|
`%APPDATA%\BSO\release-key.dpapi`) und trägt den öffentlichen Teil in `Services\ReleaseSignature.cs` ein.
|
||||||
`release.ps1` (in jedem BSO-Repo) signiert damit `BSO-RELEASE|produkt|version|sha256` und lädt hoch – braucht
|
`release.ps1` (in BSO-Mod und BSO-Launcher) signiert damit `BSO-RELEASE|produkt|version|sha256` und legt das
|
||||||
`BSO_RELEASE_TOKEN` (= `RELEASE_TOKEN` der Website) und optional `BSO_MASTER_URL`.
|
Gitea-Release an – braucht `BSO_GITEA_TOKEN` (Gitea: Einstellungen → Anwendungen → Token mit *repository: Lesen und
|
||||||
|
Schreiben*), gern als Windows-Benutzervariable.
|
||||||
|
|
||||||
**Den Schlüssel sichern:** Mit einem neuen Schlüssel erkennen bereits verteilte Launcher keine Updates mehr.
|
**Den Schlüssel sichern:** Mit einem neuen Schlüssel erkennen bereits verteilte Launcher keine Updates mehr.
|
||||||
|
|
||||||
|
|||||||
+10
-1
@@ -75,7 +75,16 @@ public static class Api
|
|||||||
// --- Freunde und Lobby (alles mit dem Konto-Token)
|
// --- Freunde und Lobby (alles mit dem Konto-Token)
|
||||||
public static Task<Result> Get(string path, string token) => Send(HttpMethod.Get, path, null, token);
|
public static Task<Result> Get(string path, string token) => Send(HttpMethod.Get, path, null, token);
|
||||||
public static Task<Result> Post(string path, string token, object? body = null) => Send(HttpMethod.Post, path, body ?? new { }, token);
|
public static Task<Result> Post(string path, string token, object? body = null) => Send(HttpMethod.Post, path, body ?? new { }, token);
|
||||||
public static async Task<Release?> Latest(string product)
|
/// <summary>Gegen eine Test-Website (-dev, BSO_LAUNCHER_API)? Dann kommen Releases zuerst von dort.</summary>
|
||||||
|
public static bool TestWebsite => Base != BaseUrl.TrimEnd('/');
|
||||||
|
|
||||||
|
/// <summary>Neueste Version: vom Git-Server (Gitea-Releases), sonst von der Website - mit -dev umgekehrt.</summary>
|
||||||
|
public static async Task<Release?> Latest(string product) =>
|
||||||
|
TestWebsite
|
||||||
|
? await WebsiteLatest(product) ?? await GiteaReleases.Latest(product)
|
||||||
|
: await GiteaReleases.Latest(product) ?? await WebsiteLatest(product);
|
||||||
|
|
||||||
|
static async Task<Release?> WebsiteLatest(string product)
|
||||||
{
|
{
|
||||||
var r = await Send(HttpMethod.Get, "/api/releases/latest?product=" + product, null, null);
|
var r = await Send(HttpMethod.Get, "/api/releases/latest?product=" + product, null, null);
|
||||||
if (!r.Ok) return null;
|
if (!r.Ok) return null;
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace BSO.Launcher;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases direkt vom Git-Server (git.mbm.wtf, Gitea): Mod aus BSO-Mod, Launcher aus BSO-Launcher (beide oeffentlich).
|
||||||
|
/// Jedes Release hat die Datei und bso-release.json (Version, SHA-256, Signatur aus release.ps1) - installiert wird weiter
|
||||||
|
/// nur, was mit dem BSO-Release-Schluessel signiert ist, egal woher die Datei kommt.
|
||||||
|
/// </summary>
|
||||||
|
public static class GiteaReleases
|
||||||
|
{
|
||||||
|
public const string ApiBase = "https://git.mbm.wtf/api/v1/repos/MrMaho/";
|
||||||
|
public const string ManifestName = "bso-release.json";
|
||||||
|
|
||||||
|
static string Repo(string product) => product == "launcher" ? "BSO-Launcher" : "BSO-Mod";
|
||||||
|
|
||||||
|
sealed record Manifest(string product, string version, string sha256, long size, string file, string signature);
|
||||||
|
|
||||||
|
/// <summary>Version aus dem Tag ("v0.5.0" -> "0.5.0") oder null.</summary>
|
||||||
|
static string? TagVersion(JsonElement release)
|
||||||
|
{
|
||||||
|
string tag = release.GetProperty("tag_name").GetString() ?? "";
|
||||||
|
string v = tag.TrimStart('v', 'V');
|
||||||
|
return Version.TryParse(v, out _) ? v : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool Published(JsonElement release) =>
|
||||||
|
!release.GetProperty("draft").GetBoolean() && !release.GetProperty("prerelease").GetBoolean();
|
||||||
|
|
||||||
|
static async Task<JsonElement[]> Fetch(string product)
|
||||||
|
{
|
||||||
|
using var doc = JsonDocument.Parse(await Api.Http.GetStringAsync(ApiBase + Repo(product) + "/releases?limit=20"));
|
||||||
|
return doc.RootElement.EnumerateArray().Where(Published).Select(r => r.Clone()).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Neueste Version von mod/launcher - null, wenn es keine gibt oder Gitea nicht erreichbar ist.</summary>
|
||||||
|
public static async Task<Api.Release?> Latest(string product)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var newest = (await Fetch(product))
|
||||||
|
.Select(r => (release: r, version: TagVersion(r)))
|
||||||
|
.Where(x => x.version != null)
|
||||||
|
.OrderByDescending(x => Version.Parse(x.version!))
|
||||||
|
.FirstOrDefault();
|
||||||
|
if (newest.version == null) return null;
|
||||||
|
|
||||||
|
var assets = newest.release.GetProperty("assets").EnumerateArray()
|
||||||
|
.ToDictionary(a => a.GetProperty("name").GetString() ?? "", a => a.GetProperty("browser_download_url").GetString() ?? "");
|
||||||
|
if (!assets.TryGetValue(ManifestName, out string? manifestUrl)) return null;
|
||||||
|
var m = JsonSerializer.Deserialize<Manifest>(await Api.Http.GetStringAsync(manifestUrl));
|
||||||
|
if (m == null || m.product != product || !assets.TryGetValue(m.file, out string? fileUrl)) return null;
|
||||||
|
return new Api.Release(product, m.version, m.sha256, m.size, newest.release.GetProperty("body").GetString() ?? "",
|
||||||
|
newest.release.GetProperty("published_at").GetString() ?? "", m.file, fileUrl, m.signature);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LauncherLog.Error($"Gitea-Release {product}: {e.Message}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Neuigkeiten: Releases von Mod und Launcher, neueste zuerst. null = Gitea nicht erreichbar.</summary>
|
||||||
|
public static async Task<List<object>?> List()
|
||||||
|
{
|
||||||
|
var items = new List<(DateTimeOffset date, object item)>();
|
||||||
|
int reached = 0;
|
||||||
|
foreach (string product in new[] { "mod", "launcher" })
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (var r in await Fetch(product))
|
||||||
|
{
|
||||||
|
if (TagVersion(r) is not { } version) continue;
|
||||||
|
string date = r.GetProperty("published_at").GetString() ?? "";
|
||||||
|
items.Add((DateTimeOffset.TryParse(date, out var d) ? d : default,
|
||||||
|
new { product, version, changelog = r.GetProperty("body").GetString() ?? "", date }));
|
||||||
|
}
|
||||||
|
reached++;
|
||||||
|
}
|
||||||
|
catch (Exception e) { LauncherLog.Error($"Gitea-Releases {product}: {e.Message}"); }
|
||||||
|
}
|
||||||
|
return reached == 0 ? null : items.OrderByDescending(x => x.date).Select(x => x.item).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
+36
-30
@@ -1,13 +1,15 @@
|
|||||||
# Signiert ein Release und laedt es auf die BSO-Website (wie release.ps1 bei MSCO).
|
# Signiert ein Release und veroeffentlicht es als Gitea-Release auf git.mbm.wtf (Launcher und Website holen es von dort).
|
||||||
# .\release.ps1 -Product mod|launcher|server -Version 0.2.0 -File dist\BSO-Mod.zip [-Changelog "..."]
|
# .\release.ps1 -Product mod|launcher -Version 0.5.0 -File dist\BSO-Mod.zip [-Changelog "..."]
|
||||||
# Laeuft auch automatisch bei "dotnet publish -p:BsoRelease=true" (Launcher und Server, siehe .csproj).
|
# Laeuft auch automatisch bei "dotnet publish -p:BsoRelease=true" (Launcher) bzw. "build.ps1 -Release" (Mod).
|
||||||
|
# - Repo: mod -> MrMaho/BSO-Mod, launcher -> MrMaho/BSO-Launcher; Tag v<Version> (wird auf dem Standard-Branch angelegt).
|
||||||
# - Ohne -Changelog: der Abschnitt "## <Version>" aus CHANGELOG.md neben diesem Skript.
|
# - Ohne -Changelog: der Abschnitt "## <Version>" aus CHANGELOG.md neben diesem Skript.
|
||||||
# - Ist -File ein Ordner (Server: publish\), wird er ohne .pdb-Dateien gezippt.
|
# - Dateien im Release: die Datei (Launcher als BSO-Launcher-Setup.exe) und bso-release.json mit Version, SHA-256 und
|
||||||
# Braucht: Release-Schluessel (BSO-Launcher\new-release-key.ps1), BSO_RELEASE_TOKEN (= RELEASE_TOKEN der Website),
|
# Signatur. Signiert wird "BSO-RELEASE|produkt|version|sha256" - der Launcher prueft das mit dem eingebauten
|
||||||
# optional BSO_MASTER_URL (Standard https://bso.mbm.wtf). Beide auch als Windows-Benutzervariable.
|
# oeffentlichen Schluessel, egal woher die Datei kommt.
|
||||||
# Signiert wird "BSO-RELEASE|produkt|version|sha256" - der Launcher prueft das mit dem eingebauten oeffentlichen Schluessel.
|
# Braucht: Release-Schluessel (BSO-Launcher\new-release-key.ps1) und BSO_GITEA_TOKEN (Gitea: Einstellungen -> Anwendungen
|
||||||
|
# -> Token mit "repository: Lesen und Schreiben"), auch als Windows-Benutzervariable. Optional BSO_GITEA_URL.
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)][ValidateSet("mod", "launcher", "server")][string]$Product,
|
[Parameter(Mandatory)][ValidateSet("mod", "launcher")][string]$Product,
|
||||||
[Parameter(Mandatory)][string]$Version,
|
[Parameter(Mandatory)][string]$Version,
|
||||||
[Parameter(Mandatory)][string]$File,
|
[Parameter(Mandatory)][string]$File,
|
||||||
[string]$Changelog = ""
|
[string]$Changelog = ""
|
||||||
@@ -22,12 +24,14 @@ function Setting([string]$name) {
|
|||||||
if (-not $v) { $v = [Environment]::GetEnvironmentVariable($name, "User") }
|
if (-not $v) { $v = [Environment]::GetEnvironmentVariable($name, "User") }
|
||||||
return $v
|
return $v
|
||||||
}
|
}
|
||||||
$master = ((Setting "BSO_MASTER_URL"), "https://bso.mbm.wtf" | Where-Object { $_ } | Select-Object -First 1).TrimEnd('/')
|
$gitea = ((Setting "BSO_GITEA_URL"), "https://git.mbm.wtf" | Where-Object { $_ } | Select-Object -First 1).TrimEnd('/')
|
||||||
$token = Setting "BSO_RELEASE_TOKEN"
|
$token = Setting "BSO_GITEA_TOKEN"
|
||||||
if (-not $token) { Write-Host "BSO_RELEASE_TOKEN nicht gesetzt - nicht hochgeladen"; return }
|
if (-not $token) { Write-Host "BSO_GITEA_TOKEN nicht gesetzt - kein Release angelegt"; return }
|
||||||
$keyFile = Join-Path $env:APPDATA "BSO\release-key.dpapi"
|
$keyFile = Join-Path $env:APPDATA "BSO\release-key.dpapi"
|
||||||
if (-not (Test-Path $keyFile)) { throw "Kein Release-Schluessel ($keyFile) - erst new-release-key.ps1 im BSO-Launcher-Repo" }
|
if (-not (Test-Path $keyFile)) { throw "Kein Release-Schluessel ($keyFile) - erst new-release-key.ps1 im BSO-Launcher-Repo" }
|
||||||
$Version = $Version.Split('+')[0]
|
$Version = $Version.Split('+')[0]
|
||||||
|
$repo = @{ mod = "BSO-Mod"; launcher = "BSO-Launcher" }[$Product]
|
||||||
|
$api = "$gitea/api/v1/repos/MrMaho/$repo"
|
||||||
|
|
||||||
# Changelog aus CHANGELOG.md: alles unter "## <Version>" bis zur naechsten "## "-Zeile
|
# Changelog aus CHANGELOG.md: alles unter "## <Version>" bis zur naechsten "## "-Zeile
|
||||||
if (-not $Changelog) {
|
if (-not $Changelog) {
|
||||||
@@ -44,15 +48,8 @@ if (-not $Changelog) {
|
|||||||
if ($Changelog) { Write-Host "Changelog aus CHANGELOG.md ($Version)" } else { Write-Host "Kein Changelog fuer $Version in CHANGELOG.md" }
|
if ($Changelog) { Write-Host "Changelog aus CHANGELOG.md ($Version)" } else { Write-Host "Kein Changelog fuer $Version in CHANGELOG.md" }
|
||||||
}
|
}
|
||||||
|
|
||||||
# Ordner (dotnet publish) -> zip
|
|
||||||
$path = (Resolve-Path $File).Path
|
$path = (Resolve-Path $File).Path
|
||||||
if (Test-Path $path -PathType Container) {
|
$fileName = if ($Product -eq "launcher") { "BSO-Launcher-Setup.exe" } else { Split-Path $path -Leaf }
|
||||||
$zip = Join-Path $env:TEMP "BSO-$Product-$Version.zip"
|
|
||||||
Remove-Item $zip -ErrorAction SilentlyContinue
|
|
||||||
Compress-Archive -Path (Get-ChildItem $path -File | Where-Object Extension -ne ".pdb").FullName -DestinationPath $zip
|
|
||||||
$path = $zip
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = [IO.File]::ReadAllBytes($path)
|
$data = [IO.File]::ReadAllBytes($path)
|
||||||
$sha = ([System.Security.Cryptography.SHA256]::Create().ComputeHash($data) | ForEach-Object { $_.ToString("x2") }) -join ""
|
$sha = ([System.Security.Cryptography.SHA256]::Create().ComputeHash($data) | ForEach-Object { $_.ToString("x2") }) -join ""
|
||||||
$private = [System.Security.Cryptography.ProtectedData]::Unprotect([IO.File]::ReadAllBytes($keyFile), $null,
|
$private = [System.Security.Cryptography.ProtectedData]::Unprotect([IO.File]::ReadAllBytes($keyFile), $null,
|
||||||
@@ -62,18 +59,27 @@ $rsa.FromXmlString([Text.Encoding]::UTF8.GetString($private))
|
|||||||
$message = [Text.Encoding]::UTF8.GetBytes("BSO-RELEASE|$Product|$Version|$sha")
|
$message = [Text.Encoding]::UTF8.GetBytes("BSO-RELEASE|$Product|$Version|$sha")
|
||||||
$signature = [Convert]::ToBase64String($rsa.SignData($message, [System.Security.Cryptography.HashAlgorithmName]::SHA256,
|
$signature = [Convert]::ToBase64String($rsa.SignData($message, [System.Security.Cryptography.HashAlgorithmName]::SHA256,
|
||||||
[System.Security.Cryptography.RSASignaturePadding]::Pkcs1))
|
[System.Security.Cryptography.RSASignaturePadding]::Pkcs1))
|
||||||
|
$manifest = [ordered]@{ product = $Product; version = $Version; sha256 = $sha; size = $data.Length; file = $fileName; signature = $signature } |
|
||||||
|
ConvertTo-Json -Compress
|
||||||
|
|
||||||
$http = New-Object System.Net.Http.HttpClient
|
$http = New-Object System.Net.Http.HttpClient
|
||||||
$http.Timeout = [TimeSpan]::FromMinutes(10)
|
$http.Timeout = [TimeSpan]::FromMinutes(10)
|
||||||
$http.DefaultRequestHeaders.Authorization = New-Object System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", $token)
|
$http.DefaultRequestHeaders.Authorization = New-Object System.Net.Http.Headers.AuthenticationHeaderValue("token", $token)
|
||||||
$form = New-Object System.Net.Http.MultipartFormDataContent
|
|
||||||
foreach ($pair in @(@("product", $Product), @("version", $Version), @("changelog", $Changelog), @("signature", $signature))) {
|
# Release anlegen (Tag v<Version>)
|
||||||
$form.Add((New-Object System.Net.Http.StringContent($pair[1])), "`"$($pair[0])`"")
|
$json = @{ tag_name = "v$Version"; name = "$Product $Version"; body = $Changelog; draft = $false; prerelease = $false } | ConvertTo-Json -Compress
|
||||||
}
|
$res = $http.PostAsync("$api/releases", (New-Object System.Net.Http.StringContent($json, [Text.Encoding]::UTF8, "application/json"))).Result
|
||||||
$content = New-Object System.Net.Http.ByteArrayContent(, $data)
|
|
||||||
$form.Add($content, "`"file`"", "`"$(Split-Path $path -Leaf)`"")
|
|
||||||
$res = $http.PostAsync("$master/api/releases/upload", $form).Result
|
|
||||||
$body = $res.Content.ReadAsStringAsync().Result
|
$body = $res.Content.ReadAsStringAsync().Result
|
||||||
if ($res.StatusCode -eq [Net.HttpStatusCode]::Conflict) { Write-Host "$Product $Version gibt es schon auf $master - Version in der .csproj erhoehen"; return }
|
if ($res.StatusCode -eq [Net.HttpStatusCode]::Conflict) { Write-Host "$repo v$Version gibt es schon - Version erhoehen"; return }
|
||||||
if (-not $res.IsSuccessStatusCode) { throw "Hochladen fehlgeschlagen ($([int]$res.StatusCode)): $body" }
|
if (-not $res.IsSuccessStatusCode) { throw "Release anlegen fehlgeschlagen ($([int]$res.StatusCode)): $body" }
|
||||||
Write-Host "$Product $Version hochgeladen nach $master (sha256 $sha)"
|
$id = ($body | ConvertFrom-Json).id
|
||||||
|
|
||||||
|
function Upload([string]$name, [byte[]]$bytes) {
|
||||||
|
$form = New-Object System.Net.Http.MultipartFormDataContent
|
||||||
|
$form.Add((New-Object System.Net.Http.ByteArrayContent(, $bytes)), "`"attachment`"", "`"$name`"")
|
||||||
|
$r = $http.PostAsync("$api/releases/$id/assets?name=$([Uri]::EscapeDataString($name))", $form).Result
|
||||||
|
if (-not $r.IsSuccessStatusCode) { throw "Hochladen von $name fehlgeschlagen ($([int]$r.StatusCode)): $($r.Content.ReadAsStringAsync().Result)" }
|
||||||
|
}
|
||||||
|
Upload $fileName $data
|
||||||
|
Upload "bso-release.json" ([Text.Encoding]::UTF8.GetBytes($manifest))
|
||||||
|
Write-Host "$Product $Version veroeffentlicht: $gitea/MrMaho/$repo/releases/tag/v$Version (sha256 $sha)"
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ async function renderHome(root) {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const ready = s.game.found && s.dotnet && (s.mod.installed || s.mod.latest);
|
const ready = s.game.found && s.dotnet && (s.mod.installed || s.mod.latest);
|
||||||
const line = s.mod.installed ? t("BSO {0} installiert · Server {1}", s.mod.installed, s.settings.server) : t("BSO wird beim ersten Start installiert");
|
const line = s.mod.installed ? t("BSO {0} installiert · zusammen spielen unter Freunde & Lobby", s.mod.installed) : t("BSO wird beim ersten Start installiert");
|
||||||
|
|
||||||
const children = [
|
const children = [
|
||||||
h("div", { class: "hero" },
|
h("div", { class: "hero" },
|
||||||
@@ -201,7 +201,7 @@ async function renderHome(root) {
|
|||||||
if (!s.masterReachable)
|
if (!s.masterReachable)
|
||||||
children.push(h("div", { class: "banner warn" }, h("span", {}, t("BSO-Server nicht erreichbar - Updates werden spaeter geprueft."))));
|
children.push(h("div", { class: "banner warn" }, h("span", {}, t("BSO-Server nicht erreichbar - Updates werden spaeter geprueft."))));
|
||||||
|
|
||||||
children.push(h("div", { class: "cards" }, gameCard(s), modCard(s), dotnetCard(s), serverCard(s)));
|
children.push(h("div", { class: "cards" }, gameCard(s), modCard(s), dotnetCard(s)));
|
||||||
root.replaceChildren(...children);
|
root.replaceChildren(...children);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,18 +246,6 @@ function dotnetCard(s) {
|
|||||||
h("div", { class: "row" }, b));
|
h("div", { class: "row" }, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
function serverCard(s) {
|
|
||||||
const input = h("input", { value: s.settings.server, placeholder: "host:7777", spellcheck: "false" });
|
|
||||||
const auto = h("input", { type: "checkbox" });
|
|
||||||
auto.checked = s.settings.autoConnect;
|
|
||||||
const save = () => call("setSettings", { server: input.value.trim(), autoConnect: auto.checked }).then(() => toast(t("Gespeichert")));
|
|
||||||
input.addEventListener("change", save);
|
|
||||||
auto.addEventListener("change", save);
|
|
||||||
return card("Server", "ok", t("Mitspielen"),
|
|
||||||
h("label", {}, h("span", {}, t("Adresse")), input),
|
|
||||||
h("label", { class: "switch" }, h("span", {}, t("Beim Start verbinden"), h("small", {}, t("sonst im Spiel mit F8"))), auto));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------- Freunde & Lobby
|
// ---------------------------------------------------------------- Freunde & Lobby
|
||||||
// Die Lobby liegt auf der Website, ihr Server laeuft im BSO-Relay - keiner hostet, keiner braucht eine Portfreigabe.
|
// Die Lobby liegt auf der Website, ihr Server laeuft im BSO-Relay - keiner hostet, keiner braucht eine Portfreigabe.
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -16,7 +16,7 @@ const EN = {
|
|||||||
"Spielen": "Play", "Freunde": "Friends", "Neuigkeiten": "News", "Einstellungen": "Settings", "Laden …": "Loading …",
|
"Spielen": "Play", "Freunde": "Friends", "Neuigkeiten": "News", "Einstellungen": "Settings", "Laden …": "Loading …",
|
||||||
// Spielen
|
// Spielen
|
||||||
"SPIELEN": "PLAY", "LAEUFT": "RUNNING", "Bus-Simulator 2012 startet …": "Bus-Simulator 2012 is starting …",
|
"SPIELEN": "PLAY", "LAEUFT": "RUNNING", "Bus-Simulator 2012 startet …": "Bus-Simulator 2012 is starting …",
|
||||||
"BSO {0} installiert · Server {1}": "BSO {0} installed · Server {1}", "BSO wird beim ersten Start installiert": "BSO will be installed on first start",
|
"BSO {0} installiert · zusammen spielen unter Freunde & Lobby": "BSO {0} installed · play together under Friends & lobby", "BSO wird beim ersten Start installiert": "BSO will be installed on first start",
|
||||||
"Multiplayer fuer Bus-Simulator 2012": "Multiplayer for Bus-Simulator 2012",
|
"Multiplayer fuer Bus-Simulator 2012": "Multiplayer for Bus-Simulator 2012",
|
||||||
"Vor dem Start fehlt noch etwas - siehe unten": "Something is still missing - see below",
|
"Vor dem Start fehlt noch etwas - siehe unten": "Something is still missing - see below",
|
||||||
"Jetzt aktualisieren": "Update now", "Launcher startet neu …": "Launcher is restarting …", "Launcher {0}": "Launcher {0}", " ist da.": " is available.",
|
"Jetzt aktualisieren": "Update now", "Launcher startet neu …": "Launcher is restarting …", "Launcher {0}": "Launcher {0}", " ist da.": " is available.",
|
||||||
@@ -28,7 +28,7 @@ const EN = {
|
|||||||
"Neu herunterladen": "Download again", "BSO {0} installiert": "BSO {0} installed",
|
"Neu herunterladen": "Download again", "BSO {0} installiert": "BSO {0} installed",
|
||||||
"Installiert": "Installed", "Die Mod laeuft mit .NET 10 (x64).": "The mod runs on .NET 10 (x64).", "Herunterladen": "Download", "Fehlt": "Missing",
|
"Installiert": "Installed", "Die Mod laeuft mit .NET 10 (x64).": "The mod runs on .NET 10 (x64).", "Herunterladen": "Download", "Fehlt": "Missing",
|
||||||
"BSO braucht die .NET 10 Runtime (x64) - \".NET Runtime\" fuer Windows x64 installieren.": "BSO needs the .NET 10 Runtime (x64) - install \".NET Runtime\" for Windows x64.",
|
"BSO braucht die .NET 10 Runtime (x64) - \".NET Runtime\" fuer Windows x64 installieren.": "BSO needs the .NET 10 Runtime (x64) - install \".NET Runtime\" for Windows x64.",
|
||||||
"Mitspielen": "Play together", "Adresse": "Address", "Gespeichert": "Saved", "Beim Start verbinden": "Connect on start", "sonst im Spiel mit F8": "otherwise in game with F8",
|
"Gespeichert": "Saved",
|
||||||
// Freunde & Lobby
|
// Freunde & Lobby
|
||||||
"Freunde & Lobby": "Friends & lobby", "{0} lädt dich in die Lobby ein": "{0} invites you to their lobby", " lädt dich in die Lobby ein": " invites you to their lobby",
|
"Freunde & Lobby": "Friends & lobby", "{0} lädt dich in die Lobby ein": "{0} invites you to their lobby", " lädt dich in die Lobby ein": " invites you to their lobby",
|
||||||
"{0} möchte dein Freund sein": "{0} wants to be your friend", "Beitreten": "Join", "Ablehnen": "Decline", "Lobby": "Lobby",
|
"{0} möchte dein Freund sein": "{0} wants to be your friend", "Beitreten": "Join", "Ablehnen": "Decline", "Lobby": "Lobby",
|
||||||
|
|||||||
Reference in New Issue
Block a user