Host on edges

This commit is contained in:
2023-08-03 18:34:53 +01:00
parent 52ce412491
commit 5a2bd21cec
7 changed files with 125 additions and 4 deletions

View File

@ -40,6 +40,10 @@ public class Config
public S3BlobConfig S3Store { get; init; } = null!;
public DateTime TosDate { get; init; }
public string GeoIpDatabase { get; init; } = null!;
public List<EdgeLocation> Edges { get; init; } = new();
}
public class LndConfig
@ -62,3 +66,11 @@ public sealed class S3BlobConfig
public bool DisablePayloadSigning { get; init; }
public Uri PublicHost { get; init; } = null!;
}
public sealed class EdgeLocation
{
public string Name { get; init; } = null!;
public Uri Url { get; init; } = null!;
public double Latitude { get; init; }
public double Longitude { get; init; }
}

View File

@ -16,9 +16,10 @@ public class PlaylistController : Controller
private readonly SrsApi _srsApi;
private readonly ViewCounter _viewCounter;
private readonly StreamManagerFactory _streamManagerFactory;
private readonly EdgeSteering _edgeSteering;
public PlaylistController(Config config, ILogger<PlaylistController> logger,
HttpClient client, SrsApi srsApi, ViewCounter viewCounter, StreamManagerFactory streamManagerFactory)
HttpClient client, SrsApi srsApi, ViewCounter viewCounter, StreamManagerFactory streamManagerFactory, EdgeSteering edgeSteering)
{
_config = config;
_logger = logger;
@ -26,6 +27,7 @@ public class PlaylistController : Controller
_srsApi = srsApi;
_viewCounter = viewCounter;
_streamManagerFactory = streamManagerFactory;
_edgeSteering = edgeSteering;
}
[ResponseCache(Duration = 1, Location = ResponseCacheLocation.Any)]
@ -106,6 +108,7 @@ public class PlaylistController : Controller
{
try
{
var edge = _edgeSteering.GetEdge(HttpContext);
var streamManager = await _streamManagerFactory.ForStream(id);
var userStream = streamManager.GetStream();
@ -138,8 +141,17 @@ public class PlaylistController : Controller
await sw.WriteLineAsync(
$"#EXT-X-STREAM-INF:{string.Join(",", allArgs)}");
var u = $"../{variant.SourceName}/{userStream.Id}.m3u8{(!string.IsNullOrEmpty(hlsCtx) ? $"?hls_ctx={hlsCtx}" : "")}";
await sw.WriteLineAsync(u);
var path = $"{variant.SourceName}/{userStream.Id}.m3u8{(!string.IsNullOrEmpty(hlsCtx) ? $"?hls_ctx={hlsCtx}" : "")}";
if (edge != default)
{
var u = new Uri(edge.Url, path);
await sw.WriteLineAsync(u.ToString());
}
else
{
var u = $"../{path}";
await sw.WriteLineAsync(u);
}
}
}
catch (Exception ex)

View File

@ -1,6 +1,7 @@
using Amazon;
using Amazon.Runtime;
using Amazon.S3;
using MaxMind.GeoIP2;
using Newtonsoft.Json;
using Nostr.Client.Json;
using Nostr.Client.Keys;
@ -50,6 +51,46 @@ public static class Extensions
return !string.IsNullOrEmpty(user.Tags) ?
user.Tags.Split(",", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) : Array.Empty<string>();
}
public static (double lat, double lon)? GetLocation(this HttpContext ctx, IGeoIP2DatabaseReader db)
{
var ip = ctx.GetRealIp();
var loc = db.TryCity(ip, out var city) ? city?.Location : default;
if ((loc?.Latitude.HasValue ?? false) && loc.Longitude.HasValue)
{
return (loc.Latitude.Value, loc.Longitude.Value);
}
return default;
}
public static string GetRealIp(this HttpContext ctx)
{
var cci = ctx.Request.Headers.TryGetValue("CF-Connecting-IP", out var xx) ? xx.ToString() : null;
if (!string.IsNullOrEmpty(cci))
{
return cci;
}
var xff = ctx.Request.Headers.TryGetValue("X-Forwarded-For", out var x) ? x.ToString() : null;
if (!string.IsNullOrEmpty(xff))
{
return xff.Split(",", StringSplitOptions.RemoveEmptyEntries).First();
}
return ctx.Connection.RemoteIpAddress!.ToString();
}
public static double GetDistance(double longitude, double latitude, double otherLongitude, double otherLatitude)
{
var d1 = latitude * (Math.PI / 180.0);
var num1 = longitude * (Math.PI / 180.0);
var d2 = otherLatitude * (Math.PI / 180.0);
var num2 = otherLongitude * (Math.PI / 180.0) - num1;
var d3 = Math.Pow(Math.Sin((d2 - d1) / 2.0), 2.0) + Math.Cos(d1) * Math.Cos(d2) * Math.Pow(Math.Sin(num2 / 2.0), 2.0);
return 6376500.0 * (2.0 * Math.Atan2(Math.Sqrt(d3), Math.Sqrt(1.0 - d3)));
}
}
public class Variant

View File

@ -38,6 +38,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="LNURL" Version="0.0.30" />
<PackageReference Include="MaxMind.GeoIP2" Version="5.1.0" />
<PackageReference Include="MediaFormatLibrary.Lib" Version="1.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.19" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.8" />

View File

@ -1,4 +1,5 @@
using System.Security.Claims;
using MaxMind.GeoIP2;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using Microsoft.EntityFrameworkCore;
@ -29,6 +30,10 @@ internal static class Program
services.AddControllers().AddNewtonsoftJson();
services.AddSingleton(config);
// GeoIP
services.AddSingleton<IGeoIP2DatabaseReader>(_ => new DatabaseReader(config.GeoIpDatabase));
services.AddTransient<EdgeSteering>();
// nostr auth
services.AddTransient<NostrAuthHandler>();
services.AddAuthentication(o =>

View File

@ -0,0 +1,35 @@
using System.Diagnostics;
using MaxMind.GeoIP2;
namespace NostrStreamer.Services;
public class EdgeSteering
{
private readonly Config _config;
private readonly IGeoIP2DatabaseReader _db;
private readonly ILogger<EdgeSteering> _logger;
public EdgeSteering(Config config, IGeoIP2DatabaseReader db, ILogger<EdgeSteering> logger)
{
_config = config;
_db = db;
_logger = logger;
}
public EdgeLocation? GetEdge(HttpContext ctx)
{
var sw = Stopwatch.StartNew();
var loc = ctx.GetLocation(_db);
if (loc != default)
{
var ret = _config.Edges.MinBy(a => Extensions.GetDistance(a.Longitude, a.Latitude, loc.Value.lon, loc.Value.lat));
sw.Stop();
_logger.LogTrace("Found edge in {n:#,##0.#}ms", sw.Elapsed.TotalMilliseconds);
return ret;
}
sw.Stop();
_logger.LogTrace("Found no edge in {n:#,##0.#}ms", sw.Elapsed.TotalMilliseconds);
return default;
}
}

View File

@ -32,6 +32,21 @@
"AccessKey": "TQcxug1ZAXfnZ5bvc9n5",
"SecretKey": "p7EK4qew6DBkBPqrpRPuJgTOc6ChUlfIcEdAwE7K",
"PublicHost": "http://localhost:9010"
}
},
"GeoIpDatabase": "/Users/kieran/Downloads/GeoLite2-City_20230801/GeoLite2-City.mmdb",
"Edges": [
{
"Name": "US0",
"Url": "https://us0.edge.zap.stream/",
"Longitude": -73.8024,
"Latitude": 45.4616
},
{
"Name": "Origin",
"Url": "https://data.zap.stream/",
"Longitude": 2.12664,
"Latitude": 50.98515
}
]
}
}