github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/eth/downloader/api.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:38</date> 10 //</624342633455554560> 11 12 13 package downloader 14 15 import ( 16 "context" 17 "sync" 18 19 ethereum "github.com/ethereum/go-ethereum" 20 "github.com/ethereum/go-ethereum/event" 21 "github.com/ethereum/go-ethereum/rpc" 22 ) 23 24 //PublicDownloaderAPI提供了一个API,它提供有关当前同步状态的信息。 25 //它只提供对任何人都可以使用的数据进行操作的方法,而不存在安全风险。 26 type PublicDownloaderAPI struct { 27 d *Downloader 28 mux *event.TypeMux 29 installSyncSubscription chan chan interface{} 30 uninstallSyncSubscription chan *uninstallSyncSubscriptionRequest 31 } 32 33 //新建PublicDownloaderAPI创建新的PublicDownloaderAPI。API有一个内部事件循环, 34 //通过全局事件mux从下载程序侦听事件。如果它收到 35 //这些事件会将其广播到通过 36 //InstallSyncSubscription频道。 37 func NewPublicDownloaderAPI(d *Downloader, m *event.TypeMux) *PublicDownloaderAPI { 38 api := &PublicDownloaderAPI{ 39 d: d, 40 mux: m, 41 installSyncSubscription: make(chan chan interface{}), 42 uninstallSyncSubscription: make(chan *uninstallSyncSubscriptionRequest), 43 } 44 45 go api.eventLoop() 46 47 return api 48 } 49 50 //EventLoop运行一个循环,直到事件mux关闭。它将安装和卸载新的 51 //将订阅和广播同步状态更新同步到已安装的同步订阅。 52 func (api *PublicDownloaderAPI) eventLoop() { 53 var ( 54 sub = api.mux.Subscribe(StartEvent{}, DoneEvent{}, FailedEvent{}) 55 syncSubscriptions = make(map[chan interface{}]struct{}) 56 ) 57 58 for { 59 select { 60 case i := <-api.installSyncSubscription: 61 syncSubscriptions[i] = struct{}{} 62 case u := <-api.uninstallSyncSubscription: 63 delete(syncSubscriptions, u.c) 64 close(u.uninstalled) 65 case event := <-sub.Chan(): 66 if event == nil { 67 return 68 } 69 70 var notification interface{} 71 switch event.Data.(type) { 72 case StartEvent: 73 notification = &SyncingResult{ 74 Syncing: true, 75 Status: api.d.Progress(), 76 } 77 case DoneEvent, FailedEvent: 78 notification = false 79 } 80 //广播 81 for c := range syncSubscriptions { 82 c <- notification 83 } 84 } 85 } 86 } 87 88 //同步提供此节点何时开始与以太坊网络同步以及何时完成同步的信息。 89 func (api *PublicDownloaderAPI) Syncing(ctx context.Context) (*rpc.Subscription, error) { 90 notifier, supported := rpc.NotifierFromContext(ctx) 91 if !supported { 92 return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported 93 } 94 95 rpcSub := notifier.CreateSubscription() 96 97 go func() { 98 statuses := make(chan interface{}) 99 sub := api.SubscribeSyncStatus(statuses) 100 101 for { 102 select { 103 case status := <-statuses: 104 notifier.Notify(rpcSub.ID, status) 105 case <-rpcSub.Err(): 106 sub.Unsubscribe() 107 return 108 case <-notifier.Closed(): 109 sub.Unsubscribe() 110 return 111 } 112 } 113 }() 114 115 return rpcSub, nil 116 } 117 118 //同步结果提供有关此节点当前同步状态的信息。 119 type SyncingResult struct { 120 Syncing bool `json:"syncing"` 121 Status ethereum.SyncProgress `json:"status"` 122 } 123 124 //UninstallSyncSubscriptionRequest在API事件循环中卸载同步订阅。 125 type uninstallSyncSubscriptionRequest struct { 126 c chan interface{} 127 uninstalled chan interface{} 128 } 129 130 //SyncStatusSubscription表示同步订阅。 131 type SyncStatusSubscription struct { 132 api *PublicDownloaderAPI //在此API实例的事件循环中注册订阅 133 c chan interface{} //事件广播到的频道 134 unsubOnce sync.Once //确保取消订阅逻辑执行一次 135 } 136 137 //取消订阅将从DeloLoad事件循环中卸载订阅。 138 //传递给subscribeSyncStatus的状态通道不再使用。 139 //在这个方法返回之后。 140 func (s *SyncStatusSubscription) Unsubscribe() { 141 s.unsubOnce.Do(func() { 142 req := uninstallSyncSubscriptionRequest{s.c, make(chan interface{})} 143 s.api.uninstallSyncSubscription <- &req 144 145 for { 146 select { 147 case <-s.c: 148 //删除新的状态事件,直到卸载确认 149 continue 150 case <-req.uninstalled: 151 return 152 } 153 } 154 }) 155 } 156 157 //订阅同步状态创建将广播新同步更新的订阅。 158 //给定的通道必须接收接口值,结果可以是 159 func (api *PublicDownloaderAPI) SubscribeSyncStatus(status chan interface{}) *SyncStatusSubscription { 160 api.installSyncSubscription <- status 161 return &SyncStatusSubscription{api: api, c: status} 162 } 163