github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/jsonrpc/storage.go (about) 1 package jsonrpc 2 3 import ( 4 "errors" 5 "fmt" 6 "sync" 7 "time" 8 9 "github.com/0xPolygon/supernets2-node/hex" 10 "github.com/google/uuid" 11 "github.com/gorilla/websocket" 12 ) 13 14 // ErrNotFound represent a not found error. 15 var ErrNotFound = errors.New("object not found") 16 17 // ErrFilterInvalidPayload indicates there is an invalid payload when creating a filter 18 var ErrFilterInvalidPayload = errors.New("invalid argument 0: cannot specify both BlockHash and FromBlock/ToBlock, choose one or the other") 19 20 // Storage uses memory to store the data 21 // related to the json rpc server 22 type Storage struct { 23 filters sync.Map 24 } 25 26 // NewStorage creates and initializes an instance of Storage 27 func NewStorage() *Storage { 28 return &Storage{ 29 filters: sync.Map{}, 30 } 31 } 32 33 // NewLogFilter persists a new log filter 34 func (s *Storage) NewLogFilter(wsConn *websocket.Conn, filter LogFilter) (string, error) { 35 if filter.BlockHash != nil && (filter.FromBlock != nil || filter.ToBlock != nil) { 36 return "", ErrFilterInvalidPayload 37 } 38 39 return s.createFilter(FilterTypeLog, filter, wsConn) 40 } 41 42 // NewBlockFilter persists a new block log filter 43 func (s *Storage) NewBlockFilter(wsConn *websocket.Conn) (string, error) { 44 return s.createFilter(FilterTypeBlock, nil, wsConn) 45 } 46 47 // NewPendingTransactionFilter persists a new pending transaction filter 48 func (s *Storage) NewPendingTransactionFilter(wsConn *websocket.Conn) (string, error) { 49 return s.createFilter(FilterTypePendingTx, nil, wsConn) 50 } 51 52 // create persists the filter to the memory and provides the filter id 53 func (s *Storage) createFilter(t FilterType, parameters interface{}, wsConn *websocket.Conn) (string, error) { 54 lastPoll := time.Now().UTC() 55 id, err := s.generateFilterID() 56 if err != nil { 57 return "", fmt.Errorf("failed to generate filter ID: %w", err) 58 } 59 s.filters.Store(id, &Filter{ 60 ID: id, 61 Type: t, 62 Parameters: parameters, 63 LastPoll: lastPoll, 64 WsConn: wsConn, 65 }) 66 67 return id, nil 68 } 69 70 func (s *Storage) generateFilterID() (string, error) { 71 r, err := uuid.NewRandom() 72 if err != nil { 73 return "", err 74 } 75 76 b, err := r.MarshalBinary() 77 if err != nil { 78 return "", err 79 } 80 81 id := hex.EncodeToHex(b) 82 return id, nil 83 } 84 85 // GetAllBlockFiltersWithWSConn returns an array with all filter that have 86 // a web socket connection and are filtering by new blocks 87 func (s *Storage) GetAllBlockFiltersWithWSConn() ([]*Filter, error) { 88 filtersWithWSConn := []*Filter{} 89 s.filters.Range(func(key, value any) bool { 90 filter := value.(*Filter) 91 if filter.WsConn == nil || filter.Type != FilterTypeBlock { 92 return true 93 } 94 95 f := filter 96 filtersWithWSConn = append(filtersWithWSConn, f) 97 return true 98 }) 99 100 return filtersWithWSConn, nil 101 } 102 103 // GetAllLogFiltersWithWSConn returns an array with all filter that have 104 // a web socket connection and are filtering by new logs 105 func (s *Storage) GetAllLogFiltersWithWSConn() ([]*Filter, error) { 106 filtersWithWSConn := []*Filter{} 107 s.filters.Range(func(key, value any) bool { 108 filter := value.(*Filter) 109 if filter.WsConn == nil || filter.Type != FilterTypeLog { 110 return true 111 } 112 113 f := filter 114 filtersWithWSConn = append(filtersWithWSConn, f) 115 return true 116 }) 117 118 return filtersWithWSConn, nil 119 } 120 121 // GetFilter gets a filter by its id 122 func (s *Storage) GetFilter(filterID string) (*Filter, error) { 123 filter, found := s.filters.Load(filterID) 124 if !found { 125 return nil, ErrNotFound 126 } 127 128 return filter.(*Filter), nil 129 } 130 131 // UpdateFilterLastPoll updates the last poll to now 132 func (s *Storage) UpdateFilterLastPoll(filterID string) error { 133 filterValue, found := s.filters.Load(filterID) 134 if !found { 135 return ErrNotFound 136 } 137 filter := filterValue.(*Filter) 138 filter.LastPoll = time.Now().UTC() 139 s.filters.Store(filterID, filter) 140 return nil 141 } 142 143 // UninstallFilter deletes a filter by its id 144 func (s *Storage) UninstallFilter(filterID string) error { 145 _, found := s.filters.Load(filterID) 146 if !found { 147 return ErrNotFound 148 } 149 s.filters.Delete(filterID) 150 return nil 151 } 152 153 // UninstallFilterByWSConn deletes all filters connected to the provided web socket connection 154 func (s *Storage) UninstallFilterByWSConn(wsConn *websocket.Conn) error { 155 filterIDsToDelete := []string{} 156 s.filters.Range(func(key, value any) bool { 157 id := key.(string) 158 filter := value.(*Filter) 159 if filter.WsConn == wsConn { 160 filterIDsToDelete = append(filterIDsToDelete, id) 161 } 162 return true 163 }) 164 165 for _, filterID := range filterIDsToDelete { 166 s.filters.Delete(filterID) 167 } 168 169 return nil 170 }