github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/chain/accounts/manager.go (about) 1 package accounts 2 3 import ( 4 "reflect" 5 "sort" 6 "sync" 7 8 "github.com/neatio-net/neatio/utilities/event" 9 ) 10 11 type Manager struct { 12 backends map[reflect.Type][]Backend 13 updaters []event.Subscription 14 updates chan WalletEvent 15 wallets []Wallet 16 17 feed event.Feed 18 19 quit chan chan error 20 lock sync.RWMutex 21 } 22 23 func NewManager(backends ...Backend) *Manager { 24 25 var wallets []Wallet 26 for _, backend := range backends { 27 wallets = merge(wallets, backend.Wallets()...) 28 } 29 30 updates := make(chan WalletEvent, 4*len(backends)) 31 32 subs := make([]event.Subscription, len(backends)) 33 for i, backend := range backends { 34 subs[i] = backend.Subscribe(updates) 35 } 36 37 am := &Manager{ 38 backends: make(map[reflect.Type][]Backend), 39 updaters: subs, 40 updates: updates, 41 wallets: wallets, 42 quit: make(chan chan error), 43 } 44 for _, backend := range backends { 45 kind := reflect.TypeOf(backend) 46 am.backends[kind] = append(am.backends[kind], backend) 47 } 48 go am.update() 49 50 return am 51 } 52 53 func (am *Manager) Close() error { 54 errc := make(chan error) 55 am.quit <- errc 56 return <-errc 57 } 58 59 func (am *Manager) update() { 60 61 defer func() { 62 am.lock.Lock() 63 for _, sub := range am.updaters { 64 sub.Unsubscribe() 65 } 66 am.updaters = nil 67 am.lock.Unlock() 68 }() 69 70 for { 71 select { 72 case event := <-am.updates: 73 74 am.lock.Lock() 75 switch event.Kind { 76 case WalletArrived: 77 am.wallets = merge(am.wallets, event.Wallet) 78 case WalletDropped: 79 am.wallets = drop(am.wallets, event.Wallet) 80 } 81 am.lock.Unlock() 82 83 am.feed.Send(event) 84 85 case errc := <-am.quit: 86 87 errc <- nil 88 return 89 } 90 } 91 } 92 93 func (am *Manager) Backends(kind reflect.Type) []Backend { 94 return am.backends[kind] 95 } 96 97 func (am *Manager) Wallets() []Wallet { 98 am.lock.RLock() 99 defer am.lock.RUnlock() 100 101 cpy := make([]Wallet, len(am.wallets)) 102 copy(cpy, am.wallets) 103 return cpy 104 } 105 106 func (am *Manager) Wallet(url string) (Wallet, error) { 107 am.lock.RLock() 108 defer am.lock.RUnlock() 109 110 parsed, err := parseURL(url) 111 if err != nil { 112 return nil, err 113 } 114 for _, wallet := range am.Wallets() { 115 if wallet.URL() == parsed { 116 return wallet, nil 117 } 118 } 119 return nil, ErrUnknownWallet 120 } 121 122 func (am *Manager) Find(account Account) (Wallet, error) { 123 am.lock.RLock() 124 defer am.lock.RUnlock() 125 126 for _, wallet := range am.wallets { 127 if wallet.Contains(account) { 128 return wallet, nil 129 } 130 } 131 return nil, ErrUnknownAccount 132 } 133 134 func (am *Manager) Subscribe(sink chan<- WalletEvent) event.Subscription { 135 return am.feed.Subscribe(sink) 136 } 137 138 func merge(slice []Wallet, wallets ...Wallet) []Wallet { 139 for _, wallet := range wallets { 140 n := sort.Search(len(slice), func(i int) bool { return slice[i].URL().Cmp(wallet.URL()) >= 0 }) 141 if n == len(slice) { 142 slice = append(slice, wallet) 143 continue 144 } 145 slice = append(slice[:n], append([]Wallet{wallet}, slice[n:]...)...) 146 } 147 return slice 148 } 149 150 func drop(slice []Wallet, wallets ...Wallet) []Wallet { 151 for _, wallet := range wallets { 152 n := sort.Search(len(slice), func(i int) bool { return slice[i].URL().Cmp(wallet.URL()) >= 0 }) 153 if n == len(slice) { 154 155 continue 156 } 157 slice = append(slice[:n], slice[n+1:]...) 158 } 159 return slice 160 }