77package ipn
88
99import (
10+ "encoding/json"
1011 "errors"
1112 "fmt"
1213 "strings"
@@ -32,7 +33,7 @@ type RpnAcc = rpn.RpnAcc
3233
3334// and kick-off an update if the acc is expired?
3435type rpnp struct {
35- mu sync.RWMutex // protects Proxy & kids
36+ mu sync.RWMutex // protects p, s, kids, & skids
3637
3738 // parent proxy
3839 p Proxy
@@ -45,6 +46,10 @@ type rpnp struct {
4546
4647 // forked child proxy IDs, may be empty (returned proxy IDs may have stopped)
4748 kids map [string ]struct {}
49+ // server metadata for each forked kid (keyed by CC)
50+ skids map [string ]* x.RpnServer
51+ // server metadata for the main proxy
52+ s * x.RpnServer
4853}
4954
5055var _ RpnProxy = (* rpnp )(nil )
6368)
6469
6570// nb: client code isn't really expecting error from asRpnProxy.
66- func asRpnProxy (e Proxy , acc RpnAcc , pxr Rpn ) (RpnProxy , error ) {
71+ func asRpnProxy (e Proxy , srv * x. RpnServer , acc RpnAcc , pxr Rpn ) (RpnProxy , error ) {
6772 if e == nil || acc == nil || pxr == nil {
6873 return nil , errRpnBadArgs
6974 }
@@ -75,7 +80,7 @@ func asRpnProxy(e Proxy, acc RpnAcc, pxr Rpn) (RpnProxy, error) {
7580 return nil , errRpnIDsMismatch
7681 }
7782 log .D ("proxy: rpn: make: %s[%s]" , providerid , proxyid )
78- return & rpnp {sync.RWMutex {}, e , acc , pxr , make (map [string ]struct {}, 0 )}, nil
83+ return & rpnp {sync.RWMutex {}, e , acc , pxr , make (map [string ]struct {}, 0 ), make ( map [ string ] * x. RpnServer , 0 ), srv }, nil
7984}
8085
8186func (r * rpnp ) ensureProxy () Proxy {
@@ -324,7 +329,13 @@ func (r *rpnp) fork(cc string) (x.Proxy, error) {
324329 // re-forking main proxy (which may not be multi-country acc) via Update() => forkAll()
325330 log .I ("proxy: rpn: fork: %s main cc %s; re-adding..." , provider , cc )
326331 // expect Emplace to be called
327- return r .pxr .addRpnProxy (acc , cc ) // re-generates conf and re-adds
332+ kid , srv , err := r .pxr .addRpnProxy (acc , cc ) // re-generates conf and re-adds
333+ if kid != nil && core .IsNotNil (kid ) {
334+ r .mu .Lock ()
335+ r .s = srv
336+ r .mu .Unlock ()
337+ }
338+ return kid , err
328339 }
329340
330341 // check main's status if not forking main
@@ -344,11 +355,14 @@ func (r *rpnp) fork(cc string) (x.Proxy, error) {
344355 log .I ("proxy: rpn: fork: %s[%s]" , provider , cc )
345356
346357 // re-adds + updates if the proxy already exists
347- kid , err := r .pxr .addRpnProxy (acc , cc )
358+ kid , srv , err := r .pxr .addRpnProxy (acc , cc )
348359
349360 if kid != nil && core .IsNotNil (kid ) {
350361 r .mu .Lock ()
351362 r .kids [cc ] = struct {}{}
363+ if srv != nil {
364+ r .skids [cc ] = srv
365+ }
352366 r .mu .Unlock ()
353367 }
354368
@@ -476,6 +490,9 @@ func (r *rpnp) purgeMain() bool {
476490 if err != nil {
477491 return false
478492 }
493+ r .mu .Lock ()
494+ r .s = nil
495+ r .mu .Unlock ()
479496 return r .pxr .removeRpnProxy (r .RpnAcc , mainpid )
480497}
481498
@@ -511,6 +528,7 @@ func (r *rpnp) purge(cc string) bool {
511528
512529 r .mu .Lock ()
513530 delete (r .kids , cc )
531+ delete (r .skids , cc )
514532 r .mu .Unlock ()
515533
516534 log .D ("proxy: rpn: purge: %s[%s]? %t" , provider , cc , rmv )
@@ -569,12 +587,16 @@ func (r *rpnp) get(cc string) (Proxy, error) {
569587}
570588
571589// Kids implements x.RpnProxy.
572- func (r * rpnp ) Kids () (csvpids string ) {
573- return r .kidsCsv ()
574- }
575-
576- func (r * rpnp ) kidsCsv () string {
577- return strings .Join (r .flattenKids (), "," )
590+ func (r * rpnp ) Kids () x.RpnServers {
591+ r .mu .RLock ()
592+ all := make ([]x.RpnServer , 0 , len (r .skids ))
593+ for _ , s := range r .skids {
594+ if s != nil {
595+ all = append (all , * s )
596+ }
597+ }
598+ r .mu .RUnlock ()
599+ return & liveServers {all : all }
578600}
579601
580602func (r * rpnp ) flattenKids () (ccs []string ) {
@@ -588,6 +610,46 @@ func (r *rpnp) flattenKids() (ccs []string) {
588610 return
589611}
590612
613+ // liveServers implements x.RpnServers.
614+ type liveServers struct {
615+ all []x.RpnServer
616+ }
617+
618+ var _ x.RpnServers = (* liveServers )(nil )
619+
620+ func (s * liveServers ) Get (i int ) (* x.RpnServer , error ) {
621+ if i < 0 || i >= len (s .all ) {
622+ return nil , fmt .Errorf ("rpn: live: %d out of range [0, %d)" , i , len (s .all ))
623+ }
624+ return & s .all [i ], nil
625+ }
626+
627+ func (s * liveServers ) Len () int {
628+ return len (s .all )
629+ }
630+
631+ func (s * liveServers ) Json () ([]byte , error ) {
632+ if s == nil || len (s .all ) <= 0 {
633+ return nil , fmt .Errorf ("rpn: live: no servers" )
634+ }
635+ b , err := json .Marshal (s .all )
636+ if err != nil {
637+ return nil , fmt .Errorf ("rpn: live: json: %w" , err )
638+ }
639+ return b , nil
640+ }
641+
642+ // Main implements x.RpnProxy.
643+ func (r * rpnp ) Main () (m * x.RpnServer ) {
644+ r .mu .RLock ()
645+ if s := r .s ; s != nil {
646+ m = new (x.RpnServer )
647+ * m = * s
648+ }
649+ r .mu .RUnlock ()
650+ return
651+ }
652+
591653// Update implements RpnAcc.
592654func (r * rpnp ) Update (ops * x.RpnOps ) (newState []byte , err error ) {
593655 newState , err = r .RpnAcc .Update (ops )
0 commit comments