Skip to content

Commit 83ea0b8

Browse files
committed
Reapply "Small fix"
This reverts commit 7fe2e63.
1 parent 7fe2e63 commit 83ea0b8

File tree

15 files changed

+402
-81
lines changed

15 files changed

+402
-81
lines changed

Marsey/MarseyPatcher.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@ private void ExecPatcher()
137137

138138
private void Afterparty()
139139
{
140-
// TODO: Test if GameAssemblies.ClientInitialized works here
141140
while (!GameAssemblies.ClientInitialized()) // Wait until EntryPoint is just about to start
142141
{
143142
Thread.Sleep(125);

SS14.Launcher/ConfigConstants.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ public static class ConfigConstants
5353
public static readonly UrlFallbackSet RobustBuildsManifest = RobustBuildsBaseUrl + "manifest.json";
5454
public static readonly UrlFallbackSet RobustModulesManifest = RobustBuildsBaseUrl + "modules.json";
5555

56-
// How long to keep cached copies of Robust manifests.
57-
// TODO: Take this from Cache-Control header responses instead.
56+
// Default cache duration for Robust manifests when response headers don't specify caching.
5857
public static readonly TimeSpan RobustManifestCacheTime = TimeSpan.FromMinutes(15);
5958

6059
public static readonly UrlFallbackSet UrlLauncherInfo = LauncherDataBaseUrl + "info.json";

SS14.Launcher/Helpers.cs

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,12 @@ public static async Task<T> AsJson<T>(this HttpContent content) where T : notnul
155155

156156
public static unsafe void MarkDirectoryCompress(string path)
157157
{
158-
// TODO: Linux: chattr +c
158+
if (OperatingSystem.IsLinux())
159+
{
160+
TryEnableLinuxDirectoryCompression(path);
161+
return;
162+
}
163+
159164
if (!OperatingSystem.IsWindows())
160165
return;
161166

@@ -187,6 +192,43 @@ public static unsafe void MarkDirectoryCompress(string path)
187192
}
188193
}
189194

195+
private static void TryEnableLinuxDirectoryCompression(string path)
196+
{
197+
try
198+
{
199+
var psi = new ProcessStartInfo("chattr")
200+
{
201+
RedirectStandardError = true,
202+
RedirectStandardOutput = true,
203+
UseShellExecute = false
204+
};
205+
psi.ArgumentList.Add("+c");
206+
psi.ArgumentList.Add(path);
207+
208+
using var proc = Process.Start(psi);
209+
if (proc == null)
210+
{
211+
Log.Debug("Failed to start chattr for {Path}", path);
212+
return;
213+
}
214+
215+
if (!proc.WaitForExit(2000))
216+
{
217+
Log.Debug("chattr timed out for {Path}", path);
218+
return;
219+
}
220+
221+
if (proc.ExitCode != 0)
222+
{
223+
Log.Debug("chattr exited with code {ExitCode} for {Path}", proc.ExitCode, path);
224+
}
225+
}
226+
catch (Exception e)
227+
{
228+
Log.Debug(e, "Failed to enable chattr +c for {Path}", path);
229+
}
230+
}
231+
190232
public static void ChmodPlusX(string path)
191233
{
192234
var f = new UnixFileInfo(path);

SS14.Launcher/LauncherDiagnostics.cs

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
using System;
22
using System.Collections.Generic;
33
using System.ComponentModel;
4+
using System.IO;
45
using System.Runtime;
56
using System.Runtime.InteropServices;
67
using System.Runtime.Intrinsics.Arm;
78
using System.Runtime.Intrinsics.X86;
89
using System.Text;
10+
using Microsoft.Win32;
911
using Serilog;
1012
using SQLitePCL;
1113
using X86Aes = System.Runtime.Intrinsics.X86.Aes;
@@ -138,7 +140,9 @@ public static string GetProcessorModel()
138140
return name;
139141
}
140142

141-
// TODO: ask OS as fallback for when x86 CPUID isn't available on Windows and Linux.
143+
var osName = GetProcessorModelFromOs();
144+
if (osName != null)
145+
return osName;
142146

143147
return "Unknown processor model";
144148
}
@@ -191,6 +195,56 @@ public static string GetProcessorModel()
191195
}
192196
}
193197

198+
private static string? GetProcessorModelFromOs()
199+
{
200+
if (OperatingSystem.IsWindows())
201+
{
202+
try
203+
{
204+
using var key = Registry.LocalMachine.OpenSubKey(
205+
@"HARDWARE\DESCRIPTION\System\CentralProcessor\0",
206+
writable: false);
207+
var value = key?.GetValue("ProcessorNameString") as string;
208+
if (!string.IsNullOrWhiteSpace(value))
209+
return value.Trim();
210+
}
211+
catch (Exception e)
212+
{
213+
Log.Debug(e, "Failed to read CPU model from registry");
214+
}
215+
216+
var env = Environment.GetEnvironmentVariable("PROCESSOR_IDENTIFIER");
217+
if (!string.IsNullOrWhiteSpace(env))
218+
return env.Trim();
219+
}
220+
221+
if (OperatingSystem.IsLinux())
222+
{
223+
try
224+
{
225+
foreach (var line in File.ReadLines("/proc/cpuinfo"))
226+
{
227+
if (!line.StartsWith("model name", StringComparison.OrdinalIgnoreCase))
228+
continue;
229+
230+
var sep = line.IndexOf(':');
231+
if (sep < 0)
232+
continue;
233+
234+
var name = line[(sep + 1)..].Trim();
235+
if (!string.IsNullOrWhiteSpace(name))
236+
return name;
237+
}
238+
}
239+
catch (Exception e)
240+
{
241+
Log.Debug(e, "Failed to read CPU model from /proc/cpuinfo");
242+
}
243+
}
244+
245+
return null;
246+
}
247+
194248
[DllImport("libc", SetLastError = true)]
195249
private static extern unsafe int sysctlbyname(
196250
byte* name,

SS14.Launcher/Models/Connector.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ private async Task LaunchClientWrap(
394394
Uri? parsedAddr,
395395
bool contentBundle)
396396
{
397+
await _loginManager.WaitForTokenRefreshAsync();
397398

398399
var cVars = new List<(string, string)>();
399400

@@ -811,7 +812,6 @@ private async Task Marsify()
811812
MarseyCleanup();
812813
}
813814

814-
// TODO: Make this a json or something like holy shit
815815
private async Task ConfigureMarsey()
816816
{
817817
// Prepare environment variables
@@ -843,7 +843,7 @@ private async Task ConfigureMarsey()
843843
};
844844

845845
// Serialize environment variables
846-
string serializedEnvVars = string.Join(";", envVars.Select(kv => $"{kv.Key}={kv.Value}"));
846+
string serializedEnvVars = JsonSerializer.Serialize(envVars);
847847

848848
await SendConfig(serializedEnvVars);
849849
}

SS14.Launcher/Models/Data/DataManager.cs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,8 @@ public sealed class DataManager : ReactiveObject
5555

5656
private readonly Dictionary<string, CVarEntry> _configEntries = new();
5757

58-
// TODO: I got lazy and this is a flat list.
59-
// This probably results in some bad O(n*m) behavior.
60-
// I don't care for now.
6158
private readonly List<InstalledEngineModule> _modules = new();
59+
private readonly HashSet<EngineModuleKey> _moduleLookup = new();
6260

6361
private readonly List<DbCommand> _dbCommandQueue = new();
6462
private readonly SemaphoreSlim _dbWritingSemaphore = new(1);
@@ -133,6 +131,7 @@ public Guid? SelectedLoginId
133131
public IObservableCache<LoginInfo, Guid> Logins => _logins;
134132
public IObservableCache<InstalledEngineVersion, string> EngineInstallations => _engineInstallations;
135133
public IEnumerable<InstalledEngineModule> EngineModules => _modules;
134+
public bool HasEngineModule(string name, string version) => _moduleLookup.Contains(new EngineModuleKey(name, version));
136135
public ICollection<ServerFilter> Filters { get; }
137136
public ICollection<Hub> Hubs { get; }
138137

@@ -180,12 +179,18 @@ public void RemoveEngineInstallation(InstalledEngineVersion version)
180179

181180
public void AddEngineModule(InstalledEngineModule module)
182181
{
182+
if (!_moduleLookup.Add(new EngineModuleKey(module.Name, module.Version)))
183+
return;
184+
183185
_modules.Add(module);
184186
AddDbCommand(c => c.Execute("INSERT INTO EngineModule VALUES (@Name, @Version)", module));
185187
}
186188

187189
public void RemoveEngineModule(InstalledEngineModule module)
188190
{
191+
if (!_moduleLookup.Remove(new EngineModuleKey(module.Name, module.Version)))
192+
return;
193+
189194
_modules.Remove(module);
190195
AddDbCommand(c => c.Execute("DELETE FROM EngineModule WHERE Name = @Name AND Version = @Version", module));
191196
}
@@ -317,7 +322,12 @@ private void LoadSqliteConfig(SqliteConnection sqliteConnection)
317322
sqliteConnection.Query<InstalledEngineVersion>("SELECT Version,Signature FROM EngineInstallation"));
318323

319324
// Engine modules
320-
_modules.AddRange(sqliteConnection.Query<InstalledEngineModule>("SELECT Name, Version FROM EngineModule"));
325+
var loadedModules = sqliteConnection.Query<InstalledEngineModule>("SELECT Name, Version FROM EngineModule");
326+
foreach (var module in loadedModules)
327+
{
328+
_modules.Add(module);
329+
_moduleLookup.Add(new EngineModuleKey(module.Name, module.Version));
330+
}
321331

322332
// Load CVars.
323333
var configRows = sqliteConnection.Query<(string, object?)>("SELECT Key, Value FROM Config");
@@ -616,6 +626,8 @@ public void FireValueChanged()
616626
}
617627
}
618628

629+
private readonly record struct EngineModuleKey(string Name, string Version);
630+
619631
private sealed class ServerFilterCollection : ICollection<ServerFilter>
620632
{
621633
private readonly DataManager _parent;

SS14.Launcher/Models/EngineManager/EngineManagerDynamic.Manifest.cs

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Diagnostics;
4+
using System.Net.Http;
45
using System.Net.Http.Json;
6+
using System.Net.Http.Headers;
57
using System.Text.Json.Serialization;
68
using System.Threading;
79
using System.Threading.Tasks;
@@ -19,6 +21,8 @@ public sealed partial class EngineManagerDynamic
1921

2022
private Dictionary<string, VersionInfo>? _cachedRobustVersionInfo;
2123
private TimeSpan _robustCacheValidUntil;
24+
private EntityTagHeaderValue? _cachedManifestEtag;
25+
private DateTimeOffset? _cachedManifestLastModified;
2226

2327
/// <summary>
2428
/// Look up information about an engine version.
@@ -67,17 +71,42 @@ public sealed partial class EngineManagerDynamic
6771

6872
private async Task UpdateBuildManifest(CancellationToken cancel)
6973
{
70-
// TODO: If-Modified-Since and If-None-Match request conditions.
71-
7274
Log.Debug("Loading manifest from {manifestUrl}...", ConfigConstants.RobustBuildsManifest);
7375
using var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(cancel);
7476
timeoutCts.CancelAfter(ManifestLoadTimeout);
7577

7678
try
7779
{
80+
using var response = await ConfigConstants.RobustBuildsManifest.SendAsync(
81+
_http,
82+
url =>
83+
{
84+
var req = new HttpRequestMessage(HttpMethod.Get, url);
85+
if (_cachedManifestEtag != null)
86+
req.Headers.IfNoneMatch.Add(_cachedManifestEtag);
87+
if (_cachedManifestLastModified != null)
88+
req.Headers.IfModifiedSince = _cachedManifestLastModified;
89+
return req;
90+
},
91+
timeoutCts.Token);
92+
93+
if (response.StatusCode == System.Net.HttpStatusCode.NotModified && _cachedRobustVersionInfo != null)
94+
{
95+
Log.Debug("Manifest not modified, using cached copy");
96+
_robustCacheValidUntil = _manifestStopwatch.Elapsed + GetManifestCacheDuration(response);
97+
return;
98+
}
99+
100+
response.EnsureSuccessStatusCode();
101+
102+
_cachedManifestEtag = response.Headers.ETag;
103+
_cachedManifestLastModified = response.Content.Headers.LastModified;
104+
78105
_cachedRobustVersionInfo =
79-
await ConfigConstants.RobustBuildsManifest.GetFromJsonAsync<Dictionary<string, VersionInfo>>(
80-
_http, timeoutCts.Token);
106+
await response.Content.ReadFromJsonAsync<Dictionary<string, VersionInfo>>(timeoutCts.Token)
107+
?? throw new InvalidOperationException("Robust manifest response was empty.");
108+
109+
_robustCacheValidUntil = _manifestStopwatch.Elapsed + GetManifestCacheDuration(response);
81110
}
82111
catch (OperationCanceledException e) when (!cancel.IsCancellationRequested && timeoutCts.IsCancellationRequested)
83112
{
@@ -86,8 +115,25 @@ await ConfigConstants.RobustBuildsManifest.GetFromJsonAsync<Dictionary<string, V
86115
"Check your proxy/tunnel stability or disable proxy for launcher downloads.",
87116
e);
88117
}
118+
}
119+
120+
private static TimeSpan GetManifestCacheDuration(HttpResponseMessage? response)
121+
{
122+
if (response?.Headers.CacheControl?.NoStore == true || response?.Headers.CacheControl?.NoCache == true)
123+
return TimeSpan.Zero;
124+
125+
var maxAge = response?.Headers.CacheControl?.MaxAge;
126+
if (maxAge.HasValue)
127+
return maxAge.Value;
128+
129+
if (response?.Content.Headers.Expires is { } expires)
130+
{
131+
var delta = expires - DateTimeOffset.UtcNow;
132+
if (delta > TimeSpan.Zero)
133+
return delta;
134+
}
89135

90-
_robustCacheValidUntil = _manifestStopwatch.Elapsed + ConfigConstants.RobustManifestCacheTime;
136+
return ConfigConstants.RobustManifestCacheTime;
91137
}
92138

93139
private FoundVersionInfo? FindVersionInfoInCached(string version, bool followRedirects)

SS14.Launcher/Models/EngineManager/EngineManagerDynamic.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ public async Task<bool> DownloadModuleIfNecessary(
169169

170170
Log.Debug("Selected module {ModuleName} {ModuleVersion}", moduleName, moduleVersion);
171171

172-
var alreadyInstalled = _cfg.EngineModules.Any(m => m.Name == moduleName && m.Version == moduleVersion);
172+
var alreadyInstalled = _cfg.HasEngineModule(moduleName, moduleVersion);
173173

174174
if (alreadyInstalled)
175175
{

0 commit comments

Comments
 (0)