Bug fixes

This commit is contained in:
2023-07-26 12:34:32 +01:00
parent 616dd066f7
commit 1a07772b8a
5 changed files with 99 additions and 57 deletions

View File

@ -1,9 +1,12 @@
using System.Security.Cryptography;
using System.Text;
using BTCPayServer.Lightning; using BTCPayServer.Lightning;
using LNURL; using LNURL;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json; using Newtonsoft.Json;
using Nostr.Client.Json; using Nostr.Client.Json;
using Nostr.Client.Messages; using Nostr.Client.Messages;
using Nostr.Client.Utils;
using NostrStreamer.Database; using NostrStreamer.Database;
using NostrStreamer.Services; using NostrStreamer.Services;
@ -41,10 +44,14 @@ public class LnurlController : Controller
} }
[HttpGet("{key}")] [HttpGet("{key}")]
public async Task<IActionResult> PayUserBalance([FromRoute] string key, [FromQuery] long amount, [FromQuery] string? nostr) public async Task<IActionResult> PayUserBalance([FromRoute] string key, [FromQuery] ulong amount, [FromQuery] string? nostr)
{ {
try try
{ {
var user = await _userService.GetUser(key);
if (user == default) return LnurlError("User not found");
string? descHash;
if (!string.IsNullOrEmpty(nostr)) if (!string.IsNullOrEmpty(nostr))
{ {
var ev = JsonConvert.DeserializeObject<NostrEvent>(nostr, NostrSerializer.Settings); var ev = JsonConvert.DeserializeObject<NostrEvent>(nostr, NostrSerializer.Settings);
@ -53,9 +60,16 @@ public class LnurlController : Controller
{ {
throw new Exception("Invalid nostr event"); 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 return Json(new LNURLPayRequest.LNURLPayRequestCallbackResponse
{ {
Pr = invoice Pr = invoice

View File

@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json; using Newtonsoft.Json;
using Nostr.Client.Json; using Nostr.Client.Json;
using Nostr.Client.Utils; using Nostr.Client.Messages;
using NostrStreamer.ApiModel; using NostrStreamer.ApiModel;
using NostrStreamer.Database; using NostrStreamer.Database;
using NostrStreamer.Services; using NostrStreamer.Services;
@ -19,14 +19,14 @@ public class NostrController : Controller
private readonly StreamerContext _db; private readonly StreamerContext _db;
private readonly Config _config; private readonly Config _config;
private readonly StreamManagerFactory _streamManagerFactory; 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; _db = db;
_config = config; _config = config;
_streamManagerFactory = streamManager; _streamManagerFactory = streamManager;
_lnd = lnd; _userService = userService;
} }
[HttpGet("account")] [HttpGet("account")]
@ -36,23 +36,24 @@ public class NostrController : Controller
if (user == default) if (user == default)
{ {
var pk = GetPubKey(); var pk = GetPubKey();
user = new() user = await _userService.CreateAccount(pk);
{
PubKey = pk,
Balance = 1000_000,
StreamKey = Guid.NewGuid().ToString()
};
_db.Users.Add(user);
await _db.SaveChangesAsync();
} }
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 var account = new Account
{ {
Event = null, Event = !string.IsNullOrEmpty(latestEvent) ? JsonConvert.DeserializeObject<NostrEvent>(latestEvent) : null,
Endpoints = endpoints.Select(a => new AccountEndpoint() Endpoints = endpoints.Select(a => new AccountEndpoint
{ {
Name = a.Name, Name = a.Name,
Url = new Uri(_config.RtmpHost, a.App).ToString(), Url = new Uri(_config.RtmpHost, a.App).ToString(),
@ -87,27 +88,17 @@ public class NostrController : Controller
var pubkey = GetPubKey(); var pubkey = GetPubKey();
if (string.IsNullOrEmpty(pubkey)) return Unauthorized(); if (string.IsNullOrEmpty(pubkey)) return Unauthorized();
var invoice = await _lnd.AddInvoice(amount * 1000, TimeSpan.FromMinutes(10), $"Top up for {pubkey}"); var invoice = await _userService.CreateTopup(pubkey, amount * 1000, null, null);
_db.Payments.Add(new()
{
PubKey = pubkey,
Amount = amount,
Invoice = invoice.PaymentRequest,
PaymentHash = invoice.RHash.ToByteArray().ToHex()
});
await _db.SaveChangesAsync();
return Json(new return Json(new
{ {
pr = invoice.PaymentRequest pr = invoice
}); });
} }
private async Task<User?> GetUser() private async Task<User?> GetUser()
{ {
var pk = GetPubKey(); var pk = GetPubKey();
return await _db.Users.FirstOrDefaultAsync(a => a.PubKey == pk); return await _userService.GetUser(pk);
} }
private string GetPubKey() private string GetPubKey()

View File

@ -34,7 +34,7 @@ public class SrsController : Controller
var streamManager = await _streamManagerFactory.ForStream(new StreamInfo var streamManager = await _streamManagerFactory.ForStream(new StreamInfo
{ {
App = appSplit[0], App = appSplit[0],
Variant = appSplit.Length > 1 ? appSplit[1] : "source", Variant = appSplit.Length > 1 ? appSplit[1] : "",
ClientId = req.ClientId!, ClientId = req.ClientId!,
StreamKey = req.Stream StreamKey = req.Stream
}); });
@ -42,15 +42,23 @@ public class SrsController : Controller
if (req.Action == "on_forward") if (req.Action == "on_forward")
{ {
var urls = await streamManager.OnForward(); 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.App.EndsWith("/source"))
{ {
if (req.Action == "on_publish") if (req.Action == "on_publish")
@ -78,7 +86,7 @@ public class SrsController : Controller
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogWarning(ex, "Failed to start stream"); _logger.LogWarning("Failed to start stream: {message}", ex.Message);
} }
return new() return new()

View File

@ -84,23 +84,27 @@ public class StreamManagerFactory
if (ep == default) throw new Exception("No endpoint found"); 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, stream = new()
PubKey = user.PubKey, {
ClientId = info.ClientId, EndpointId = ep.Id,
State = UserStreamState.Planned 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 // replace again with new values
stream = new() stream = new()
{ {
Id = stream.Id, Id = stream?.Id ?? Guid.NewGuid(),
User = user, User = user,
Endpoint = ep, Endpoint = ep,
ClientId = info.ClientId, ClientId = info.ClientId,

View File

@ -1,5 +1,3 @@
using System.Security.Cryptography;
using System.Text;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Nostr.Client.Utils; using Nostr.Client.Utils;
using NostrStreamer.Database; using NostrStreamer.Database;
@ -17,17 +15,44 @@ public class UserService
_lnd = lnd; _lnd = lnd;
} }
public async Task<string> CreateTopup(string pubkey, ulong amount, string? nostr) /// <summary>
/// Create new user account
/// </summary>
/// <param name="pubkey"></param>
/// <returns></returns>
public async Task<User> 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;
}
/// <summary>
/// Create topup for a user
/// </summary>
/// <param name="pubkey"></param>
/// <param name="amount">milli-sats amount</param>
/// <param name="descHash"></param>
/// <param name="nostr"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task<string> CreateTopup(string pubkey, ulong amount, string? descHash, string? nostr)
{ {
var user = await GetUser(pubkey); var user = await GetUser(pubkey);
if (user == default) throw new Exception("No user found"); 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, TimeSpan.FromMinutes(10), $"Top up for {pubkey}", descHash);
var invoice = await _lnd.AddInvoice(amount * 1000, TimeSpan.FromMinutes(10), $"Top up for {pubkey}", descHash);
_db.Payments.Add(new() _db.Payments.Add(new()
{ {
PubKey = pubkey, PubKey = pubkey,
Amount = amount, Amount = amount / 1000,
Invoice = invoice.PaymentRequest, Invoice = invoice.PaymentRequest,
PaymentHash = invoice.RHash.ToByteArray().ToHex(), PaymentHash = invoice.RHash.ToByteArray().ToHex(),
Nostr = nostr, Nostr = nostr,