FASTER relay
This commit is contained in:
118
FASTERlay/FASTERRelay.cs
Normal file
118
FASTERlay/FASTERRelay.cs
Normal file
@ -0,0 +1,118 @@
|
||||
using FASTER.core;
|
||||
using Nostr.Client.Messages;
|
||||
using Nostr.Client.Requests;
|
||||
using NostrRelay;
|
||||
|
||||
namespace FASTERlay;
|
||||
|
||||
public class FasterRelay : INostrRelay, IDisposable
|
||||
{
|
||||
private readonly ClientSession<byte[], byte[], byte[], byte[], Empty, SimpleFunctions<byte[], byte[]>> _session;
|
||||
private readonly ClientSession<string, byte[], byte[], byte[], Empty, TagSetFunctions> _tagsSession;
|
||||
|
||||
public FasterRelay(NostrStore store)
|
||||
{
|
||||
_session = store.MainStore.For(new SimpleFunctions<byte[], byte[]>()).NewSession<SimpleFunctions<byte[], byte[]>>();
|
||||
_tagsSession = store.TagStore.For(new TagSetFunctions()).NewSession<TagSetFunctions>();
|
||||
}
|
||||
|
||||
public ValueTask<bool> AcceptConnection(NostrClientContext context)
|
||||
{
|
||||
return ValueTask.FromResult(true);
|
||||
}
|
||||
|
||||
public async IAsyncEnumerable<NostrEvent> HandleRequest(NostrClientContext context, NostrRequest req)
|
||||
{
|
||||
var iter = _session.Iterate();
|
||||
var filter = req.NostrFilter;
|
||||
while (iter.GetNext(out _, out _, out var bytes))
|
||||
{
|
||||
var ev = NostrBuf.Decode(bytes);
|
||||
if (ev != default)
|
||||
{
|
||||
if (filter.Since.HasValue && ev.CreatedAt <= filter.Since)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (filter.Until.HasValue && ev.CreatedAt > filter.Until)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (filter.Ids != default && !filter.Ids.Contains(ev.Id!))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (filter.Authors != default && !filter.Authors.Contains(ev.Pubkey!))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (filter.Kinds != default && !filter.Kinds.Contains(ev.Kind))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return ev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<HandleEventResponse> HandleEvent(NostrClientContext context, NostrEvent ev)
|
||||
{
|
||||
await SaveEvent(ev);
|
||||
return new(true, null);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_session.Dispose();
|
||||
_tagsSession.Dispose();
|
||||
}
|
||||
|
||||
private async Task SaveEvent(NostrEvent ev)
|
||||
{
|
||||
var idBytes = Convert.FromHexString(ev.Id!);
|
||||
var eventBytes = NostrBuf.Encode(ev);
|
||||
|
||||
await _session.UpsertAsync(ref idBytes, ref eventBytes);
|
||||
|
||||
var indexTags = ev.Tags!.Where(a => a.TagIdentifier.Length == 1);
|
||||
foreach (var tag in indexTags)
|
||||
{
|
||||
var kIndex = $"{tag.TagIdentifier}.{tag.AdditionalData[0]}";
|
||||
await _tagsSession.RMWAsync(ref kIndex, ref idBytes);
|
||||
}
|
||||
|
||||
await _session.CompletePendingAsync();
|
||||
await _tagsSession.CompletePendingAsync();
|
||||
}
|
||||
|
||||
private async Task<NostrEvent?> GetEvent(string id)
|
||||
{
|
||||
var idBytes = Convert.FromHexString(id);
|
||||
var read = await _session.ReadAsync(ref idBytes);
|
||||
if (read.Status.Found)
|
||||
{
|
||||
var data = read.Complete().output;
|
||||
return NostrBuf.Decode(data);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
private class TagSetFunctions : SimpleFunctions<string, byte[]>
|
||||
{
|
||||
public TagSetFunctions() : base((l, r) =>
|
||||
{
|
||||
var output = new byte[l.Length + r.Length];
|
||||
Buffer.BlockCopy(l, 0, output, 0, l.Length);
|
||||
Buffer.BlockCopy(r, 0, output, l.Length, r.Length);
|
||||
return output;
|
||||
})
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user