github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/neatptc/downloader/api.go (about)

     1  package downloader
     2  
     3  import (
     4  	"context"
     5  	"sync"
     6  
     7  	"github.com/neatio-net/neatio"
     8  	"github.com/neatio-net/neatio/network/rpc"
     9  	"github.com/neatio-net/neatio/utilities/event"
    10  )
    11  
    12  type PublicDownloaderAPI struct {
    13  	d                         *Downloader
    14  	mux                       *event.TypeMux
    15  	installSyncSubscription   chan chan interface{}
    16  	uninstallSyncSubscription chan *uninstallSyncSubscriptionRequest
    17  }
    18  
    19  func NewPublicDownloaderAPI(d *Downloader, m *event.TypeMux) *PublicDownloaderAPI {
    20  	api := &PublicDownloaderAPI{
    21  		d:                         d,
    22  		mux:                       m,
    23  		installSyncSubscription:   make(chan chan interface{}),
    24  		uninstallSyncSubscription: make(chan *uninstallSyncSubscriptionRequest),
    25  	}
    26  
    27  	go api.eventLoop()
    28  
    29  	return api
    30  }
    31  
    32  func (api *PublicDownloaderAPI) eventLoop() {
    33  	var (
    34  		sub               = api.mux.Subscribe(StartEvent{}, DoneEvent{}, FailedEvent{})
    35  		syncSubscriptions = make(map[chan interface{}]struct{})
    36  	)
    37  
    38  	for {
    39  		select {
    40  		case i := <-api.installSyncSubscription:
    41  			syncSubscriptions[i] = struct{}{}
    42  		case u := <-api.uninstallSyncSubscription:
    43  			delete(syncSubscriptions, u.c)
    44  			close(u.uninstalled)
    45  		case event := <-sub.Chan():
    46  			if event == nil {
    47  				return
    48  			}
    49  
    50  			var notification interface{}
    51  			switch event.Data.(type) {
    52  			case StartEvent:
    53  				notification = &SyncingResult{
    54  					Syncing: true,
    55  					Status:  api.d.Progress(),
    56  				}
    57  			case DoneEvent, FailedEvent:
    58  				notification = false
    59  			}
    60  
    61  			for c := range syncSubscriptions {
    62  				c <- notification
    63  			}
    64  		}
    65  	}
    66  }
    67  
    68  func (api *PublicDownloaderAPI) Syncing(ctx context.Context) (*rpc.Subscription, error) {
    69  	notifier, supported := rpc.NotifierFromContext(ctx)
    70  	if !supported {
    71  		return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported
    72  	}
    73  
    74  	rpcSub := notifier.CreateSubscription()
    75  
    76  	go func() {
    77  		statuses := make(chan interface{})
    78  		sub := api.SubscribeSyncStatus(statuses)
    79  
    80  		for {
    81  			select {
    82  			case status := <-statuses:
    83  				notifier.Notify(rpcSub.ID, status)
    84  			case <-rpcSub.Err():
    85  				sub.Unsubscribe()
    86  				return
    87  			case <-notifier.Closed():
    88  				sub.Unsubscribe()
    89  				return
    90  			}
    91  		}
    92  	}()
    93  
    94  	return rpcSub, nil
    95  }
    96  
    97  type SyncingResult struct {
    98  	Syncing bool                `json:"syncing"`
    99  	Status  neatio.SyncProgress `json:"status"`
   100  }
   101  
   102  type uninstallSyncSubscriptionRequest struct {
   103  	c           chan interface{}
   104  	uninstalled chan interface{}
   105  }
   106  
   107  type SyncStatusSubscription struct {
   108  	api       *PublicDownloaderAPI
   109  	c         chan interface{}
   110  	unsubOnce sync.Once
   111  }
   112  
   113  func (s *SyncStatusSubscription) Unsubscribe() {
   114  	s.unsubOnce.Do(func() {
   115  		req := uninstallSyncSubscriptionRequest{s.c, make(chan interface{})}
   116  		s.api.uninstallSyncSubscription <- &req
   117  
   118  		for {
   119  			select {
   120  			case <-s.c:
   121  
   122  				continue
   123  			case <-req.uninstalled:
   124  				return
   125  			}
   126  		}
   127  	})
   128  }
   129  
   130  func (api *PublicDownloaderAPI) SubscribeSyncStatus(status chan interface{}) *SyncStatusSubscription {
   131  	api.installSyncSubscription <- status
   132  	return &SyncStatusSubscription{api: api, c: status}
   133  }