code.vegaprotocol.io/vega@v0.79.0/datanode/candlesv2/service.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package candlesv2 17 18 import ( 19 "context" 20 "fmt" 21 "sync" 22 "time" 23 24 "code.vegaprotocol.io/vega/datanode/entities" 25 "code.vegaprotocol.io/vega/logging" 26 ) 27 28 // CandleStore ... 29 // 30 //go:generate go run github.com/golang/mock/mockgen -destination mocks/candle_store_mock.go -package mocks code.vegaprotocol.io/vega/datanode/candlesv2 CandleStore 31 type CandleStore interface { 32 GetCandleDataForTimeSpan(ctx context.Context, candleID string, from *time.Time, to *time.Time, 33 p entities.CursorPagination) ([]entities.Candle, entities.PageInfo, error) 34 GetCandlesForMarket(ctx context.Context, market string) (map[string]string, error) 35 CandleExists(ctx context.Context, candleID string) (bool, error) 36 GetCandleIDForIntervalAndMarket(ctx context.Context, interval string, market string) (bool, string, error) 37 } 38 39 type Svc struct { 40 Config 41 CandleStore 42 ctx context.Context 43 log *logging.Logger 44 45 candleIDToUpdatesStream map[string]*CandleUpdates 46 subscriptionIDToCandleID map[string]string 47 updatesSubscriptionMutex sync.Mutex 48 } 49 50 func NewService(ctx context.Context, log *logging.Logger, config Config, candleStore CandleStore) *Svc { 51 log = log.Named(namedLogger) 52 log.SetLevel(config.Level.Get()) 53 54 return &Svc{ 55 ctx: ctx, 56 log: log, 57 Config: config, 58 CandleStore: candleStore, 59 candleIDToUpdatesStream: map[string]*CandleUpdates{}, 60 subscriptionIDToCandleID: map[string]string{}, 61 } 62 } 63 64 // Subscribe to a channel of new or updated candles. The subscriber id will must be retained for future reference and to Unsubscribe. 65 func (cs *Svc) Subscribe(ctx context.Context, candleID string) (string, <-chan entities.Candle, error) { 66 cs.updatesSubscriptionMutex.Lock() 67 defer cs.updatesSubscriptionMutex.Unlock() 68 69 exists, err := cs.CandleExists(ctx, candleID) 70 if err != nil { 71 return "", nil, fmt.Errorf("subscribing to candles:%w", err) 72 } 73 74 if !exists { 75 return "", nil, fmt.Errorf("no candle exists for candle id:%s", candleID) 76 } 77 78 if _, ok := cs.candleIDToUpdatesStream[candleID]; !ok { 79 updates := NewCandleUpdates(cs.ctx, cs.log, candleID, cs, cs.Config.CandleUpdates) 80 cs.candleIDToUpdatesStream[candleID] = updates 81 } 82 83 updatesStream := cs.candleIDToUpdatesStream[candleID] 84 subscriptionID, out, err := updatesStream.Subscribe() 85 if err != nil { 86 return "", nil, fmt.Errorf("failed to subscribe to candle %s: %w", candleID, err) 87 } 88 89 cs.subscriptionIDToCandleID[subscriptionID] = candleID 90 91 return subscriptionID, out, nil 92 } 93 94 func (cs *Svc) Unsubscribe(subscriptionID string) error { 95 cs.updatesSubscriptionMutex.Lock() 96 defer cs.updatesSubscriptionMutex.Unlock() 97 98 if candleID, ok := cs.subscriptionIDToCandleID[subscriptionID]; ok { 99 updatesStream := cs.candleIDToUpdatesStream[candleID] 100 err := updatesStream.Unsubscribe(subscriptionID) 101 if err != nil { 102 return fmt.Errorf("failed to unsubscribe from candle %s: %w", candleID, err) 103 } 104 return nil 105 } 106 return fmt.Errorf("no subscription found for id %s", subscriptionID) 107 }