Files
gocryptotrader/exchange/accounts/store.go
Gareth Kirwan 73e200e4e7 accounts: Move to instance methods, fix races and isolate tests (#1923)
* Bybit: Fix race in TestUpdateAccountInfo and  TestWSHandleData

* DriveBy rename TestWSHandleData
* This doesn't address running with -race=2+ due to the singleton

* Accounts: Add account.GetService()

* exchange: Assertify TestSetupDefaults

* Exchanges: Add account.Service override for testing

* Exchanges: Remove duplicate IsWebsocketEnabled test from TestSetupDefaults

* Dispatch: Replace nil checks with NilGuard

* Engine: Remove deprecated printAccountHoldingsChangeSummary

* Dispatcher: Add EnsureRunning method

* Accounts: Move singleton accounts service to exchange Accounts

* Move singleton accounts service to exchange Accounts

This maintains the concept of a global store, whilst allowing exchanges
to override it when needed, particularly for testing.

APIServer:

* Remove getAllActiveAccounts from apiserver

Deprecated apiserver only thing using this, so remove it instead of
updating it

* Update comment for UpdateAccountBalances everywhere

* Docs: Add punctuation to function comments

* Bybit: Coverage for wsProcessWalletPushData Save
2025-10-28 13:52:45 +11:00

66 lines
1.4 KiB
Go

package accounts
import (
"context"
"sync"
"sync/atomic"
"github.com/thrasher-corp/gocryptotrader/dispatch"
)
// Store contains accounts for exchanges.
type Store struct {
exchangeAccounts exchangeMap
mu sync.Mutex
mux *dispatch.Mux
}
type exchangeMap map[exchange]*Accounts
type exchange interface {
GetName() string
GetCredentials(context.Context) (*Credentials, error)
}
type exchangeWrapper interface {
GetBase() exchange
}
var global atomic.Pointer[Store]
// NewStore returns a new store with the default global dispatcher mux.
func NewStore() *Store {
return &Store{
exchangeAccounts: make(exchangeMap),
mux: dispatch.GetNewMux(nil),
}
}
// GetStore returns the singleton accounts store for global use; Initialising if necessary.
func GetStore() *Store {
if s := global.Load(); s != nil {
return s
}
_ = global.CompareAndSwap(nil, NewStore())
return global.Load()
}
// GetExchangeAccounts returns accounts for a specific exchange.
func (s *Store) GetExchangeAccounts(e exchange) (a *Accounts, err error) {
s.mu.Lock()
defer s.mu.Unlock()
if w, ok := e.(exchangeWrapper); ok {
// Because SetupDefaults is called on Base, it's easiest to just use the Base pointer as the key
e = w.GetBase()
}
a, ok := s.exchangeAccounts[e]
if !ok {
a, err = NewAccounts(e, s.mux)
if err != nil {
return nil, err
}
s.exchangeAccounts[e] = a
}
return a, nil
}