Fix nostr event fetching issues

This commit is contained in:
2026-08-11 18:14:11 -06:00
parent 12a1570c7d
commit 6bfe63c234
3 changed files with 97 additions and 19 deletions
+3 -1
View File
@@ -34,7 +34,9 @@ module NostrManager
received_event.signal received_event.signal
end end
elsif msg && msg[0] == "EOSE" elsif msg && msg[0] == "EOSE"
Thread.current.exit mutex.synchronize do
received_event.signal
end
end end
end end
@@ -9,7 +9,6 @@ module NostrManager
end end
def call def call
received_events = 0
events = [] events = []
begin begin
@@ -17,28 +16,17 @@ module NostrManager
@relays.each do |url| @relays.each do |url|
event = NostrManager::FetchEvent.call(filter: @filter, relay_url: url) event = NostrManager::FetchEvent.call(filter: @filter, relay_url: url)
if event.present? if event.present? && events.none? { |e| e["id"] == event["id"] }
events << event if events.none? { |e| e["id"] == event["id"] } events << event
received_events += 1 break if events.size >= @max_events
end
if received_events >= @max_events
Rails.logger.debug "Found #{@max_events} events, ending the search"
break
end end
end end
events.min_by { |e| e["created_at"] }
end end
rescue Timeout::Error rescue Timeout::Error
if events.size == 1 Rails.logger.debug "[nostr] Timeout after #{TIMEOUT}s, found #{events.size} events"
Rails.logger.debug "[nostr] Timeout: only found 1 event within #{TIMEOUT} seconds for filter: #{@filter.inspect}"
events.first
else
Rails.logger.debug "[nostr] Timeout: no events found within #{TIMEOUT} seconds for filter: #{@filter.inspect}"
nil
end
end end
events.max_by { |e| e["created_at"] }
end end
end end
end end
@@ -0,0 +1,88 @@
require 'rails_helper'
RSpec.describe NostrManager::FetchLatestEvent, type: :model do
let(:filter) { Nostr::Filter.new(authors: ["pubkey"], kinds: [0], limit: 1) }
let(:event_v1) { { "id" => "aaa", "created_at" => 1000, "content" => "v1" } }
let(:event_v2) { { "id" => "bbb", "created_at" => 2000, "content" => "v2" } }
describe "with no events found" do
it "returns nil" do
allow(NostrManager::FetchEvent).to receive(:call).and_return(nil)
result = described_class.call(relays: ["wss://a", "wss://b"], filter: filter)
expect(result).to be_nil
end
end
describe "with event on 1 relay only" do
it "returns the event" do
allow(NostrManager::FetchEvent).to receive(:call) do |args|
case args[:relay_url]
when "wss://a" then event_v1
else nil
end
end
result = described_class.call(
relays: ["wss://a", "wss://b", "wss://c"], filter: filter
)
expect(result).to eq(event_v1)
end
end
describe "with events on 2 relays, different versions" do
it "returns the latest event (max created_at)" do
allow(NostrManager::FetchEvent).to receive(:call) do |args|
case args[:relay_url]
when "wss://a" then event_v1
when "wss://b" then event_v2
end
end
result = described_class.call(relays: ["wss://a", "wss://b"], filter: filter)
expect(result).to eq(event_v2)
end
end
describe "with duplicate events (same ID) on 2 relays" do
it "returns the single event without double-counting" do
allow(NostrManager::FetchEvent).to receive(:call).and_return(event_v1)
result = described_class.call(relays: ["wss://a", "wss://b"], filter: filter)
expect(result).to eq(event_v1)
end
end
describe "with timeout after finding 1 event" do
it "still returns the found event" do
allow(NostrManager::FetchEvent).to receive(:call) do |args|
case args[:relay_url]
when "wss://a" then event_v1
when "wss://b" then raise Timeout::Error
end
end
result = described_class.call(relays: ["wss://a", "wss://b"], filter: filter)
expect(result).to eq(event_v1)
end
end
describe "with max_events reached" do
it "stops querying further relays" do
call_count = 0
allow(NostrManager::FetchEvent).to receive(:call) do |args|
call_count += 1
raise "should not query wss://c" if args[:relay_url] == "wss://c"
case args[:relay_url]
when "wss://a" then event_v1
when "wss://b" then event_v2
end
end
described_class.call(
relays: ["wss://a", "wss://b", "wss://c"], filter: filter
)
expect(call_count).to eq(2)
end
end
end