client.go raw

   1  // Package directory_client provides a client library for the Distributed
   2  // Directory Consensus Protocol (NIP-XX).
   3  //
   4  // This package offers a high-level API for working with directory events,
   5  // managing identity resolution, tracking key delegations, and computing
   6  // trust scores. It builds on the lower-level directory protocol package.
   7  //
   8  // # Basic Usage
   9  //
  10  //	// Create an identity resolver
  11  //	resolver := directory_client.NewIdentityResolver()
  12  //
  13  //	// Parse and track events
  14  //	event := getDirectoryEvent()
  15  //	resolver.ProcessEvent(event)
  16  //
  17  //	// Resolve identity behind a delegate key
  18  //	actualIdentity := resolver.ResolveIdentity(delegateKey)
  19  //
  20  //	// Check if a key is a delegate
  21  //	isDelegate := resolver.IsDelegateKey(pubkey)
  22  //
  23  // # Trust Management
  24  //
  25  //	// Create a trust calculator
  26  //	calculator := directory_client.NewTrustCalculator()
  27  //
  28  //	// Add trust acts
  29  //	trustAct := directory.ParseTrustAct(event)
  30  //	calculator.AddAct(trustAct)
  31  //
  32  //	// Calculate aggregate trust score
  33  //	score := calculator.CalculateTrust(targetPubkey)
  34  //
  35  // # Replication Filtering
  36  //
  37  //	// Create a replication filter
  38  //	filter := directory_client.NewReplicationFilter(50) // min trust score of 50
  39  //
  40  //	// Add trust acts to influence replication decisions
  41  //	filter.AddTrustAct(trustAct)
  42  //
  43  //	// Check if should replicate from a relay
  44  //	if filter.ShouldReplicate(relayPubkey) {
  45  //		// Proceed with replication
  46  //	}
  47  //
  48  // # Event Filtering
  49  //
  50  //	// Filter directory events from a stream
  51  //	events := getEvents()
  52  //	directoryEvents := directory_client.FilterDirectoryEvents(events)
  53  //
  54  //	// Check if an event is a directory event
  55  //	if directory_client.IsDirectoryEvent(event) {
  56  //		// Handle directory event
  57  //	}
  58  package directory_client
  59  
  60  import (
  61  	"next.orly.dev/pkg/lol/errorf"
  62  	"next.orly.dev/pkg/nostr/encoders/event"
  63  	"next.orly.dev/pkg/protocol/directory"
  64  )
  65  
  66  // IsDirectoryEvent checks if an event is a directory consensus event.
  67  func IsDirectoryEvent(ev *event.E) bool {
  68  	if ev == nil {
  69  		return false
  70  	}
  71  	k := uint16(ev.Kind)
  72  	return k == 39100 || k == 39101 || k == 39102 ||
  73  		k == 39103 || k == 39104 || k == 39105
  74  }
  75  
  76  // FilterDirectoryEvents filters a slice of events to only directory events.
  77  func FilterDirectoryEvents(events []*event.E) (filtered []*event.E) {
  78  	filtered = make([]*event.E, 0)
  79  	for _, ev := range events {
  80  		if IsDirectoryEvent(ev) {
  81  			filtered = append(filtered, ev)
  82  		}
  83  	}
  84  	return
  85  }
  86  
  87  // NormalizeRelayURL ensures a relay URL has the canonical format with trailing slash.
  88  func NormalizeRelayURL(url string) string {
  89  	if url == "" {
  90  		return ""
  91  	}
  92  	if url[len(url)-1] != '/' {
  93  		return url + "/"
  94  	}
  95  	return url
  96  }
  97  
  98  // ParseDirectoryEvent parses any directory event based on its kind.
  99  func ParseDirectoryEvent(ev *event.E) (parsed interface{}, err error) {
 100  	if !IsDirectoryEvent(ev) {
 101  		return nil, errorf.E("not a directory event: kind %d", uint16(ev.Kind))
 102  	}
 103  
 104  	switch uint16(ev.Kind) {
 105  	case 39100:
 106  		return directory.ParseRelayIdentityAnnouncement(ev)
 107  	case 39101:
 108  		return directory.ParseTrustAct(ev)
 109  	case 39102:
 110  		return directory.ParseGroupTagAct(ev)
 111  	case 39103:
 112  		return directory.ParsePublicKeyAdvertisement(ev)
 113  	case 39104:
 114  		return directory.ParseDirectoryEventReplicationRequest(ev)
 115  	case 39105:
 116  		return directory.ParseDirectoryEventReplicationResponse(ev)
 117  	default:
 118  		return nil, errorf.E("unknown directory event kind: %d", uint16(ev.Kind))
 119  	}
 120  }
 121