client.go raw

   1  package main
   2  
   3  import (
   4  	"common/jsbridge/sw"
   5  	"common/nostr"
   6  	"common/relay"
   7  )
   8  
   9  // Relay Proxy — WebSocket connection management.
  10  // Receives events from relays, routes them to the Subscription Router.
  11  
  12  var (
  13  	rpool       *relay.Pool
  14  	writeRelays []string
  15  )
  16  
  17  func initRelayProxy() {
  18  	rpool = relay.NewPool()
  19  }
  20  
  21  func getConn(url string) *relay.Conn {
  22  	c := rpool.Connect(url)
  23  	wireConn(c, url)
  24  	return c
  25  }
  26  
  27  func wireConn(c *relay.Conn, url string) {
  28  	c.SetOnEvent(func(_ string, ev *nostr.Event) {
  29  		routerOnRelayEvent(url, ev)
  30  	})
  31  	c.SetOnEOSE(func(subID string) {
  32  		routerOnRelayEOSE(subID)
  33  	})
  34  	c.SetOnOK(func(eventID string, ok bool, msg string) {
  35  		okStr := "true"
  36  		if !ok {
  37  			okStr = "false"
  38  		}
  39  		fwdAll("[\"OK\"," + jstr(eventID) + "," + okStr + "," + jstr(msg) + "]")
  40  	})
  41  	c.SetOnAuth(func(challenge string) {
  42  		onRelayAuth(url, challenge)
  43  	})
  44  	c.ScheduleReconnect = func(fn func()) {
  45  		sw.SetTimeout(5000, fn)
  46  	}
  47  }
  48  
  49  func onRelayAuth(relayURL, challenge string) {
  50  	if myPubkey == "" {
  51  		return
  52  	}
  53  	authEv := &nostr.Event{
  54  		Kind:      22242,
  55  		PubKey:    myPubkey,
  56  		Content:   "",
  57  		Tags:      nostr.Tags{{"relay", relayURL}, {"challenge", challenge}},
  58  		CreatedAt: sw.NowSeconds(),
  59  	}
  60  	// Proxy signing through shell SW -> signer extension.
  61  	cryptoProxy("signEvent", "", authEv.ToJSON(), func(signedJSON, errMsg string) {
  62  		if errMsg != "" || signedJSON == "" {
  63  			return
  64  		}
  65  		c := rpool.Get(relayURL)
  66  		if c != nil && c.IsOpen() {
  67  			c.Send("[\"AUTH\"," + signedJSON + "]")
  68  		}
  69  	})
  70  }
  71  
  72  func relayPublish(ev *nostr.Event) {
  73  	for _, url := range writeRelays {
  74  		getConn(url).Publish(ev)
  75  	}
  76  }
  77  
  78  func relayPublishExcept(ev *nostr.Event, exceptURL string) {
  79  	for _, wr := range writeRelays {
  80  		if wr != exceptURL {
  81  			getConn(wr).Publish(ev)
  82  		}
  83  	}
  84  }
  85  
  86  func urlSuffix(url string) string {
  87  	n := min(len(url), 8)
  88  	out := make([]byte, 0, n)
  89  	for i := len(url) - n; i < len(url); i++ {
  90  		c := url[i]
  91  		if (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') {
  92  			out = append(out, c)
  93  		}
  94  	}
  95  	return string(out)
  96  }
  97  
  98  func handleRelayInfo(clientID, relayURL string) {
  99  	fwd(clientID, "[\"RELAY_INFO\","+jstr(relayURL)+",null]")
 100  }
 101