From cf3996a51fdb9de308542fbae0f8704548bd05ff Mon Sep 17 00:00:00 2001 From: Goober5000 Date: Wed, 6 May 2026 00:31:56 -0400 Subject: [PATCH] Fix 504 Gateway Timeout falsely reported as success in Nebula API calls Previously, a GatewayTimeout response from any of mod/release, mod/release/update, mod/release/delete, or multiupload/finish was silently converted into a fabricated { result: true } reply, causing the UI to report success when the server may never have processed the request. - multiupload/finish: now returns null on 504, allowing Finish() to use its existing retry loop and CheckUploadDone() verification path rather than bypassing it with a fake success. - mod/release, mod/release/update, mod/release/delete: now return a non-null ApiReply with gatewayTimeout=true (result=false). The three callers (ReleaseMod, UpdateMetaData, DeleteModVersion) surface a clear warning asking the user to verify the operation on the Nebula website, rather than silently claiming it succeeded. Also fixes the 504 status code check from a fragile .ToString() string comparison to the correct HttpStatusCode enum value. Co-Authored-By: Claude Sonnet 4.6 --- Knossos.NET/Models/Nebula.cs | 41 +++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/Knossos.NET/Models/Nebula.cs b/Knossos.NET/Models/Nebula.cs index d1de0324..342dd0cd 100644 --- a/Knossos.NET/Models/Nebula.cs +++ b/Knossos.NET/Models/Nebula.cs @@ -715,7 +715,10 @@ private struct ApiReply [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool done { get; set; } - + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool gatewayTimeout { get; set; } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public Mod mod { get; set; } } @@ -815,14 +818,21 @@ private enum ApiMethod } } data.Dispose(); - /* Upload/Update/delete Mod Timeout Hack */ - if(response.StatusCode.ToString() == "GatewayTimeout" && (resourceUrl == "mod/release" || resourceUrl == "mod/release/update" || resourceUrl == "mod/release/delete" || resourceUrl == "multiupload/finish")) + if (response.StatusCode == System.Net.HttpStatusCode.GatewayTimeout) { - Log.Add(Log.LogSeverity.Warning, "Nebula.ApiCall(" + resourceUrl + ")", "A GatewayTimeout was received. This is a known issue with Nebula and while Knet handles this" + - " as a success there is not an actual way to know if the api call was really successfull."); - var reply = new ApiReply(); - reply.result = true; - return reply; + if (resourceUrl == "multiupload/finish") + { + /* Finish() has retry + CheckUploadDone() verification for null replies — let it handle this */ + Log.Add(Log.LogSeverity.Warning, "Nebula.ApiCall(" + resourceUrl + ")", "A GatewayTimeout was received. Returning null so Finish() can verify server state."); + return null; + } + if (resourceUrl == "mod/release" || resourceUrl == "mod/release/update" || resourceUrl == "mod/release/delete") + { + Log.Add(Log.LogSeverity.Warning, "Nebula.ApiCall(" + resourceUrl + ")", "A GatewayTimeout was received. Operation status is unknown — the server may have processed the request after the proxy timed out."); + var reply = new ApiReply(); + reply.gatewayTimeout = true; + return reply; + } } } Log.Add(Log.LogSeverity.Error, "Nebula.ApiCall(" + resourceUrl + ")", "An error has ocurred during nebula api POST call: " + response.StatusCode + "(" + (int)response.StatusCode + ")"); @@ -1433,6 +1443,11 @@ public static async Task IsModEditable(string id) Log.Add(Log.LogSeverity.Information, "Nebula.DeleteModVersion", "Deleted mod/version : " + mod + " from Nebula."); return "ok"; } + else if (reply.Value.gatewayTimeout) + { + Log.Add(Log.LogSeverity.Warning, "Nebula.DeleteModVersion", "Server timed out. The deletion may or may not have succeeded. Please verify on the Nebula website."); + return "Server timed out — please verify the deletion on the Nebula website."; + } else { Log.Add(Log.LogSeverity.Error, "Nebula.DeleteModVersion", "Error while deleting mod/version: " + mod + " Reason: " + reply.Value.reason); @@ -1694,6 +1709,11 @@ public static async Task IsFileUploaded(string? checksum = null, string? c Log.Add(Log.LogSeverity.Information, "Nebula.ReleaseMod", "ReleaseMod: " + mod + " OK!"); return "ok"; } + else if (reply.Value.gatewayTimeout) + { + Log.Add(Log.LogSeverity.Warning, "Nebula.ReleaseMod", "Server timed out. The release may or may not have succeeded. Please verify on the Nebula website."); + return "Server timed out — please verify the release on the Nebula website."; + } else { Log.Add(Log.LogSeverity.Error, "Nebula.ReleaseMod", "ReleaseMod: " + mod + " error. Reason: " + reply.Value.reason); @@ -1730,6 +1750,11 @@ public static async Task IsFileUploaded(string? checksum = null, string? c Log.Add(Log.LogSeverity.Information, "Nebula.UpdateMetaData", "UpdateMetaData: " + mod + " OK!"); return "ok"; } + else if (reply.Value.gatewayTimeout) + { + Log.Add(Log.LogSeverity.Warning, "Nebula.UpdateMetaData", "Server timed out. The metadata update may or may not have succeeded. Please verify on the Nebula website."); + return "Server timed out — please verify the metadata update on the Nebula website."; + } else { Log.Add(Log.LogSeverity.Error, "Nebula.UpdateMetaData", "UpdateMetaData: " + mod + " error. Reason: " + reply.Value.reason);