github.com/diadata-org/diadata@v1.4.593/pkg/model/supplies.go (about) 1 package models 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "strconv" 8 "time" 9 10 "github.com/diadata-org/diadata/pkg/dia" 11 "github.com/diadata-org/diadata/pkg/dia/helpers" 12 "github.com/go-redis/redis" 13 clientInfluxdb "github.com/influxdata/influxdb1-client/v2" 14 ) 15 16 func getKeySupply(asset dia.Asset) string { 17 return "dia_supply_" + asset.Blockchain + "_" + asset.Address 18 } 19 20 func getKeyDiaTotalSupply() string { 21 return "dia_diaTotalSupply" 22 } 23 24 func getKeyDiaCirculatingSupply() string { 25 return "dia_diaCirculatingSupply" 26 } 27 28 func (datastore *DB) SaveSupplyInflux(supply *dia.Supply) error { 29 fields := map[string]interface{}{ 30 "supply": supply.Supply, 31 "circulatingsupply": supply.CirculatingSupply, 32 "source": supply.Source, 33 } 34 tags := map[string]string{ 35 "symbol": EscapeReplacer.Replace(supply.Asset.Symbol), 36 "name": EscapeReplacer.Replace(supply.Asset.Name), 37 "address": supply.Asset.Address, 38 "blockchain": supply.Asset.Blockchain, 39 } 40 pt, err := clientInfluxdb.NewPoint(influxDbSupplyTable, tags, fields, supply.Time) 41 if err != nil { 42 log.Errorln("NewSupplyInflux:", err) 43 } else { 44 datastore.addPoint(pt) 45 } 46 47 err = datastore.WriteBatchInflux() 48 if err != nil { 49 log.Errorln("SaveSupplyInflux", err) 50 } 51 52 return err 53 } 54 55 // GetSupplyInflux returns supply and circulating supply of @asset. Needs asset.Address and asset.Blockchain. 56 // If no time range is given it returns the latest supply. 57 func (datastore *DB) GetSupplyInflux(asset dia.Asset, starttime time.Time, endtime time.Time) ([]dia.Supply, error) { 58 retval := []dia.Supply{} 59 var q string 60 if starttime.IsZero() || endtime.IsZero() { 61 queryString := "SELECT supply,circulatingsupply,source,\"name\",\"symbol\" FROM %s WHERE \"address\" = '%s' AND \"blockchain\"='%s' AND time<now() ORDER BY DESC LIMIT 1" 62 q = fmt.Sprintf(queryString, influxDbSupplyTable, asset.Address, asset.Blockchain) 63 } else { 64 queryString := "SELECT supply,circulatingsupply,source,\"name\",\"symbol\" FROM %s WHERE time > %d AND time < %d AND \"address\" = '%s' AND \"blockchain\"='%s' ORDER BY DESC" 65 q = fmt.Sprintf(queryString, influxDbSupplyTable, starttime.UnixNano(), endtime.UnixNano(), asset.Address, asset.Blockchain) 66 } 67 res, err := queryInfluxDB(datastore.influxClient, q) 68 if err != nil { 69 return retval, err 70 } 71 if len(res) > 0 && len(res[0].Series) > 0 { 72 for i := 0; i < len(res[0].Series[0].Values); i++ { 73 currentSupply := dia.Supply{Asset: asset} 74 if res[0].Series[0].Values[i][0] != nil { 75 currentSupply.Time, err = time.Parse(time.RFC3339, res[0].Series[0].Values[i][0].(string)) 76 if err != nil { 77 return retval, err 78 } 79 } 80 currentSupply.Supply, err = res[0].Series[0].Values[i][1].(json.Number).Float64() 81 if err != nil { 82 return retval, err 83 } 84 currentSupply.CirculatingSupply, err = res[0].Series[0].Values[i][2].(json.Number).Float64() 85 if err != nil { 86 return retval, err 87 } 88 if res[0].Series[0].Values[i][3] != nil { 89 currentSupply.Source = res[0].Series[0].Values[i][3].(string) 90 if err != nil { 91 return retval, err 92 } 93 } 94 if res[0].Series[0].Values[i][4] != nil { 95 currentSupply.Asset.Name = res[0].Series[0].Values[i][4].(string) 96 if err != nil { 97 log.Error("error getting symbol name from influx: ", err) 98 } 99 } 100 if res[0].Series[0].Values[i][5] != nil { 101 currentSupply.Asset.Symbol = res[0].Series[0].Values[i][5].(string) 102 if err != nil { 103 log.Error("error getting symbol name from influx: ", err) 104 } 105 } 106 retval = append(retval, currentSupply) 107 } 108 } else { 109 return retval, errors.New("parsing supply value from database") 110 } 111 return retval, nil 112 } 113 114 func (datastore *DB) GetLatestSupply(symbol string, relDB *RelDB) (*dia.Supply, error) { 115 val, err := datastore.GetSupply(symbol, time.Time{}, time.Time{}, relDB) 116 if err != nil { 117 log.Error(err) 118 return &dia.Supply{}, err 119 } 120 return &val[0], err 121 } 122 123 func (datastore *DB) GetSupply(symbol string, starttime, endtime time.Time, relDB *RelDB) ([]dia.Supply, error) { 124 125 // First get asset with @symbol with largest market cap. 126 topAsset, err := relDB.GetTopAssetByVolume(symbol) 127 if err != nil || len(topAsset) < 1 { 128 log.Error(err) 129 return []dia.Supply{}, err 130 } 131 132 switch symbol { 133 case "MIOTA": 134 retArray := []dia.Supply{} 135 s := dia.Supply{ 136 Asset: dia.Asset{Name: helpers.NameForSymbol("MIOTA"), Symbol: "MIOTA"}, 137 CirculatingSupply: 2779530283.0, 138 Time: time.Now(), 139 Source: dia.Diadata, 140 } 141 retArray = append(retArray, s) 142 return retArray, nil 143 default: 144 value, err := datastore.GetSupplyInflux(topAsset[0], starttime, endtime) 145 if err != nil { 146 log.Errorf("Error: %v on GetSupply %v\n", err, symbol) 147 return []dia.Supply{}, err 148 } 149 return value, err 150 } 151 } 152 153 func (datastore *DB) GetSupplyCache(asset dia.Asset) (supply dia.Supply, err error) { 154 err = datastore.redisClient.Get(getKeySupply(asset)).Scan(&supply) 155 if err != nil { 156 return 157 } 158 return supply, nil 159 } 160 161 func (datastore *DB) SetSupply(supply *dia.Supply) error { 162 key := getKeySupply(supply.Asset) 163 log.Debug("setting ", key, supply) 164 err := datastore.redisClient.Set(key, supply, 0).Err() 165 if err != nil { 166 log.Errorf("Error: %v on SetSupply (redis) %v\n", err, supply.Asset.Symbol) 167 } 168 err = datastore.SaveSupplyInflux(supply) 169 if err != nil { 170 log.Errorf("Error: %v on SetSupply (influx) %v\n", err, supply.Asset.Symbol) 171 } 172 return err 173 } 174 175 func (db *DB) SetDiaTotalSupply(totalSupply float64) error { 176 key := getKeyDiaTotalSupply() 177 log.Debug("setting ", key, totalSupply) 178 179 err := db.redisClient.Set(key, totalSupply, 0).Err() 180 if err != nil { 181 log.Errorf("Error: %v on SetDiaTotalSupply (redis) %v\n", err, totalSupply) 182 } 183 return err 184 } 185 186 func (db *DB) GetDiaTotalSupply() (float64, error) { 187 key := getKeyDiaTotalSupply() 188 value, err := db.redisClient.Get(key).Result() 189 if err != nil { 190 if err != redis.Nil { 191 log.Errorf("Error: %v on GetDiaTotalSupply\n", err) 192 } 193 return 0.0, err 194 } 195 retval, err := strconv.ParseFloat(value, 64) 196 if err != nil { 197 log.Error("Cannot convert to float in GetDiaTotalSupply") 198 return 0.0, err 199 } 200 return retval, nil 201 } 202 203 func (db *DB) SetDiaCirculatingSupply(circulatingSupply float64) error { 204 key := getKeyDiaCirculatingSupply() 205 log.Debug("setting ", key, circulatingSupply) 206 207 err := db.redisClient.Set(key, circulatingSupply, 0).Err() 208 if err != nil { 209 log.Errorf("Error: %v on SetDiaCirculatingSupply (redis) %v\n", err, circulatingSupply) 210 } 211 return err 212 } 213 214 func (db *DB) GetDiaCirculatingSupply() (float64, error) { 215 key := getKeyDiaCirculatingSupply() 216 value, err := db.redisClient.Get(key).Result() 217 if err != nil { 218 if err != redis.Nil { 219 log.Errorf("Error: %v on GetDiaCirculatingSupply\n", err) 220 } 221 return 0.0, err 222 } 223 retval, err := strconv.ParseFloat(value, 64) 224 if err != nil { 225 log.Error("Cannot convert to float in GetDiaCirculatingSupply") 226 return 0.0, err 227 } 228 return retval, nil 229 }