@@ -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