@@ -50,6 +50,8 @@ type mobileClient struct {
5050	localPrivCreateCallback   NativeCallback 
5151	remoteKeyReceiveCallback  NativeCallback 
5252	authDataCallback          NativeCallback 
53+ 
54+ 	mutex  sync.Mutex 
5355}
5456
5557func  newMobileClient () * mobileClient  {
9193
9294	m  =  make (map [string ]* mobileClient )
9395
94- 	// mMutex should always be used to guard the m  map 
96+ 	// mMutex should always be used to guard the mutex  map.  
9597	mMutex  sync.RWMutex 
9698
9799	registry  =  make (map [string ]func (context.Context ,
@@ -100,6 +102,20 @@ var (
100102	interceptorLogsInitialize  =  false 
101103)
102104
105+ // getClient returns the mobile client for the given namespace or an error if no 
106+ // client exists. 
107+ func  getClient (nameSpace  string ) (* mobileClient , error ) {
108+ 	mMutex .Lock ()
109+ 	defer  mMutex .Unlock ()
110+ 
111+ 	mc , ok  :=  m [nameSpace ]
112+ 	if  ! ok  {
113+ 		return  nil , fmt .Errorf ("unknown namespace: %v" , nameSpace )
114+ 	}
115+ 
116+ 	return  mc , nil 
117+ }
118+ 
103119// InitLNC sets up everything required for LNC to run including 
104120// signal interceptor, logs, and an instance of the mobile client. 
105121func  InitLNC (nameSpace , debugLevel  string ) error  {
@@ -173,85 +189,91 @@ func ConnectServer(nameSpace string, mailboxServer string, isDevServer bool,
173189		}
174190	}
175191
176- 	mMutex .Lock ()
177- 	defer  mMutex .Unlock ()
178- 
179- 	mc , ok  :=  m [nameSpace ]
180- 	if  ! ok  {
181- 		return  fmt .Errorf ("unknown namespace: %s" , nameSpace )
182- 	}
183- 
184- 	statusChecker , lndConnect , err  :=  core .MailboxRPCConnection (
185- 		mailboxServer , pairingPhrase , localPriv , remotePub ,
186- 		func (key  * btcec.PublicKey ) error  {
187- 			mc .remoteKeyReceiveCallback .SendResult (
188- 				hex .EncodeToString (key .SerializeCompressed ()),
189- 			)
190- 
191- 			return  nil 
192- 		}, func (data  []byte ) error  {
193- 			parts  :=  strings .Split (string (data ), ": " )
194- 			if  len (parts ) !=  2  ||  parts [0 ] !=  "Macaroon"  {
195- 				return  fmt .Errorf ("authdata does "  + 
196- 					"not contain a macaroon" )
197- 			}
198- 
199- 			macBytes , err  :=  hex .DecodeString (parts [1 ])
200- 			if  err  !=  nil  {
201- 				return  err 
202- 			}
203- 
204- 			mac  :=  & macaroon.Macaroon {}
205- 			err  =  mac .UnmarshalBinary (macBytes )
206- 			if  err  !=  nil  {
207- 				return  fmt .Errorf ("unable to decode " + 
208- 					"macaroon: %v" , err )
209- 			}
210- 
211- 			mc .mac  =  mac 
192+ 	// Since the connection function is blocking, we need to spin it off 
193+ 	// in another goroutine here. See https://pkg.go.dev/syscall/js#FuncOf. 
194+ 	go  func () {
195+ 		mc , err  :=  getClient (nameSpace )
196+ 		if  err  !=  nil  {
197+ 			log .Errorf ("Error getting client: %v" , err )
198+ 			return 
199+ 		}
212200
213- 			mc .authDataCallback .SendResult (string (data ))
201+ 		mc .mutex .Lock ()
202+ 		defer  mc .mutex .Unlock ()
203+ 
204+ 		statusChecker , lndConnect , err  :=  core .MailboxRPCConnection (
205+ 			mailboxServer , pairingPhrase , localPriv , remotePub ,
206+ 			func (key  * btcec.PublicKey ) error  {
207+ 				mc .remoteKeyReceiveCallback .SendResult (
208+ 					hex .EncodeToString (key .SerializeCompressed ()),
209+ 				)
210+ 
211+ 				return  nil 
212+ 			}, func (data  []byte ) error  {
213+ 				parts  :=  strings .Split (string (data ), ": " )
214+ 				if  len (parts ) !=  2  ||  parts [0 ] !=  "Macaroon"  {
215+ 					return  fmt .Errorf ("authdata does "  + 
216+ 						"not contain a macaroon" )
217+ 				}
218+ 
219+ 				macBytes , err  :=  hex .DecodeString (parts [1 ])
220+ 				if  err  !=  nil  {
221+ 					return  err 
222+ 				}
223+ 
224+ 				mac  :=  & macaroon.Macaroon {}
225+ 				err  =  mac .UnmarshalBinary (macBytes )
226+ 				if  err  !=  nil  {
227+ 					return  fmt .Errorf ("unable to decode " + 
228+ 						"macaroon: %v" , err )
229+ 				}
230+ 
231+ 				mc .mac  =  mac 
232+ 
233+ 				mc .authDataCallback .SendResult (string (data ))
234+ 
235+ 				return  nil 
236+ 			},
237+ 		)
238+ 		if  err  !=  nil  {
239+ 			log .Errorf ("Error running wasm client: %v" , err )
240+ 		}
214241
215- 			return  nil 
216- 		},
217- 	)
218- 	if  err  !=  nil  {
219- 		return  err 
220- 	}
242+ 		mc .statusChecker  =  statusChecker 
243+ 		mc .lndConn , err  =  lndConnect ()
244+ 		if  err  !=  nil  {
245+ 			log .Errorf ("Error running wasm client: %v" , err )
246+ 		}
221247
222- 	mc .statusChecker  =  statusChecker 
223- 	mc .lndConn , err  =  lndConnect ()
224- 	if  err  !=  nil  {
225- 		return  err 
226- 	}
248+ 		log .Debugf ("Mobile client connected to RPC" )
249+ 	}()
227250
228- 	log .Debugf ("Mobile client connected to RPC" )
229251	return  nil 
230252}
231253
232254// IsConnected returns whether or not there is an active connection. 
233255func  IsConnected (nameSpace  string ) (bool , error ) {
234- 	mMutex .Lock ()
235- 	defer  mMutex .Unlock ()
236- 
237- 	mc , ok  :=  m [nameSpace ]
238- 	if  ! ok  {
239- 		return  false , fmt .Errorf ("unknown namespace: %s" , nameSpace )
256+ 	mc , err  :=  getClient (nameSpace )
257+ 	if  err  !=  nil  {
258+ 		return  false , fmt .Errorf ("error getting client: %v" , err )
240259	}
241260
261+ 	mc .mutex .Lock ()
262+ 	defer  mc .mutex .Unlock ()
263+ 
242264	return  mc .lndConn  !=  nil , nil 
243265}
244266
245267// Disconnect closes the RPC connection. 
246268func  Disconnect (nameSpace  string ) error  {
247- 	mMutex .Lock ()
248- 	defer  mMutex .Unlock ()
249- 
250- 	mc , ok  :=  m [nameSpace ]
251- 	if  ! ok  {
252- 		return  fmt .Errorf ("unknown namespace: %s" , nameSpace )
269+ 	mc , err  :=  getClient (nameSpace )
270+ 	if  err  !=  nil  {
271+ 		return  fmt .Errorf ("error getting client: %v" , err )
253272	}
254273
274+ 	mc .mutex .Lock ()
275+ 	defer  mc .mutex .Unlock ()
276+ 
255277	if  mc .lndConn  !=  nil  {
256278		if  err  :=  mc .lndConn .Close (); err  !=  nil  {
257279			log .Errorf ("Error closing RPC connection: %v" , err )
@@ -264,14 +286,14 @@ func Disconnect(nameSpace string) error {
264286
265287// Status returns the status of the LNC RPC connection. 
266288func  Status (nameSpace  string ) (string , error ) {
267- 	mMutex .Lock ()
268- 	defer  mMutex .Unlock ()
269- 
270- 	mc , ok  :=  m [nameSpace ]
271- 	if  ! ok  {
272- 		return  "" , fmt .Errorf ("unknown namespace: %s" , nameSpace )
289+ 	mc , err  :=  getClient (nameSpace )
290+ 	if  err  !=  nil  {
291+ 		return  "" , fmt .Errorf ("error getting client: %v" , err )
273292	}
274293
294+ 	mc .mutex .Lock ()
295+ 	defer  mc .mutex .Unlock ()
296+ 
275297	if  mc .statusChecker  ==  nil  {
276298		return  "" , nil 
277299	}
@@ -284,14 +306,14 @@ func Status(nameSpace string) (string, error) {
284306func  RegisterLocalPrivCreateCallback (nameSpace  string ,
285307	c  NativeCallback ) error  {
286308
287- 	mMutex .Lock ()
288- 	defer  mMutex .Unlock ()
289- 
290- 	mc , ok  :=  m [nameSpace ]
291- 	if  ! ok  {
292- 		return  fmt .Errorf ("unknown namespace: %s" , nameSpace )
309+ 	mc , err  :=  getClient (nameSpace )
310+ 	if  err  !=  nil  {
311+ 		return  fmt .Errorf ("error getting client: %v" , err )
293312	}
294313
314+ 	mc .mutex .Lock ()
315+ 	defer  mc .mutex .Unlock ()
316+ 
295317	mc .localPrivCreateCallback  =  c 
296318
297319	return  nil 
@@ -302,14 +324,14 @@ func RegisterLocalPrivCreateCallback(nameSpace string,
302324func  RegisterRemoteKeyReceiveCallback (nameSpace  string ,
303325	c  NativeCallback ) error  {
304326
305- 	mMutex .Lock ()
306- 	defer  mMutex .Unlock ()
307- 
308- 	mc , ok  :=  m [nameSpace ]
309- 	if  ! ok  {
310- 		return  fmt .Errorf ("unknown namespace: %s" , nameSpace )
327+ 	mc , err  :=  getClient (nameSpace )
328+ 	if  err  !=  nil  {
329+ 		return  fmt .Errorf ("error getting client: %v" , err )
311330	}
312331
332+ 	mc .mutex .Lock ()
333+ 	defer  mc .mutex .Unlock ()
334+ 
313335	mc .remoteKeyReceiveCallback  =  c 
314336
315337	return  nil 
@@ -318,14 +340,14 @@ func RegisterRemoteKeyReceiveCallback(nameSpace string,
318340// RegisterAuthDataCallback sets up the native callbacks upon 
319341// receiving auth data. 
320342func  RegisterAuthDataCallback (nameSpace  string , c  NativeCallback ) error  {
321- 	mMutex .Lock ()
322- 	defer  mMutex .Unlock ()
323- 
324- 	mc , ok  :=  m [nameSpace ]
325- 	if  ! ok  {
326- 		return  fmt .Errorf ("unknown namespace: %s" , nameSpace )
343+ 	mc , err  :=  getClient (nameSpace )
344+ 	if  err  !=  nil  {
345+ 		return  fmt .Errorf ("error getting client: %v" , err )
327346	}
328347
348+ 	mc .mutex .Lock ()
349+ 	defer  mc .mutex .Unlock ()
350+ 
329351	mc .authDataCallback  =  c 
330352
331353	return  nil 
@@ -335,14 +357,14 @@ func RegisterAuthDataCallback(nameSpace string, c NativeCallback) error {
335357func  InvokeRPC (nameSpace  string , rpcName  string , requestJSON  string ,
336358	c  NativeCallback ) error  {
337359
338- 	mMutex .Lock ()
339- 	defer  mMutex .Unlock ()
340- 
341- 	mc , ok  :=  m [nameSpace ]
342- 	if  ! ok  {
343- 		return  fmt .Errorf ("unknown namespace: %s" , nameSpace )
360+ 	mc , err  :=  getClient (nameSpace )
361+ 	if  err  !=  nil  {
362+ 		return  fmt .Errorf ("error getting client: %v" , err )
344363	}
345364
365+ 	mc .mutex .Lock ()
366+ 	defer  mc .mutex .Unlock ()
367+ 
346368	if  rpcName  ==  ""  {
347369		return  fmt .Errorf ("param rpcName required" )
348370	}
@@ -380,14 +402,14 @@ func InvokeRPC(nameSpace string, rpcName string, requestJSON string,
380402
381403// GetExpiry returns the expiration time of the connection macaroon. 
382404func  GetExpiry (nameSpace  string ) (string , error ) {
383- 	mMutex .Lock ()
384- 	defer  mMutex .Unlock ()
385- 
386- 	mc , ok  :=  m [nameSpace ]
387- 	if  ! ok  {
388- 		return  "" , fmt .Errorf ("unknown namespace: %s" , nameSpace )
405+ 	mc , err  :=  getClient (nameSpace )
406+ 	if  err  !=  nil  {
407+ 		return  "" , fmt .Errorf ("error getting client: %v" , err )
389408	}
390409
410+ 	mc .mutex .Lock ()
411+ 	defer  mc .mutex .Unlock ()
412+ 
391413	if  mc .mac  ==  nil  {
392414		return  "" , fmt .Errorf ("macaroon not obtained yet. GetExpiry"  + 
393415			"should only be called once the connection is"  + 
@@ -404,14 +426,14 @@ func GetExpiry(nameSpace string) (string, error) {
404426
405427// IsReadOnly returns whether or not the connection macaroon is read-only. 
406428func  IsReadOnly (nameSpace  string ) (bool , error ) {
407- 	mMutex .Lock ()
408- 	defer  mMutex .Unlock ()
409- 
410- 	mc , ok  :=  m [nameSpace ]
411- 	if  ! ok  {
412- 		return  false , fmt .Errorf ("unknown namespace: %s" , nameSpace )
429+ 	mc , err  :=  getClient (nameSpace )
430+ 	if  err  !=  nil  {
431+ 		return  false , fmt .Errorf ("error getting client: %v" , err )
413432	}
414433
434+ 	mc .mutex .Lock ()
435+ 	defer  mc .mutex .Unlock ()
436+ 
415437	if  mc .mac  ==  nil  {
416438		log .Errorf ("macaroon not obtained yet. IsReadOnly should "  + 
417439			"only be called once the connection is complete" )
@@ -430,16 +452,16 @@ func IsReadOnly(nameSpace string) (bool, error) {
430452}
431453
432454// HasPermissions returns whether or not the connection macaroon 
433- // has a specificed  permission. 
455+ // has a specified  permission. 
434456func  HasPermissions (nameSpace , permission  string ) (bool , error ) {
435- 	mMutex .Lock ()
436- 	defer  mMutex .Unlock ()
437- 
438- 	mc , ok  :=  m [nameSpace ]
439- 	if  ! ok  {
440- 		return  false , fmt .Errorf ("unknown namespace: %s" , nameSpace )
457+ 	mc , err  :=  getClient (nameSpace )
458+ 	if  err  !=  nil  {
459+ 		return  false , fmt .Errorf ("error getting client: %v" , err )
441460	}
442461
462+ 	mc .mutex .Lock ()
463+ 	defer  mc .mutex .Unlock ()
464+ 
443465	if  permission  ==  ""  {
444466		return  false , nil 
445467	}
@@ -553,17 +575,17 @@ func validateArgs(mailboxServer, localPrivKey, remotePubKey string) error {
553575// parseKeys parses the given keys from their string format and calls callback 
554576// functions where appropriate. NOTE: This function assumes that the parameter 
555577// combinations have been checked by validateArgs. 
556- func  parseKeys (nameSpace , localPrivKey ,  remotePubKey   string ) ( 
557- 	keychain.SingleKeyECDH , * btcec.PublicKey , error ) {
578+ func  parseKeys (nameSpace , localPrivKey ,
579+ 	remotePubKey   string ) ( keychain.SingleKeyECDH , * btcec.PublicKey , error ) {
558580
559- 	mMutex .Lock ()
560- 	defer  mMutex .Unlock ()
561- 
562- 	mc , ok  :=  m [nameSpace ]
563- 	if  ! ok  {
564- 		return  nil , nil , fmt .Errorf ("unknown namespace: %s" , nameSpace )
581+ 	mc , err  :=  getClient (nameSpace )
582+ 	if  err  !=  nil  {
583+ 		return  nil , nil , fmt .Errorf ("error getting client: %v" , err )
565584	}
566585
586+ 	mc .mutex .Lock ()
587+ 	defer  mc .mutex .Unlock ()
588+ 
567589	var  (
568590		localStaticKey   keychain.SingleKeyECDH 
569591		remoteStaticKey  * btcec.PublicKey 
0 commit comments