From e5e64a1b363294ac31422129d8fd4e7de7a751e0 Mon Sep 17 00:00:00 2001 From: Yuansi Hu Date: Tue, 5 Dec 2017 16:45:18 +0800 Subject: [PATCH] Add monitor API /api/stats to expose information: Total BTC received and Total SKY sent. --- src/exchange/deposit.go | 5 +++++ src/exchange/exchange.go | 12 ++++++++++++ src/exchange/store.go | 26 ++++++++++++++++++++++++++ src/exchange/store_test.go | 5 +++++ src/monitor/monitor.go | 32 +++++++++++++++++++++++++++++++- src/monitor/monitor_test.go | 16 ++++++++++++++++ 6 files changed, 95 insertions(+), 1 deletion(-) diff --git a/src/exchange/deposit.go b/src/exchange/deposit.go index a4b3f1e9..3b5f5c31 100644 --- a/src/exchange/deposit.go +++ b/src/exchange/deposit.go @@ -73,6 +73,11 @@ type DepositInfo struct { Deposit scanner.Deposit } +type DepositStats struct { + TotalBTCReceived int64 `json:"total_btc_received"` + TotalSKYSent int64 `json:"total_sky_sent"` +} + // ValidateForStatus does a consistency check of the data based upon the Status value func (di DepositInfo) ValidateForStatus() error { diff --git a/src/exchange/exchange.go b/src/exchange/exchange.go index a86f9cfb..18e2e42e 100644 --- a/src/exchange/exchange.go +++ b/src/exchange/exchange.go @@ -48,6 +48,7 @@ type Exchanger interface { GetDepositStatuses(skyAddr string) ([]DepositStatus, error) GetDepositStatusDetail(flt DepositFilter) ([]DepositStatusDetail, error) GetBindNum(skyAddr string) (int, error) + GetDepositStats() (*DepositStats, error) } // Exchange manages coin exchange between deposits and skycoin @@ -626,3 +627,14 @@ func (s *Exchange) GetBindNum(skyAddr string) (int, error) { addrs, err := s.store.GetSkyBindBtcAddresses(skyAddr) return len(addrs), err } + +func (s *Exchange) GetDepositStats() (stats *DepositStats, err error) { + tbr, tss, err := s.store.GetDepositStats() + if err != nil { + return nil, err + } + return &DepositStats{ + TotalBTCReceived: tbr, + TotalSKYSent: tss, + }, nil +} diff --git a/src/exchange/store.go b/src/exchange/store.go index ddbf84ff..182b686c 100644 --- a/src/exchange/store.go +++ b/src/exchange/store.go @@ -44,6 +44,7 @@ type Storer interface { UpdateDepositInfo(string, func(DepositInfo) DepositInfo) (DepositInfo, error) UpdateDepositInfoCallback(string, func(DepositInfo) DepositInfo, func(DepositInfo) error) (DepositInfo, error) GetSkyBindBtcAddresses(string) ([]string, error) + GetDepositStats() (int64, int64, error) } // Store storage for exchange @@ -473,3 +474,28 @@ func (s *Store) getSkyBindBtcAddressesTx(tx *bolt.Tx, skyAddr string) ([]string, return addrs, nil } + +func (s *Store) GetDepositStats() (int64, int64, error) { + var totalBTCReceived int64 + var totalSKYSent int64 + + if err := s.db.View(func(tx *bolt.Tx) error { + return dbutil.ForEach(tx, depositInfoBkt, func(k, v []byte) error { + var dpi DepositInfo + if err := json.Unmarshal(v, &dpi); err != nil { + return err + } + + if dpi.CoinType == scanner.CoinTypeBTC { + totalBTCReceived += dpi.DepositValue + } + totalSKYSent += int64(dpi.SkySent) + + return nil + }) + }); err != nil { + return -1, -1, err + } + + return totalBTCReceived, totalSKYSent, nil +} diff --git a/src/exchange/store_test.go b/src/exchange/store_test.go index 038f4d70..1d934c33 100644 --- a/src/exchange/store_test.go +++ b/src/exchange/store_test.go @@ -74,6 +74,11 @@ func (m *MockStore) GetSkyBindBtcAddresses(skyAddr string) ([]string, error) { return btcAddrs.([]string), args.Error(1) } +func (m *MockStore) GetDepositStats() (int64, int64, error) { + args := m.Called() + return args.Get(0).(int64), args.Get(1).(int64), args.Error(2) +} + func newTestStore(t *testing.T) (*Store, func()) { db, shutdown := testutil.PrepareDB(t) diff --git a/src/monitor/monitor.go b/src/monitor/monitor.go index 4e83fed4..c4acd60c 100644 --- a/src/monitor/monitor.go +++ b/src/monitor/monitor.go @@ -34,6 +34,7 @@ type AddrManager interface { // DepositStatusGetter interface provides api to access exchange resource type DepositStatusGetter interface { GetDepositStatusDetail(flt exchange.DepositFilter) ([]exchange.DepositStatusDetail, error) + GetDepositStats() (*exchange.DepositStats, error) } // ScanAddressGetter get scanning address interface @@ -101,6 +102,7 @@ func (m *Monitor) setupMux() *http.ServeMux { mux.Handle("/api/address", httputil.LogHandler(m.log, m.addressHandler())) mux.Handle("/api/deposit_status", httputil.LogHandler(m.log, m.depositStatus())) + mux.Handle("/api/stats", httputil.LogHandler(m.log, m.statsHandler())) return mux } @@ -158,7 +160,7 @@ func (m *Monitor) addressHandler() http.HandlerFunc { } } -// depostStatus returns all deposit status +// depositStatus returns all deposit status // Method: GET // URI: /api/deposit_status // Args: @@ -210,3 +212,31 @@ func (m *Monitor) depositStatus() http.HandlerFunc { } } } + +// stats returns all deposit stats, including total BTC received and total SKY sent. +// Method: GET +// URI: /api/stats +func (m *Monitor) statsHandler() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + log := logger.FromContext(ctx) + + if r.Method != http.MethodGet { + w.Header().Set("Allow", http.MethodGet) + httputil.ErrResponse(w, http.StatusMethodNotAllowed) + return + } + + ts, err := m.GetDepositStats() + if err != nil { + log.WithError(err).Error("GetDepositStats failed") + httputil.ErrResponse(w, http.StatusInternalServerError) + return + } + + if err := httputil.JSONResponse(w, ts); err != nil { + log.WithError(err).Error("Write json response failed") + return + } + } +} diff --git a/src/monitor/monitor_test.go b/src/monitor/monitor_test.go index 3858b6af..eadb5320 100644 --- a/src/monitor/monitor_test.go +++ b/src/monitor/monitor_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "github.com/skycoin/teller/src/exchange" + "github.com/skycoin/teller/src/scanner" "github.com/skycoin/teller/src/util/testutil" ) @@ -43,6 +44,21 @@ func (dps dummyDepositStatusGetter) GetDepositStatusDetail(flt exchange.DepositF return ds, nil } +func (dps dummyDepositStatusGetter) GetDepositStats() (*exchange.DepositStats, error) { + var totalBTCReceived int64 + var totalSKYSent int64 + for _, dpi := range dps.dpis { + if dpi.CoinType == scanner.CoinTypeBTC { + totalBTCReceived += dpi.DepositValue + } + totalSKYSent += int64(dpi.SkySent) + } + return &exchange.DepositStats{ + TotalBTCReceived: totalBTCReceived, + TotalSKYSent: totalSKYSent, + }, nil +} + type dummyScanAddrs struct { addrs []string }