Files
MeWeb/src/MeWeb.Core/Knowledge/Providers.cs
T
thepraandClaude Opus 5.5 50c40195d3
Build / Desktop, server and tools (push) Successful in 1m15s
Release / Every platform, the server, the release (push) Successful in 26m55s
"me-web?" 0.12.0: every address block travels with the app
- The app now carries the whole RIPE Database list of address blocks, all five million, small single-customer blocks
  included, so the provider card and the path can name the block your connection belongs to without a connection to
  the publisher's server. The downloads are about 25 MB larger for it.
- When the publisher's server can't be reached, the provider card still names your network and its block, from the
  public address your router reports or the one the STUN test sees.
- The table is read a small piece at a time, so it takes almost no memory on a phone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012CzABvBkbcFqoHdmi8b9WB
2026-10-16 19:41:56 +02:00

120 lines
4.3 KiB
C#

using System.Text.Json;
using System.Text.Json.Serialization;
using MeWeb.Core.Net;
namespace MeWeb.Core.Knowledge;
public class ProviderFact
{
public string Value { get; set; }
public decimal? Price { get; set; }
public string Currency { get; set; }
public string Basis { get; set; }
public string Source { get; set; }
public string Date { get; set; }
}
public class ProviderProfile
{
public string Name { get; set; }
public string Country { get; set; }
public List<uint> Asns { get; set; } = [];
public string Sheet { get; set; }
public ProviderFact Ipv4 { get; set; }
public ProviderFact PublicAddress { get; set; }
public ProviderFact Ipv6 { get; set; }
public ProviderFact Port25 { get; set; }
}
[JsonSourceGenerationOptions(JsonSerializerDefaults.Web)]
[JsonSerializable(typeof(ProviderProfile))]
[JsonSerializable(typeof(List<Carrier>))]
[JsonSerializable(typeof(List<ObservedNetwork>))]
public partial class KnowledgeJsonContext : JsonSerializerContext
{
}
public sealed class KnowledgeBase(IPlatform platform)
{
readonly Lazy<AsnTable> asn = new(LoadAsn);
readonly Lazy<List<ProviderProfile>> providers = new(LoadProviders);
readonly Lazy<NetworkTable> networks = new(LoadNetworks);
readonly Lazy<RegistryTable> registry = new(() => LoadRegistry(platform));
readonly Lazy<Dictionary<string, string>> carriers = new(LoadCarriers);
readonly Lazy<List<ObservedNetwork>> observed = new(LoadObserved);
public bool HasAsnTable => typeof(KnowledgeBase).Assembly.GetManifestResourceInfo("ip2asn.bin") is not null;
public AsnTable Asn => asn.Value;
public IReadOnlyList<ProviderProfile> Providers => providers.Value;
public RegistryTable Registry => registry.Value;
public ProviderProfile ProviderFor(uint number) => number == 0 ? null : Providers.FirstOrDefault(p => p.Asns.Contains(number));
public ObservedNetwork ObservedFor(uint number, bool mobile) =>
number == 0 ? null : observed.Value.FirstOrDefault(o => o.Asn == number && o.Line == (mobile ? ObservedNetwork.Mobile : ObservedNetwork.Home));
public NetworkInfo NetworkFor(uint number) => number == 0 ? null : networks.Value?.Find(number);
public string CarrierFor(string mccMnc) => string.IsNullOrEmpty(mccMnc) ? null : carriers.Value.GetValueOrDefault(mccMnc);
public string NameOf(uint number) => NetworkFor(number)?.Organisation ?? Asn?.Find(number)?.Name;
static NetworkTable LoadNetworks()
{
using var stream = typeof(KnowledgeBase).Assembly.GetManifestResourceStream("networks.bin");
return stream is null ? null : NetworkTable.Read(stream);
}
static RegistryTable LoadRegistry(IPlatform platform)
{
var stream = platform.OpenRegistry();
if (stream is null) return null;
try
{
return RegistryTable.Open(stream);
}
catch (Exception ex) when (ex is IOException or InvalidDataException or EndOfStreamException)
{
stream.Dispose();
return null;
}
}
static Dictionary<string, string> LoadCarriers()
{
using var stream = typeof(KnowledgeBase).Assembly.GetManifestResourceStream("carriers.json");
if (stream is null) return [];
var list = JsonSerializer.Deserialize(stream, KnowledgeJsonContext.Default.ListCarrier) ?? [];
return list.Where(c => c.MccMnc is not null && c.Name is not null).GroupBy(c => c.MccMnc).ToDictionary(g => g.Key, g => g.First().Name);
}
static List<ObservedNetwork> LoadObserved()
{
using var stream = typeof(KnowledgeBase).Assembly.GetManifestResourceStream("observed.json");
return stream is null ? [] : JsonSerializer.Deserialize(stream, KnowledgeJsonContext.Default.ListObservedNetwork) ?? [];
}
static AsnTable LoadAsn()
{
using var stream = typeof(KnowledgeBase).Assembly.GetManifestResourceStream("ip2asn.bin");
return stream is null ? null : AsnTable.Read(stream);
}
static List<ProviderProfile> LoadProviders()
{
var assembly = typeof(KnowledgeBase).Assembly;
var list = new List<ProviderProfile>();
foreach (var name in assembly.GetManifestResourceNames().Where(n => n.StartsWith("isp.", StringComparison.Ordinal)).Order(StringComparer.Ordinal))
{
using var stream = assembly.GetManifestResourceStream(name);
var profile = JsonSerializer.Deserialize(stream, KnowledgeJsonContext.Default.ProviderProfile);
if (profile is not null) list.Add(profile);
}
return list;
}
}