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  }