main.go raw

   1  package main
   2  
   3  import (
   4  	"common/jsbridge/bc"
   5  	"common/jsbridge/idb"
   6  	"common/jsbridge/sw"
   7  )
   8  
   9  // Relay SW — relay pool, subscriptions, event storage, DM caching.
  10  // Communicates with shell/marmot SWs via BroadcastChannel (client-local).
  11  
  12  var bus bc.BC
  13  
  14  func main() {
  15  	idb.SetVersion(version)
  16  	initSharedState()
  17  	initRouter()
  18  	initRelayProxy()
  19  	sw.OnInstall(onInstall)
  20  	sw.OnActivate(onActivate)
  21  	sw.OnFetch(onFetch)
  22  	sw.OnMessage(onMessage)
  23  	connectBus()
  24  	// Send READY on every start — not just onActivate, which doesn't re-fire
  25  	// when the browser stops and restarts the SW thread.
  26  	busSend("shell", "[\"READY\","+jstr(version)+"]")
  27  }
  28  
  29  func onInstall(event sw.Event) {
  30  	sw.WaitUntil(event, func(done func()) {
  31  		sw.SkipWaiting()
  32  		done()
  33  	})
  34  }
  35  
  36  func onActivate(event sw.Event) {
  37  	sw.WaitUntil(event, func(done func()) {
  38  		sw.ClaimClients(func() {
  39  				busSend("shell", "[\"READY\","+jstr(version)+"]")
  40  			done()
  41  		})
  42  	})
  43  }
  44  
  45  func onFetch(event sw.Event) {
  46  	// Relay SW does not intercept fetches.
  47  }
  48  
  49  func onMessage(event sw.Event) {
  50  	// Keepalive from loader iframe — just receiving the event keeps us alive.
  51  }
  52  
  53  func connectBus() {
  54  	bus = bc.Open("smesh-bus", func(raw string) { onBusMessage(raw) })
  55  }
  56  
  57  func busSend(to, msg string) {
  58  	bc.Send(bus, "{\"from\":\"relay\",\"to\":"+jstr(to)+",\"msg\":"+msg+"}")
  59  }
  60  
  61  func onBusMessage(raw string) {
  62  	from := jsonField(raw, "from")
  63  	if from == "relay" {
  64  		return
  65  	}
  66  	to := jsonField(raw, "to")
  67  	if to != "relay" && to != "*" {
  68  		return
  69  	}
  70  	msg := jsonFieldRaw(raw, "msg")
  71  	if msg == "" {
  72  		return
  73  	}
  74  	w := newMW(msg)
  75  	msgType := w.str()
  76  
  77  	if msgType != "PING" && msgType != "SAVE_DM_QUIET" && msgType != "SAVE_DM" {
  78  		sw.Log("relay: bus→" + msgType)
  79  	}
  80  
  81  	switch msgType {
  82  	case "PING":
  83  		busSend("shell", "[\"READY\","+jstr(version)+"]")
  84  		return
  85  
  86  	// Identity propagation.
  87  	case "SET_PUBKEY":
  88  		identitySetPubkey(w.str())
  89  	case "CLEAR_KEY":
  90  		identityClearKey()
  91  		writeRelays = nil
  92  
  93  	// Relay operations.
  94  	case "SET_WRITE_RELAYS":
  95  		writeRelays = w.strs()
  96  	case "REQ":
  97  		clientID := w.str()
  98  		subID := w.str()
  99  		filterRaw := w.raw()
 100  		routerReq(clientID, subID, filterRaw)
 101  	case "CLOSE":
 102  		subID := w.str()
 103  		routerClose(subID)
 104  	case "EVENT":
 105  		clientID := w.str()
 106  		eventRaw := w.raw()
 107  		routerPublish(clientID, eventRaw)
 108  	case "MLS_RELAY_PUBLISH":
 109  		eventRaw := w.raw()
 110  		relayURLs := w.strs()
 111  		routerPublishToRelays(eventRaw, relayURLs)
 112  	case "PROXY":
 113  		clientID := w.str()
 114  		subID := w.str()
 115  		filterRaw := w.raw()
 116  		relayURLs := w.strs()
 117  		routerProxy(clientID, subID, filterRaw, relayURLs)
 118  	case "RELAY_INFO":
 119  		clientID := w.str()
 120  		relayURL := w.str()
 121  		handleRelayInfo(clientID, relayURL)
 122  	case "SIGN":
 123  		clientID := w.str()
 124  		requestID := w.str()
 125  		eventRaw := w.raw()
 126  		routerSign(clientID, requestID, eventRaw)
 127  	case "BROADCAST":
 128  		clientID := w.str()
 129  		pubkey := w.str()
 130  		relayURLs := w.strs()
 131  		routerBroadcast(clientID, pubkey, relayURLs)
 132  
 133  	// DM storage.
 134  	case "DM_LIST":
 135  		clientID := w.str()
 136  		routerDMList(clientID)
 137  	case "DM_HISTORY":
 138  		clientID := w.str()
 139  		peer := w.str()
 140  		limit := int(w.num())
 141  		until := w.num()
 142  		routerDMHistory(clientID, peer, limit, until)
 143  	case "SAVE_DM":
 144  		dmJSON := w.raw()
 145  		cacheSaveDM(dmJSON, func(result string) {
 146  			if result != "duplicate" {
 147  				fwdAll("[\"DM_RECEIVED\"," + dmJSON + "]")
 148  			}
 149  		})
 150  	case "SAVE_DM_QUIET":
 151  		dmJSON := w.raw()
 152  		cacheSaveDM(dmJSON, func(result string) {})
 153  	case "CLEAR_DM_HISTORY":
 154  		peer := w.str()
 155  		cacheClearDMsByPeer(peer, func() {
 156  			busSend("shell", "[\"DM_HISTORY_CLEARED\","+jstr(peer)+"]")
 157  		})
 158  
 159  	// Crypto proxy result from shell.
 160  	case "CRYPTO_RESULT":
 161  		id := int(w.num())
 162  		result := w.str()
 163  		errMsg := w.str()
 164  		if fn, ok := cryptoCBs[id]; ok {
 165  			delete(cryptoCBs, id)
 166  			fn(result, errMsg)
 167  		}
 168  	}
 169  
 170  }
 171