From 1a07772b8a1876e8e947985a300215f1e119468a Mon Sep 17 00:00:00 2001 From: Kieran Date: Wed, 26 Jul 2023 12:34:32 +0100 Subject: [PATCH] Bug fixes --- NostrStreamer/Controllers/LnurlController.cs | 18 ++++++- NostrStreamer/Controllers/NostrController.cs | 51 ++++++++----------- NostrStreamer/Controllers/SRSController.cs | 22 +++++--- .../StreamManager/StreamManagerFactory.cs | 28 +++++----- .../{UserBalanceService.cs => UserService.cs} | 37 +++++++++++--- 5 files changed, 99 insertions(+), 57 deletions(-) rename NostrStreamer/Services/{UserBalanceService.cs => UserService.cs} (53%) diff --git a/NostrStreamer/Controllers/LnurlController.cs b/NostrStreamer/Controllers/LnurlController.cs index 5d8b65f..de57344 100644 --- a/NostrStreamer/Controllers/LnurlController.cs +++ b/NostrStreamer/Controllers/LnurlController.cs @@ -1,9 +1,12 @@ +using System.Security.Cryptography; +using System.Text; using BTCPayServer.Lightning; using LNURL; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using Nostr.Client.Json; using Nostr.Client.Messages; +using Nostr.Client.Utils; using NostrStreamer.Database; using NostrStreamer.Services; @@ -41,10 +44,14 @@ public class LnurlController : Controller } [HttpGet("{key}")] - public async Task PayUserBalance([FromRoute] string key, [FromQuery] long amount, [FromQuery] string? nostr) + public async Task PayUserBalance([FromRoute] string key, [FromQuery] ulong amount, [FromQuery] string? nostr) { try { + var user = await _userService.GetUser(key); + if (user == default) return LnurlError("User not found"); + + string? descHash; if (!string.IsNullOrEmpty(nostr)) { var ev = JsonConvert.DeserializeObject(nostr, NostrSerializer.Settings); @@ -53,9 +60,16 @@ public class LnurlController : Controller { throw new Exception("Invalid nostr event"); } + + descHash = SHA256.HashData(Encoding.UTF8.GetBytes(nostr)).ToHex(); + } + else + { + var metadata = GetMetadata(user); + descHash = SHA256.HashData(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(metadata))).ToHex(); } - var invoice = await _userService.CreateTopup(key, (ulong)(amount / 1000), nostr); + var invoice = await _userService.CreateTopup(key, amount, descHash, nostr); return Json(new LNURLPayRequest.LNURLPayRequestCallbackResponse { Pr = invoice diff --git a/NostrStreamer/Controllers/NostrController.cs b/NostrStreamer/Controllers/NostrController.cs index a37d46f..c8f9219 100644 --- a/NostrStreamer/Controllers/NostrController.cs +++ b/NostrStreamer/Controllers/NostrController.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; using Nostr.Client.Json; -using Nostr.Client.Utils; +using Nostr.Client.Messages; using NostrStreamer.ApiModel; using NostrStreamer.Database; using NostrStreamer.Services; @@ -19,14 +19,14 @@ public class NostrController : Controller private readonly StreamerContext _db; private readonly Config _config; private readonly StreamManagerFactory _streamManagerFactory; - private readonly LndNode _lnd; + private readonly UserService _userService; - public NostrController(StreamerContext db, Config config, StreamManagerFactory streamManager, LndNode lnd) + public NostrController(StreamerContext db, Config config, StreamManagerFactory streamManager, UserService userService) { _db = db; _config = config; _streamManagerFactory = streamManager; - _lnd = lnd; + _userService = userService; } [HttpGet("account")] @@ -36,23 +36,24 @@ public class NostrController : Controller if (user == default) { var pk = GetPubKey(); - user = new() - { - PubKey = pk, - Balance = 1000_000, - StreamKey = Guid.NewGuid().ToString() - }; - - _db.Users.Add(user); - - await _db.SaveChangesAsync(); + user = await _userService.CreateAccount(pk); } - var endpoints = await _db.Endpoints.ToListAsync(); + var endpoints = await _db.Endpoints + .AsNoTracking() + .ToListAsync(); + + var latestEvent = await _db.Streams + .AsNoTracking() + .Where(a => a.User.PubKey == user.PubKey) + .OrderByDescending(a => a.Starts) + .Select(a => a.Event) + .FirstOrDefaultAsync(); + var account = new Account { - Event = null, - Endpoints = endpoints.Select(a => new AccountEndpoint() + Event = !string.IsNullOrEmpty(latestEvent) ? JsonConvert.DeserializeObject(latestEvent) : null, + Endpoints = endpoints.Select(a => new AccountEndpoint { Name = a.Name, Url = new Uri(_config.RtmpHost, a.App).ToString(), @@ -87,27 +88,17 @@ public class NostrController : Controller var pubkey = GetPubKey(); if (string.IsNullOrEmpty(pubkey)) return Unauthorized(); - var invoice = await _lnd.AddInvoice(amount * 1000, TimeSpan.FromMinutes(10), $"Top up for {pubkey}"); - _db.Payments.Add(new() - { - PubKey = pubkey, - Amount = amount, - Invoice = invoice.PaymentRequest, - PaymentHash = invoice.RHash.ToByteArray().ToHex() - }); - - await _db.SaveChangesAsync(); - + var invoice = await _userService.CreateTopup(pubkey, amount * 1000, null, null); return Json(new { - pr = invoice.PaymentRequest + pr = invoice }); } private async Task GetUser() { var pk = GetPubKey(); - return await _db.Users.FirstOrDefaultAsync(a => a.PubKey == pk); + return await _userService.GetUser(pk); } private string GetPubKey() diff --git a/NostrStreamer/Controllers/SRSController.cs b/NostrStreamer/Controllers/SRSController.cs index 32208eb..28a03e2 100644 --- a/NostrStreamer/Controllers/SRSController.cs +++ b/NostrStreamer/Controllers/SRSController.cs @@ -34,7 +34,7 @@ public class SrsController : Controller var streamManager = await _streamManagerFactory.ForStream(new StreamInfo { App = appSplit[0], - Variant = appSplit.Length > 1 ? appSplit[1] : "source", + Variant = appSplit.Length > 1 ? appSplit[1] : "", ClientId = req.ClientId!, StreamKey = req.Stream }); @@ -42,15 +42,23 @@ public class SrsController : Controller if (req.Action == "on_forward") { var urls = await streamManager.OnForward(); - return new SrsForwardHookReply + if (urls.Count > 0) { - Data = new() + return new SrsForwardHookReply { - Urls = urls - } + Data = new() + { + Urls = urls + } + }; + } + + return new() + { + Code = 2 // invalid request }; } - + if (req.App.EndsWith("/source")) { if (req.Action == "on_publish") @@ -78,7 +86,7 @@ public class SrsController : Controller } catch (Exception ex) { - _logger.LogWarning(ex, "Failed to start stream"); + _logger.LogWarning("Failed to start stream: {message}", ex.Message); } return new() diff --git a/NostrStreamer/Services/StreamManager/StreamManagerFactory.cs b/NostrStreamer/Services/StreamManager/StreamManagerFactory.cs index 6c2c0eb..1ab1f93 100644 --- a/NostrStreamer/Services/StreamManager/StreamManagerFactory.cs +++ b/NostrStreamer/Services/StreamManager/StreamManagerFactory.cs @@ -84,23 +84,27 @@ public class StreamManagerFactory if (ep == default) throw new Exception("No endpoint found"); - stream = new() + // create new stream entry for source only + if (info.Variant == "source") { - EndpointId = ep.Id, - PubKey = user.PubKey, - ClientId = info.ClientId, - State = UserStreamState.Planned - }; + stream = new() + { + EndpointId = ep.Id, + PubKey = user.PubKey, + ClientId = info.ClientId, + State = UserStreamState.Planned + }; + + var ev = _eventBuilder.CreateStreamEvent(user, stream); + stream.Event = JsonConvert.SerializeObject(ev, NostrSerializer.Settings); + _db.Streams.Add(stream); + await _db.SaveChangesAsync(); + } - var ev = _eventBuilder.CreateStreamEvent(user, stream); - stream.Event = JsonConvert.SerializeObject(ev, NostrSerializer.Settings); - _db.Streams.Add(stream); - await _db.SaveChangesAsync(); - // replace again with new values stream = new() { - Id = stream.Id, + Id = stream?.Id ?? Guid.NewGuid(), User = user, Endpoint = ep, ClientId = info.ClientId, diff --git a/NostrStreamer/Services/UserBalanceService.cs b/NostrStreamer/Services/UserService.cs similarity index 53% rename from NostrStreamer/Services/UserBalanceService.cs rename to NostrStreamer/Services/UserService.cs index 78a5aed..b5402b8 100644 --- a/NostrStreamer/Services/UserBalanceService.cs +++ b/NostrStreamer/Services/UserService.cs @@ -1,5 +1,3 @@ -using System.Security.Cryptography; -using System.Text; using Microsoft.EntityFrameworkCore; using Nostr.Client.Utils; using NostrStreamer.Database; @@ -17,17 +15,44 @@ public class UserService _lnd = lnd; } - public async Task CreateTopup(string pubkey, ulong amount, string? nostr) + /// + /// Create new user account + /// + /// + /// + public async Task CreateAccount(string pubkey) + { + var user = new User() + { + PubKey = pubkey, + Balance = 1000_000, + StreamKey = Guid.NewGuid().ToString() + }; + + _db.Users.Add(user); + await _db.SaveChangesAsync(); + return user; + } + + /// + /// Create topup for a user + /// + /// + /// milli-sats amount + /// + /// + /// + /// + public async Task CreateTopup(string pubkey, ulong amount, string? descHash, string? nostr) { var user = await GetUser(pubkey); if (user == default) throw new Exception("No user found"); - var descHash = string.IsNullOrEmpty(nostr) ? null : SHA256.HashData(Encoding.UTF8.GetBytes(nostr)).ToHex(); - var invoice = await _lnd.AddInvoice(amount * 1000, TimeSpan.FromMinutes(10), $"Top up for {pubkey}", descHash); + var invoice = await _lnd.AddInvoice(amount, TimeSpan.FromMinutes(10), $"Top up for {pubkey}", descHash); _db.Payments.Add(new() { PubKey = pubkey, - Amount = amount, + Amount = amount / 1000, Invoice = invoice.PaymentRequest, PaymentHash = invoice.RHash.ToByteArray().ToHex(), Nostr = nostr,