diff --git a/NostrServices.Client/NostrServices.Client.csproj b/NostrServices.Client/NostrServices.Client.csproj
index 800f194..91c914a 100644
--- a/NostrServices.Client/NostrServices.Client.csproj
+++ b/NostrServices.Client/NostrServices.Client.csproj
@@ -6,7 +6,7 @@
enable
true
https://git.v0l.io/Kieran/NostrServices
- 1.0.1
+ 1.0.2
Kieran
Client wrapper for https://nostr.api.v0l.io
https://git.v0l.io/Kieran/NostrServices
@@ -19,4 +19,8 @@
+
+
+
+
diff --git a/NostrServices.Client/NostrServicesClient.cs b/NostrServices.Client/NostrServicesClient.cs
index 927a2c6..ffe12cc 100644
--- a/NostrServices.Client/NostrServicesClient.cs
+++ b/NostrServices.Client/NostrServicesClient.cs
@@ -1,6 +1,8 @@
+using System.Net.Http.Headers;
using Newtonsoft.Json;
using Nostr.Client.Json;
using Nostr.Client.Messages;
+using NostrServices.Model;
namespace NostrServices.Client;
@@ -15,54 +17,47 @@ public class NostrServicesClient
_client.Timeout = TimeSpan.FromSeconds(60);
}
- public async Task Profile(string id)
+ public async Task Profile(string id)
{
- var rsp = await _client.GetAsync($"/api/v1/export/profile/{id}");
- if (rsp.IsSuccessStatusCode)
- {
- var json = await rsp.Content.ReadAsStringAsync();
- return JsonConvert.DeserializeObject(json);
- }
-
- return default;
+ return await Get(HttpMethod.Get, $"/api/v1/export/profile/{id}");
}
public async Task Event(string id)
{
- var rsp = await _client.GetAsync($"/api/v1/export/{id}");
+ return await Get(HttpMethod.Get, $"/api/v1/export/{id}");
+ }
+
+ public async Task LinkPreview(string url)
+ {
+ return await Get(HttpMethod.Get, $"/api/v1/preview?url={Uri.EscapeDataString(url)}");
+ }
+
+ public async Task?> CloseRelays(double lat, double lon, int count = 5)
+ {
+ return await Get>(HttpMethod.Post, $"/api/v1/relays?count={count}", new {lat, lon});
+ }
+
+ public async Task?> TopRelays(int count = 5)
+ {
+ return await Get>(HttpMethod.Get, $"/api/v1/relays/top?count={count}");
+ }
+
+ private async Task Get(HttpMethod method, string path, object? body = null)
+ {
+ var req = new HttpRequestMessage(method, path);
+ if (body != null)
+ {
+ req.Content = new StringContent(JsonConvert.SerializeObject(body, NostrSerializer.Settings),
+ new MediaTypeHeaderValue("application/json"));
+ }
+
+ var rsp = await _client.SendAsync(req);
if (rsp.IsSuccessStatusCode)
{
var json = await rsp.Content.ReadAsStringAsync();
- return NostrJson.Deserialize(json);
+ return JsonConvert.DeserializeObject(json, NostrSerializer.Settings);
}
return default;
}
-
- public class NostrProfile
- {
- [JsonProperty("pubkey")]
- public byte[] PubKey { get; init; } = null!;
-
- [JsonProperty("name")]
- public string? Name { get; init; }
-
- [JsonProperty("about")]
- public string? About { get; init; }
-
- [JsonProperty("picture")]
- public string? Picture { get; init; }
-
- [JsonProperty("nip05")]
- public string? Nip05 { get; init; }
-
- [JsonProperty("lud16")]
- public string? LightningAddress { get; init; }
-
- [JsonProperty("banner")]
- public string? Banner { get; init; }
-
- [JsonProperty("created")]
- public DateTime Created { get; init; }
- }
}
diff --git a/NostrServices.Model/LinkPreviewData.cs b/NostrServices.Model/LinkPreviewData.cs
new file mode 100644
index 0000000..92fdf01
--- /dev/null
+++ b/NostrServices.Model/LinkPreviewData.cs
@@ -0,0 +1,29 @@
+using Newtonsoft.Json;
+using ProtoBuf;
+
+namespace NostrServices.Model;
+
+[ProtoContract]
+public class LinkPreviewData
+{
+ [ProtoMember(1)]
+ [JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public List> OgTags { get; init; } = new();
+
+ [ProtoIgnore]
+ [JsonProperty("og_tags")]
+ public List OgTagsJson => OgTags.Select(a => new[] {a.Key, a.Value}).ToList();
+
+ [ProtoMember(2)]
+ [JsonProperty("title")]
+ public string? Title { get; init; }
+
+ [ProtoMember(3)]
+ [JsonProperty("description")]
+ public string? Description { get; init; }
+
+ [ProtoMember(4)]
+ [JsonProperty("image")]
+ public string? Image { get; init; }
+}
diff --git a/NostrServices.Model/NostrServices.Model.csproj b/NostrServices.Model/NostrServices.Model.csproj
new file mode 100644
index 0000000..076b41a
--- /dev/null
+++ b/NostrServices.Model/NostrServices.Model.csproj
@@ -0,0 +1,15 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
diff --git a/NostrServices.Model/Profile.cs b/NostrServices.Model/Profile.cs
new file mode 100644
index 0000000..5cfbd1b
--- /dev/null
+++ b/NostrServices.Model/Profile.cs
@@ -0,0 +1,66 @@
+using NBitcoin.JsonConverters;
+using Newtonsoft.Json;
+using Nostr.Client.Json;
+using Nostr.Client.Messages;
+using Nostr.Client.Messages.Metadata;
+using ProtoBuf;
+
+namespace NostrServices.Model;
+
+[ProtoContract]
+public class CompactProfile
+{
+ [ProtoMember(1)]
+ [JsonProperty("pubkey")]
+ [JsonConverter(typeof(HexJsonConverter))]
+ public byte[] PubKey { get; init; } = null!;
+
+ [ProtoMember(2)]
+ [JsonProperty("name")]
+ public string? Name { get; init; }
+
+ [ProtoMember(3)]
+ [JsonProperty("about")]
+ public string? About { get; init; }
+
+ [ProtoMember(4)]
+ [JsonProperty("picture")]
+ public string? Picture { get; init; }
+
+ [ProtoMember(5)]
+ [JsonProperty("nip05")]
+ public string? Nip05 { get; init; }
+
+ [ProtoMember(6)]
+ [JsonProperty("lud16")]
+ public string? Lud16 { get; init; }
+
+ [ProtoMember(7)]
+ [JsonProperty("banner")]
+ public string? Banner { get; init; }
+
+ [ProtoMember(8)]
+ [JsonProperty("created")]
+ public DateTime Created { get; init; }
+
+ public static CompactProfile? FromNostrEvent(NostrEvent ev)
+ {
+ var meta = NostrJson.Deserialize(ev.Content);
+ if (meta != default)
+ {
+ return new()
+ {
+ PubKey = Convert.FromHexString(ev.Pubkey!),
+ Name = meta.Name,
+ About = meta.About,
+ Picture = meta.Picture,
+ Nip05 = meta.Nip05,
+ Lud16 = meta.Lud16,
+ Banner = meta.Banner,
+ Created = ev.CreatedAt!.Value
+ };
+ }
+
+ return default;
+ }
+}
diff --git a/NostrServices.Model/RelayDistance.cs b/NostrServices.Model/RelayDistance.cs
new file mode 100644
index 0000000..28548df
--- /dev/null
+++ b/NostrServices.Model/RelayDistance.cs
@@ -0,0 +1,36 @@
+using Newtonsoft.Json;
+
+namespace NostrServices.Model;
+
+public class RelayDistance
+{
+ [JsonProperty("url")]
+ public Uri Url { get; init; } = null!;
+
+ [JsonProperty("distance")]
+ public double Distance { get; init; }
+
+ [JsonProperty("users")]
+ public long? Users { get; init; }
+
+ [JsonProperty("country")]
+ public string? Country { get; init; }
+
+ [JsonProperty("city")]
+ public string? City { get; init; }
+
+ [JsonProperty("description")]
+ public string? Description { get; init; }
+
+ [JsonProperty("is_paid")]
+ public bool? IsPaid { get; init; }
+
+ [JsonProperty("is_write_restricted")]
+ public bool? IsWriteRestricted { get; init; }
+
+ [JsonProperty("lat")]
+ public double? Latitude { get; init; }
+
+ [JsonProperty("lon")]
+ public double? Longitude { get; init; }
+}
diff --git a/NostrServices.sln b/NostrServices.sln
index 4ffb49f..b134b21 100644
--- a/NostrServices.sln
+++ b/NostrServices.sln
@@ -19,6 +19,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PayForReactions", "PayForRe
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NostrServices.Client", "NostrServices.Client\NostrServices.Client.csproj", "{17CA7036-95BC-4851-BAB1-419996EA2761}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NostrServices.Model", "NostrServices.Model\NostrServices.Model.csproj", "{70E7A5B7-005F-4EEE-9C0D-7FFB1389ED2A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -49,5 +51,9 @@ Global
{17CA7036-95BC-4851-BAB1-419996EA2761}.Debug|Any CPU.Build.0 = Debug|Any CPU
{17CA7036-95BC-4851-BAB1-419996EA2761}.Release|Any CPU.ActiveCfg = Release|Any CPU
{17CA7036-95BC-4851-BAB1-419996EA2761}.Release|Any CPU.Build.0 = Release|Any CPU
+ {70E7A5B7-005F-4EEE-9C0D-7FFB1389ED2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {70E7A5B7-005F-4EEE-9C0D-7FFB1389ED2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {70E7A5B7-005F-4EEE-9C0D-7FFB1389ED2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {70E7A5B7-005F-4EEE-9C0D-7FFB1389ED2A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/NostrServices/Controllers/ImportController.cs b/NostrServices/Controllers/ImportController.cs
index 83a482e..b16bdf2 100644
--- a/NostrServices/Controllers/ImportController.cs
+++ b/NostrServices/Controllers/ImportController.cs
@@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Nostr.Client.Json;
using Nostr.Client.Messages;
+using NostrServices.Model;
using NostrServices.Services;
namespace NostrServices.Controllers;
diff --git a/NostrServices/Controllers/LinkPreviewController.cs b/NostrServices/Controllers/LinkPreviewController.cs
index b204d29..85fcbcc 100644
--- a/NostrServices/Controllers/LinkPreviewController.cs
+++ b/NostrServices/Controllers/LinkPreviewController.cs
@@ -3,8 +3,7 @@ using System.Text;
using AngleSharp;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
-using Newtonsoft.Json;
-using ProtoBuf;
+using NostrServices.Model;
using StackExchange.Redis;
namespace NostrServices.Controllers;
@@ -102,28 +101,3 @@ public class LinkPreviewController : Controller
return default;
}
}
-
-[ProtoContract]
-public class LinkPreviewData
-{
- [ProtoMember(1)]
- [JsonIgnore]
- [System.Text.Json.Serialization.JsonIgnore]
- public List> OgTags { get; init; } = new();
-
- [ProtoIgnore]
- [JsonProperty("og_tags")]
- public List OgTagsJson => OgTags.Select(a => new[] {a.Key, a.Value}).ToList();
-
- [ProtoMember(2)]
- [JsonProperty("title")]
- public string? Title { get; init; }
-
- [ProtoMember(3)]
- [JsonProperty("description")]
- public string? Description { get; init; }
-
- [ProtoMember(4)]
- [JsonProperty("image")]
- public string? Image { get; init; }
-}
diff --git a/NostrServices/Controllers/OpenGraphController.cs b/NostrServices/Controllers/OpenGraphController.cs
index 96febaa..7245b11 100644
--- a/NostrServices/Controllers/OpenGraphController.cs
+++ b/NostrServices/Controllers/OpenGraphController.cs
@@ -1,10 +1,10 @@
using AngleSharp;
using AngleSharp.Dom;
using Microsoft.AspNetCore.Mvc;
-using Newtonsoft.Json;
using Nostr.Client.Identifiers;
using Nostr.Client.Messages;
using Nostr.Client.Utils;
+using NostrServices.Model;
using NostrServices.Services;
using ProtoBuf;
@@ -18,14 +18,11 @@ public class OpenGraphController : Controller
{
private readonly ILogger _logger;
private readonly RedisStore _redisStore;
- private readonly HttpClient _httpClient;
- public OpenGraphController(ILogger logger, RedisStore redisStore, HttpClient httpClient)
+ public OpenGraphController(ILogger logger, RedisStore redisStore)
{
_logger = logger;
_redisStore = redisStore;
- _httpClient = httpClient;
- _httpClient.Timeout = TimeSpan.FromSeconds(2);
}
///
@@ -118,7 +115,7 @@ public class OpenGraphController : Controller
{
case (long)NostrKind.LiveEvent:
{
- var host = ev.Tags.FirstOrDefault(a => a is {Key: "p", Values: [_, "host", ..]})?.Values[0] ?? ev.PubKey.ToHex();
+ var host = ev.Tags.FirstOrDefault(a => a.Key == "p" && a.Values[1] == "host")?.Values[0] ?? ev.PubKey.ToHex();
var hostProfile = await _redisStore.GetProfile(host);
var hostName = hostProfile?.Name ?? profile?.Name ?? "Nostrich";
var stream = ev.GetFirstTagValue("streaming") ?? ev.GetFirstTagValue("recording") ?? "";
diff --git a/NostrServices/Controllers/RelaysController.cs b/NostrServices/Controllers/RelaysController.cs
index bd4fa4f..ebc83a3 100644
--- a/NostrServices/Controllers/RelaysController.cs
+++ b/NostrServices/Controllers/RelaysController.cs
@@ -20,7 +20,7 @@ public class RelaysController : Controller
const int distance = 5000 * 1000; // 5,000km
var relays = await _database.FindCloseRelays(pos.Lat, pos.Lon, distance, count);
- return Json(relays.Select(RelayDistance.FromDistance));
+ return Json(relays.Select(a => a.FromDistance()));
}
[HttpGet("top")]
@@ -30,7 +30,7 @@ public class RelaysController : Controller
var topSelected = top.OrderByDescending(a => a.Value).Take(count);
var infos = await Task.WhenAll(topSelected.Select(a => _database.GetRelay(a.Key)));
- return Json(infos.Where(a => a != default).Select(a => RelayDistance.FromInfo(a!)));
+ return Json(infos.Where(a => a != default).Select(a => a!.FromInfo()));
}
}
@@ -43,42 +43,12 @@ public class LatLonReq
public double Lon { get; init; }
}
-class RelayDistance
+public static class RelayDistanceExtension
{
- [JsonProperty("url")]
- public Uri Url { get; init; } = null!;
-
- [JsonProperty("distance")]
- public double Distance { get; init; }
-
- [JsonProperty("users")]
- public long? Users { get; init; }
-
- [JsonProperty("country")]
- public string? Country { get; init; }
-
- [JsonProperty("city")]
- public string? City { get; init; }
-
- [JsonProperty("description")]
- public string? Description { get; init; }
-
- [JsonProperty("is_paid")]
- public bool? IsPaid { get; init; }
-
- [JsonProperty("is_write_restricted")]
- public bool? IsWriteRestricted { get; init; }
-
- [JsonProperty("lat")]
- public double? Latitude { get; init; }
-
- [JsonProperty("lon")]
- public double? Longitude { get; init; }
-
- public static RelayDistance FromDistance(Services.RelayDistance x)
+ public static Model.RelayDistance FromDistance(this RelayDistance x)
{
var rp = x.Relay.Positions.FirstOrDefault(a => a.IpAddress == x.IpAddress) ?? x.Relay.Positions.First();
- return new RelayDistance()
+ return new Model.RelayDistance()
{
Url = x.Relay.Url,
Distance = x.Distance,
@@ -93,10 +63,10 @@ class RelayDistance
};
}
- public static RelayDistance FromInfo(RelayInfo x)
+ public static Model.RelayDistance FromInfo(this RelayInfo x)
{
var rp = x.Positions.First();
- return new RelayDistance()
+ return new Model.RelayDistance()
{
Url = x.Url,
Distance = 0,
diff --git a/NostrServices/Extensions.cs b/NostrServices/Extensions.cs
index f0b4a83..328fc91 100644
--- a/NostrServices/Extensions.cs
+++ b/NostrServices/Extensions.cs
@@ -5,6 +5,7 @@ using Nostr.Client.Json;
using Nostr.Client.Messages;
using Nostr.Client.Utils;
using NostrRelay;
+using NostrServices.Model;
using NostrServices.Services;
using ProtoBuf;
using StackExchange.Redis;
diff --git a/NostrServices/NostrServices.csproj b/NostrServices/NostrServices.csproj
index fa7c680..58f89b7 100644
--- a/NostrServices/NostrServices.csproj
+++ b/NostrServices/NostrServices.csproj
@@ -31,6 +31,7 @@
+
diff --git a/NostrServices/Services/EventHandlers/RedisEventCache.cs b/NostrServices/Services/EventHandlers/RedisEventCache.cs
index d7df081..1df314d 100644
--- a/NostrServices/Services/EventHandlers/RedisEventCache.cs
+++ b/NostrServices/Services/EventHandlers/RedisEventCache.cs
@@ -1,6 +1,7 @@
using NBitcoin;
using Newtonsoft.Json;
using Nostr.Client.Messages;
+using NostrServices.Model;
namespace NostrServices.Services.EventHandlers;
diff --git a/NostrServices/Services/RedisStore.cs b/NostrServices/Services/RedisStore.cs
index bda9da4..f00de22 100644
--- a/NostrServices/Services/RedisStore.cs
+++ b/NostrServices/Services/RedisStore.cs
@@ -1,11 +1,8 @@
using NBitcoin;
-using NBitcoin.JsonConverters;
-using Newtonsoft.Json;
using Nostr.Client.Identifiers;
-using Nostr.Client.Json;
using Nostr.Client.Messages;
-using Nostr.Client.Messages.Metadata;
using Nostr.Client.Utils;
+using NostrServices.Model;
using ProtoBuf;
using StackExchange.Redis;
@@ -231,64 +228,6 @@ public class CompactEvent
}
}
-[ProtoContract]
-public class CompactProfile
-{
- [ProtoMember(1)]
- [JsonProperty("pubkey")]
- [JsonConverter(typeof(HexJsonConverter))]
- public byte[] PubKey { get; init; } = null!;
-
- [ProtoMember(2)]
- [JsonProperty("name")]
- public string? Name { get; init; }
-
- [ProtoMember(3)]
- [JsonProperty("about")]
- public string? About { get; init; }
-
- [ProtoMember(4)]
- [JsonProperty("picture")]
- public string? Picture { get; init; }
-
- [ProtoMember(5)]
- [JsonProperty("nip05")]
- public string? Nip05 { get; init; }
-
- [ProtoMember(6)]
- [JsonProperty("lud16")]
- public string? Lud16 { get; init; }
-
- [ProtoMember(7)]
- [JsonProperty("banner")]
- public string? Banner { get; init; }
-
- [ProtoMember(8)]
- [JsonProperty("created")]
- public DateTime Created { get; init; }
-
- public static CompactProfile? FromNostrEvent(NostrEvent ev)
- {
- var meta = NostrJson.Deserialize(ev.Content);
- if (meta != default)
- {
- return new()
- {
- PubKey = Convert.FromHexString(ev.Pubkey!),
- Name = meta.Name,
- About = meta.About,
- Picture = meta.Picture,
- Nip05 = meta.Nip05,
- Lud16 = meta.Lud16,
- Banner = meta.Banner,
- Created = ev.CreatedAt!.Value
- };
- }
-
- return default;
- }
-}
-
[ProtoContract]
public class RelayDistance
{
diff --git a/PayForReactions/ReactionQueue.cs b/PayForReactions/ReactionQueue.cs
index 3c9ee6d..90c8284 100644
--- a/PayForReactions/ReactionQueue.cs
+++ b/PayForReactions/ReactionQueue.cs
@@ -105,7 +105,7 @@ public class ReactionQueueWorker : BackgroundService
continue;
}
- var parsedTarget = Lnurl.ParseLnUrl(senderProfile.LightningAddress ?? "");
+ var parsedTarget = Lnurl.ParseLnUrl(senderProfile.Lud16 ?? "");
if (parsedTarget == default)
{
_logger.LogInformation(
@@ -115,7 +115,7 @@ public class ReactionQueueWorker : BackgroundService
continue;
}
- _logger.LogInformation("Starting payment for {name} - {addr}", senderProfile.Name, senderProfile.LightningAddress);
+ _logger.LogInformation("Starting payment for {name} - {addr}", senderProfile.Name, senderProfile.Lud16);
var svc = await _lnurl.LoadAsync(parsedTarget.ToString());
if (svc == default)
{