Skip to content

Tracker

Event tracker for managing which events have been seen from which relays, used for deduplication across multiple relay connections.

Classes

Tracker

Tracks the relationship between event IDs and relay URLs to prevent duplicate processing.

Properties:

  • relaysById - Map of event IDs to sets of relay URLs
  • idsByRelay - Map of relay URLs to sets of event IDs

Methods:

  • getIds(relay) - Gets all event IDs seen from a relay
  • getRelays(eventId) - Gets all relays that have sent an event
  • hasRelay(eventId, relay) - Checks if an event was seen from a relay
  • addRelay(eventId, relay) - Records that an event was seen from a relay
  • removeRelay(eventId, relay) - Removes the event-relay association
  • track(eventId, relay) - Tracks an event and returns true if already seen
  • copy(eventId1, eventId2) - Copies relay associations from one event to another
  • load(relaysById) - Loads tracker state from a map
  • clear() - Clears all tracked data

Events:

  • add - Emitted when event-relay association is added
  • remove - Emitted when event-relay association is removed
  • load - Emitted when tracker state is loaded
  • clear - Emitted when tracker is cleared

Example

typescript
import {Tracker} from "@welshman/net"

const tracker = new Tracker()

// Track events from different relays
const isDuplicate1 = tracker.track("event123", "wss://relay1.com") // false
const isDuplicate2 = tracker.track("event123", "wss://relay2.com") // false
const isDuplicate3 = tracker.track("event123", "wss://relay1.com") // true (duplicate)

// Check which relays have sent an event
const relays = tracker.getRelays("event123") // Set(["wss://relay1.com", "wss://relay2.com"])

If you're not using @welshman/app, you might want to track relays for all events that come through:

typescript
import {Pool, Tracker, SocketEvent, isRelayEvent} from "@welshman/net"
import {isEphemeralKind, isDVMKind, verifyEvent} from "@welshman/util"
import {Repository} from "@welshman/relay"

const tracker = new Tracker()
const repository = new Repository()

Pool.get().subscribe(socket => {
  socket.on(SocketEvent.Receive, message => {
    if (isRelayEvent(message)) {
      const event = message[2]

      if (!isEphemeralKind(event.kind) && !isDVMKind(event.kind) && verifyEvent(event)) {
        tracker.track(event.id, socket.url)
        repository.publish(event)
      }
    }
  })
})