Skip to content

Commit

Permalink
Always use the same SourceForge mirror
Browse files Browse the repository at this point in the history
  • Loading branch information
HebaruSan committed Sep 5, 2024
1 parent f475493 commit 107303c
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 25 deletions.
50 changes: 28 additions & 22 deletions Core/Net/Net.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Net;
Expand All @@ -9,6 +10,7 @@
using ChinhDo.Transactions.FileManager;
using log4net;

using CKAN.Extensions;
using CKAN.Configuration;

namespace CKAN
Expand Down Expand Up @@ -198,33 +200,37 @@ public static string Download(string url, out string? etag, string? filename = n
}

public static Uri? ResolveRedirect(Uri url,
string? userAgent = "")
string? userAgent = null,
int maxRedirects = 6)
{
const int maxRedirects = 6;
for (int redirects = 0; redirects <= maxRedirects; ++redirects)
var urls = url.TraverseNodes(u => new RedirectWebClient(userAgent) is RedirectWebClient rwClient
&& rwClient.OpenRead(u) is Stream s && DisposeStream(s)
&& rwClient.ResponseHeaders is WebHeaderCollection headers
&& headers["Location"] is string location
? Uri.IsWellFormedUriString(location, UriKind.Absolute)
? new Uri(location)
: Uri.IsWellFormedUriString(location, UriKind.Relative)
? new Uri(u, location)
: throw new Kraken(string.Format(Properties.Resources.NetInvalidLocation,
location))
: null)
// The first element is the input, so e.g. if we want two redirects, that's three elements
.Take(maxRedirects + 1)
.ToArray();
if (log.IsDebugEnabled)
{
var rwClient = new RedirectWebClient(userAgent);
using (rwClient.OpenRead(url)) { }
var location = rwClient.ResponseHeaders?["Location"];
if (location == null)
foreach ((Uri from, Uri to) in urls.Zip(urls.Skip(1)))
{
return url;
}
else if (Uri.IsWellFormedUriString(location, UriKind.Absolute))
{
url = new Uri(location);
}
else if (Uri.IsWellFormedUriString(location, UriKind.Relative))
{
url = new Uri(url, location);
log.DebugFormat("Relative URL {0} is absolute URL {1}", location, url);
}
else
{
throw new Kraken(string.Format(Properties.Resources.NetInvalidLocation, location));
log.DebugFormat("Redirected {0} to {1}", from, to);
}
}
return null;
return urls.LastOrDefault();
}

private static bool DisposeStream(Stream s)
{
s.Dispose();
return true;
}

/// <summary>
Expand Down
33 changes: 30 additions & 3 deletions Netkan/Transformers/SourceForgeTransformer.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Linq;
using System.Web;
using System.Collections.Generic;
using System.Collections.Specialized;

using Newtonsoft.Json.Linq;
using log4net;
Expand Down Expand Up @@ -74,8 +76,18 @@ private static Metadata TransformOne(JObject json,
{ "bugtracker", mod.BugTrackerLink },
}));
// SourceForge doesn't send redirects to user agents it considers browser-like
json.SafeAdd("download", Net.ResolveRedirect(version.Link, "Wget")
?.OriginalString);
if (Net.ResolveRedirect(version.Link, "Wget", 1) is Uri firstRedir)
{
// SourceForge redirects to different mirrors for load-balancing
// (IF it considers your user agent string a non-browser, which excludes the CKAN client),
// but for us that means CKAN users constantly shifting from one server
// to another in unison as the bot changes the URL in the metadata.
// https://sourceforge.net/p/forge/documentation/Mirrors/
// Tweak the intermediate redirect URL to use the same mirror every time.
json.SafeAdd("download", Net.ResolveRedirect(SetQueryKey(firstRedir, "use_mirror", mirror),
"Wget", 1)
?.OriginalString);
}
json.SafeAdd(Metadata.UpdatedPropertyName, version.Timestamp);

json.Remove("$kref");
Expand All @@ -84,7 +96,22 @@ private static Metadata TransformOne(JObject json,
return new Metadata(json);
}

private static Uri SetQueryKey(Uri url, string key, string value)
{
if (HttpUtility.ParseQueryString(url.Query) is NameValueCollection newQuery)
{
newQuery.Set(key, value);
return new UriBuilder(url)
{
Query = newQuery.ToString(),
}.Uri;

}
return url;
}

private readonly ISourceForgeApi api;
private static readonly ILog log = LogManager.GetLogger(typeof(GitlabTransformer));
private const string mirror = "psychz"; // Brooklyn, United States
private static readonly ILog log = LogManager.GetLogger(typeof(GitlabTransformer));
}
}

0 comments on commit 107303c

Please sign in to comment.