@@ -24,7 +24,7 @@ import (
2424 "time"
2525
2626 "github.com/cskr/pubsub"
27- "github.com/ethereum/go-ethereum"
27+ ethereum "github.com/ethereum/go-ethereum"
2828 "github.com/ethereum/go-ethereum/common"
2929 "github.com/ethereum/go-ethereum/core/types"
3030 "github.com/ethereum/go-ethereum/ethclient"
@@ -619,18 +619,18 @@ type Header struct {
619619// SubscribeNewHead subscribes to notifications about the current blockchain head
620620// on the given channel.
621621func (mc * Client ) SubscribeNewHead (ctx context.Context , ch chan <- * Header ) (ethereum.Subscription , error ) {
622- clientsMap := mc .rpcClientMap .Map ()
623- lens := len (clientsMap )
622+ ids := mc .rpcClientMap .Ids ()
623+ lens := len (ids )
624624 if lens == 0 {
625625 return nil , ErrNoEthClient
626626 }
627627
628628 var subscribeNewHeadWg sync.WaitGroup
629629
630630 cctx , cancel := context .WithCancel (ctx )
631- for url := range clientsMap {
631+ for _ , id := range ids {
632632 subscribeNewHeadWg .Add (1 )
633- go mc .subscribeNewHead (cctx , & subscribeNewHeadWg , url , ch )
633+ go mc .subscribeNewHead (cctx , & subscribeNewHeadWg , id , ch )
634634 }
635635
636636 newClientCh := mc .pubSub .Sub (newAvailableClientTopic )
@@ -640,9 +640,9 @@ func (mc *Client) SubscribeNewHead(ctx context.Context, ch chan<- *Header) (ethe
640640 for {
641641 select {
642642 case newC := <- newClientCh :
643- url := newC .(string )
643+ id := newC .(uint64 )
644644 subscribeNewHeadWg .Add (1 )
645- go mc .subscribeNewHead (cctx , & subscribeNewHeadWg , url , ch )
645+ go mc .subscribeNewHead (cctx , & subscribeNewHeadWg , id , ch )
646646 case <- cctx .Done ():
647647 return
648648 }
@@ -657,46 +657,69 @@ func (mc *Client) SubscribeNewHead(ctx context.Context, ch chan<- *Header) (ethe
657657 }), nil
658658}
659659
660- func (mc * Client ) subscribeNewHead (ctx context.Context , wg * sync.WaitGroup , url string , ch chan <- * Header ) error {
660+ func (mc * Client ) subscribeNewHead (ctx context.Context , wg * sync.WaitGroup , id uint64 , ch chan <- * Header ) error {
661+ logger := log .New ("id" , id )
661662 defer wg .Done ()
662663
663664 for {
664- rc := mc .rpcClientMap .Get ( url )
665- if rc == nil {
666- log .Trace ("EthClient has been removed" , "url" , url )
665+ rc , existed := mc .rpcClientMap .GetById ( id )
666+ if ! existed {
667+ logger .Trace ("EthClient has been removed" )
667668 return nil
668669 }
669-
670- headerCh := make (chan * types.Header )
671- c := ethclient .NewClient (rc )
672- sub , err := c .SubscribeNewHead (ctx , headerCh )
673- if err != nil {
674- log .Warn ("Failed to subscribe new head" , "url" , url , "err" , err )
670+ if rc == nil {
671+ logger .Warn ("The client is not ready, wait for a while" )
675672 } else {
676- WAIT_NEW_HEADER:
677- for {
678- select {
679- case header := <- headerCh :
680- h := & Header {
681- Client : rc ,
682- Header : header ,
683- }
684- select {
685- case ch <- h :
686- case <- ctx .Done ():
687- return nil
688- }
689- case err := <- sub .Err ():
690- log .Warn ("Failed during subscription" , "url" , url , "err" , err )
691- break WAIT_NEW_HEADER
692- case <- ctx .Done ():
693- return nil
694- }
673+ // If we have error, we need to retry
674+ err := doSubscribe (ctx , id , rc , ch )
675+ if err == nil {
676+ return nil
695677 }
696678 }
679+
697680 // retry subscribe after retryPeriod
698- time .Sleep (retryPeriod )
699- log .Trace ("Retry to subscribe new head" , "url" , url )
681+ t := time .NewTicker (retryPeriod )
682+ select {
683+ case <- t .C :
684+ case <- ctx .Done ():
685+ t .Stop ()
686+ return nil
687+ }
688+ t .Stop ()
689+ logger .Trace ("Retry to subscribe new head" )
690+ }
691+ }
692+
693+ func doSubscribe (ctx context.Context , id uint64 , rc * rpc.Client , ch chan <- * Header ) error {
694+ logger := log .New ("id" , id )
695+ headerCh := make (chan * types.Header )
696+ c := ethclient .NewClient (rc )
697+ subCtx , cancel := context .WithCancel (ctx )
698+ defer cancel ()
699+
700+ sub , err := c .SubscribeNewHead (subCtx , headerCh )
701+ if err != nil {
702+ logger .Warn ("Failed to subscribe new head" , "err" , err )
703+ return err
704+ }
705+ for {
706+ select {
707+ case header := <- headerCh :
708+ h := & Header {
709+ Client : rc ,
710+ Header : header ,
711+ }
712+ select {
713+ case ch <- h :
714+ case <- subCtx .Done ():
715+ return nil
716+ }
717+ case err := <- sub .Err ():
718+ logger .Warn ("Failed during subscription" , "err" , err )
719+ return err
720+ case <- subCtx .Done ():
721+ return nil
722+ }
700723 }
701724}
702725
@@ -788,8 +811,8 @@ func (mc *Client) DialClients(ctx context.Context) {
788811 for i := 0 ; i < len (urls ); i ++ {
789812 dialed := <- dialCh
790813 if dialed .client != nil {
791- mc .rpcClientMap .Replace (dialed .url , dialed .client )
792- mc .pubSub .Pub (dialed . url , newAvailableClientTopic )
814+ id := mc .rpcClientMap .Replace (dialed .url , dialed .client )
815+ mc .pubSub .Pub (id , newAvailableClientTopic )
793816 }
794817 }
795818}
0 commit comments