Compare commits
3 Commits
b4598ce495
...
42e2a23e26
Author | SHA1 | Date |
---|---|---|
Massaki Archambault | 42e2a23e26 | |
Massaki Archambault | 592fbea0e6 | |
Massaki Archambault | 20eddb8fc3 |
328
exporter.go
328
exporter.go
|
@ -5,8 +5,10 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/helium-blockchain-exporter/heliumapi"
|
||||
|
@ -46,6 +48,13 @@ type Account struct {
|
|||
Tx AccountTx
|
||||
}
|
||||
|
||||
type AccountTx struct {
|
||||
DepositTotal int
|
||||
WithdrawalTotal int
|
||||
LastUpdate time.Time
|
||||
UpdateLock sync.Mutex
|
||||
}
|
||||
|
||||
func NewAccount(address string) Account {
|
||||
return Account{
|
||||
Address: address,
|
||||
|
@ -57,12 +66,6 @@ func NewAccount(address string) Account {
|
|||
}
|
||||
}
|
||||
|
||||
type AccountTx struct {
|
||||
DepositTotal int
|
||||
WithdrawalTotal int
|
||||
LastUpdate time.Time
|
||||
}
|
||||
|
||||
const (
|
||||
namespace = "helium"
|
||||
)
|
||||
|
@ -317,16 +320,27 @@ func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
|
|||
// Collect fetches the data from the helium blockchain api and delivers them as Prometheus metrics.
|
||||
// implements prometheus.Collector.
|
||||
func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
|
||||
e.collectOracleMetrics(ch)
|
||||
e.collectStatsMetrics(ch)
|
||||
wg := new(sync.WaitGroup)
|
||||
|
||||
wg.Add(2)
|
||||
go e.collectOracleMetrics(wg, ch)
|
||||
e.collectStatsMetrics(wg, ch)
|
||||
for i := range e.Accounts {
|
||||
e.collectAccountMetrics(ch, &e.Accounts[i])
|
||||
e.collectHotspotMetrics(ch, &e.Accounts[i])
|
||||
wg.Add(5)
|
||||
go e.collectAccountMetrics(wg, ch, &e.Accounts[i])
|
||||
go e.collectAccountActivityMetrics(wg, ch, &e.Accounts[i])
|
||||
go e.collectAccountRewardsTotalMetrics(wg, ch, &e.Accounts[i])
|
||||
go e.collectAccountTransactionsMetrics(wg, ch, &e.Accounts[i])
|
||||
|
||||
go e.collectHotspotMetrics(wg, ch, &e.Accounts[i])
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// collectOracleMetrics collect metrics in the oracle group from the helium api
|
||||
func (e *Exporter) collectOracleMetrics(ch chan<- prometheus.Metric) {
|
||||
func (e *Exporter) collectOracleMetrics(wg *sync.WaitGroup, ch chan<- prometheus.Metric) {
|
||||
defer wg.Done()
|
||||
|
||||
currentOraclePrice, err := heliumapi.GetCurrentOraclePrice()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
|
@ -334,12 +348,14 @@ func (e *Exporter) collectOracleMetrics(ch chan<- prometheus.Metric) {
|
|||
}
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
oraclePrice.Desc, oraclePrice.Type, float64(currentOraclePrice.Data.Price)/100000000,
|
||||
oraclePrice.Desc, oraclePrice.Type, float64(currentOraclePrice.Price)/100000000,
|
||||
)
|
||||
}
|
||||
|
||||
// collectStatsMetrics collect metrics in the stats group from the helium api
|
||||
func (e *Exporter) collectStatsMetrics(ch chan<- prometheus.Metric) {
|
||||
func (e *Exporter) collectStatsMetrics(wg *sync.WaitGroup, ch chan<- prometheus.Metric) {
|
||||
defer wg.Done()
|
||||
|
||||
blockchainStats, err := heliumapi.GetBlockchainStats()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
|
@ -347,98 +363,188 @@ func (e *Exporter) collectStatsMetrics(ch chan<- prometheus.Metric) {
|
|||
}
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
statsValidators.Desc, statsValidators.Type, float64(blockchainStats.Data.Counts.Validators),
|
||||
statsValidators.Desc, statsValidators.Type, float64(blockchainStats.Counts.Validators),
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
statsOuis.Desc, statsOuis.Type, float64(blockchainStats.Data.Counts.Ouis),
|
||||
statsOuis.Desc, statsOuis.Type, float64(blockchainStats.Counts.Ouis),
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
statsHotspotsDataOnly.Desc, statsHotspotsDataOnly.Type, float64(blockchainStats.Data.Counts.HotspotsDataonly),
|
||||
statsHotspotsDataOnly.Desc, statsHotspotsDataOnly.Type, float64(blockchainStats.Counts.HotspotsDataonly),
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
statsBlocks.Desc, statsBlocks.Type, float64(blockchainStats.Data.Counts.Blocks),
|
||||
statsBlocks.Desc, statsBlocks.Type, float64(blockchainStats.Counts.Blocks),
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
statsChallenges.Desc, statsChallenges.Type, float64(blockchainStats.Data.Counts.Challenges),
|
||||
statsChallenges.Desc, statsChallenges.Type, float64(blockchainStats.Counts.Challenges),
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
statsCities.Desc, statsCities.Type, float64(blockchainStats.Data.Counts.Cities),
|
||||
statsCities.Desc, statsCities.Type, float64(blockchainStats.Counts.Cities),
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
statsConsensusGroups.Desc, statsConsensusGroups.Type, float64(blockchainStats.Data.Counts.ConsensusGroups),
|
||||
statsConsensusGroups.Desc, statsConsensusGroups.Type, float64(blockchainStats.Counts.ConsensusGroups),
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
statsCountries.Desc, statsCountries.Type, float64(blockchainStats.Data.Counts.Countries),
|
||||
statsCountries.Desc, statsCountries.Type, float64(blockchainStats.Counts.Countries),
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
statsHotspots.Desc, statsHotspots.Type, float64(blockchainStats.Data.Counts.Hotspots),
|
||||
statsHotspots.Desc, statsHotspots.Type, float64(blockchainStats.Counts.Hotspots),
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
statsTokenSupply.Desc, statsTokenSupply.Type, blockchainStats.Data.TokenSupply,
|
||||
statsTokenSupply.Desc, statsTokenSupply.Type, blockchainStats.TokenSupply,
|
||||
)
|
||||
}
|
||||
|
||||
// collectStatsMetrics collect metrics in the account group from the helium api
|
||||
func (e *Exporter) collectAccountMetrics(ch chan<- prometheus.Metric, account *Account) {
|
||||
func (e *Exporter) collectAccountMetrics(wg *sync.WaitGroup, ch chan<- prometheus.Metric, account *Account) {
|
||||
defer wg.Done()
|
||||
|
||||
accountForAddress, err := heliumapi.GetAccountForAddress(account.Address)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
accountBalanceHnt.Desc, accountBalanceHnt.Type, float64(accountForAddress.Balance),
|
||||
account.Address,
|
||||
)
|
||||
}
|
||||
|
||||
// collectAccountActivityMetrics collect the total number of activities executed by an account from the helium api
|
||||
func (e *Exporter) collectAccountActivityMetrics(wg *sync.WaitGroup, ch chan<- prometheus.Metric, account *Account) {
|
||||
defer wg.Done()
|
||||
|
||||
accountActivityForAddress, err := heliumapi.GetActivityCountsForAccount(account.Address)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
accountRewardTotalsForAddress, err := heliumapi.GetRewardTotalsForAccount(account.Address, &e.StartTime, nil)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
err = account.collectTransactionMetrics(ch)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
accountBalanceHnt.Desc, accountBalanceHnt.Type, float64(accountForAddress.Data.Balance),
|
||||
account.Address,
|
||||
)
|
||||
for accType, count := range accountActivityForAddress.Data {
|
||||
for accType, count := range *accountActivityForAddress {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
accountActivity.Desc, accountActivity.Type, float64(count),
|
||||
account.Address, accType,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// collectAccountRewardsTotalMetrics collect the total rewards accumulated by an account from the helium api
|
||||
func (e *Exporter) collectAccountRewardsTotalMetrics(wg *sync.WaitGroup, ch chan<- prometheus.Metric, account *Account) {
|
||||
defer wg.Done()
|
||||
|
||||
accountRewardTotalsForAddress, err := heliumapi.GetRewardTotalsForAccount(account.Address, &e.StartTime, nil)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
accountRewardsHnt.Desc, accountRewardsHnt.Type, accountRewardTotalsForAddress.Data.Sum,
|
||||
accountRewardsHnt.Desc, accountRewardsHnt.Type, accountRewardTotalsForAddress.Sum,
|
||||
account.Address,
|
||||
)
|
||||
}
|
||||
|
||||
// collectStatsMetrics collect metrics in the hotspot group from the helium api
|
||||
func (e *Exporter) collectHotspotMetrics(ch chan<- prometheus.Metric, account *Account) {
|
||||
// collectAccountTransactionsMetrics collect the total deposited/withdrawn by an account from the helium api
|
||||
func (e *Exporter) collectAccountTransactionsMetrics(wg *sync.WaitGroup, ch chan<- prometheus.Metric, account *Account) {
|
||||
defer wg.Done()
|
||||
|
||||
// we can only ever allow a single instance of the routine doing
|
||||
// calculations on the deposited and widthdrawn total
|
||||
account.Tx.UpdateLock.Lock()
|
||||
defer account.Tx.UpdateLock.Unlock()
|
||||
|
||||
now := time.Now()
|
||||
activities, err := heliumapi.GetActivityForAccount(account.Address, []string{}, &account.Tx.LastUpdate, &now)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// impl based on https://github.com/helium/hotspot-app/blob/918563fba84d1abf4554a43a4d42bb838d017bd3/src/features/wallet/root/useActivityItem.tsx#L336
|
||||
for _, activity := range activities.AddGatewayV1 {
|
||||
account.Tx.WithdrawalTotal += activity.StakingFee
|
||||
}
|
||||
for _, activity := range activities.AssertLocationV1 {
|
||||
account.Tx.WithdrawalTotal += activity.StakingFee
|
||||
}
|
||||
for _, activity := range activities.AssertLocationV2 {
|
||||
account.Tx.WithdrawalTotal += activity.StakingFee
|
||||
}
|
||||
for _, activity := range activities.PaymentV1 {
|
||||
if activity.Payer == account.Address {
|
||||
account.Tx.WithdrawalTotal += activity.Amount
|
||||
} else {
|
||||
account.Tx.DepositTotal += activity.Amount
|
||||
}
|
||||
}
|
||||
for _, activity := range activities.PaymentV2 {
|
||||
if activity.Payer == account.Address {
|
||||
paymentTotal := 0
|
||||
for _, payment := range activity.Payments {
|
||||
paymentTotal += payment.Amount
|
||||
}
|
||||
account.Tx.WithdrawalTotal += paymentTotal
|
||||
} else {
|
||||
for _, payment := range activity.Payments {
|
||||
if payment.Payee == account.Address {
|
||||
account.Tx.DepositTotal += payment.Amount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, activity := range activities.RewardsV1 {
|
||||
for _, reward := range activity.Rewards {
|
||||
account.Tx.DepositTotal += reward.Amount
|
||||
}
|
||||
}
|
||||
for _, activity := range activities.RewardsV2 {
|
||||
for _, reward := range activity.Rewards {
|
||||
account.Tx.DepositTotal += reward.Amount
|
||||
}
|
||||
}
|
||||
for _, activity := range activities.StakeValidatorV1 {
|
||||
account.Tx.WithdrawalTotal += activity.Stake
|
||||
}
|
||||
for _, activity := range activities.TokenBurnV1 {
|
||||
account.Tx.WithdrawalTotal += activity.Amount
|
||||
}
|
||||
for _, activity := range activities.TransferHotspotV1 {
|
||||
if activity.Buyer == account.Address {
|
||||
account.Tx.WithdrawalTotal += activity.AmountToSeller
|
||||
} else {
|
||||
account.Tx.DepositTotal += activity.AmountToSeller
|
||||
}
|
||||
}
|
||||
for _, activity := range activities.UnstakeValidatorV1 {
|
||||
account.Tx.WithdrawalTotal += activity.StakeAmount
|
||||
}
|
||||
account.Tx.LastUpdate = now
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
accountDepositsHnt.Desc, accountDepositsHnt.Type, float64(account.Tx.DepositTotal),
|
||||
account.Address,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
accountWithdrawalsHnt.Desc, accountWithdrawalsHnt.Type, float64(account.Tx.WithdrawalTotal),
|
||||
account.Address,
|
||||
)
|
||||
}
|
||||
|
||||
// collectStatsMetrics collect metrics of the hotspot of an account from the helium api
|
||||
func (e *Exporter) collectHotspotMetrics(wg *sync.WaitGroup, ch chan<- prometheus.Metric, account *Account) {
|
||||
defer wg.Done()
|
||||
|
||||
hotspotsForAddress, err := heliumapi.GetHotspotsForAccount(account.Address)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, hotspotData := range hotspotsForAddress.Data {
|
||||
hotspotActivityForAddress, err := heliumapi.GetHotspotActivityCount(hotspotData.Address)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
hotspotRewardTotalsForAddress, err := heliumapi.GetRewardsTotalForHotspot(hotspotData.Address, &e.StartTime, nil)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
for _, hotspotData := range *hotspotsForAddress {
|
||||
// collect hotspot metric requiring extra queries in a new routine
|
||||
wg.Add(2)
|
||||
go e.collectHotspotActivityMetrics(wg, ch, account, hotspotData)
|
||||
go e.collectHotspotRewardsMetrics(wg, ch, account, hotspotData)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
hotspotUp.Desc, hotspotUp.Type, bool2Float64(hotspotData.Status.Online == "online"),
|
||||
|
@ -464,105 +570,52 @@ func (e *Exporter) collectHotspotMetrics(ch chan<- prometheus.Metric, account *A
|
|||
hotspotAntennaInfo.Desc, hotspotAntennaInfo.Type, 1.0,
|
||||
account.Address, hotspotData.Address, hotspotData.Name, strconv.Itoa(hotspotData.Gain), strconv.Itoa(hotspotData.Elevation),
|
||||
)
|
||||
for accType, count := range hotspotActivityForAddress.Data {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
hotspotActivity.Desc, hotspotActivity.Type, float64(count),
|
||||
account.Address, hotspotData.Address, hotspotData.Name, accType,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// collectHotspotActivityMetrics collect the total number of activities executed by a hotspot from the helium api
|
||||
func (e *Exporter) collectHotspotActivityMetrics(wg *sync.WaitGroup, ch chan<- prometheus.Metric, account *Account, hotspotData heliumapi.AccountHotspot) {
|
||||
defer wg.Done()
|
||||
|
||||
hotspotActivityForAddress, err := heliumapi.GetHotspotActivityCount(hotspotData.Address)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
for accType, count := range *hotspotActivityForAddress {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
hotspotRewardsHnt.Desc, hotspotRewardsHnt.Type, hotspotRewardTotalsForAddress.Data.Sum,
|
||||
account.Address, hotspotData.Address, hotspotData.Name,
|
||||
hotspotActivity.Desc, hotspotActivity.Type, float64(count),
|
||||
account.Address, hotspotData.Address, hotspotData.Name, accType,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Account) collectTransactionMetrics(ch chan<- prometheus.Metric) error {
|
||||
now := time.Now()
|
||||
activities, err := heliumapi.GetActivityForAccount(a.Address, []string{}, &a.Tx.LastUpdate, &now)
|
||||
// collectHotspotRewardsMetrics collect the total rewards accumulated by a hotspot from the helium api
|
||||
func (e *Exporter) collectHotspotRewardsMetrics(wg *sync.WaitGroup, ch chan<- prometheus.Metric, account *Account, hotspotData heliumapi.AccountHotspot) {
|
||||
defer wg.Done()
|
||||
|
||||
hotspotRewardTotalsForAddress, err := heliumapi.GetRewardsTotalForHotspot(hotspotData.Address, &e.StartTime, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// logic based on https://github.com/helium/hotspot-app/blob/918563fba84d1abf4554a43a4d42bb838d017bd3/src/features/wallet/root/useActivityItem.tsx#L336
|
||||
for _, activity := range activities.AddGatewayV1 {
|
||||
a.Tx.WithdrawalTotal += activity.StakingFee
|
||||
}
|
||||
for _, activity := range activities.AssertLocationV1 {
|
||||
a.Tx.WithdrawalTotal += activity.StakingFee
|
||||
}
|
||||
for _, activity := range activities.AssertLocationV2 {
|
||||
a.Tx.WithdrawalTotal += activity.StakingFee
|
||||
}
|
||||
for _, activity := range activities.PaymentV1 {
|
||||
if activity.Payer == a.Address {
|
||||
a.Tx.WithdrawalTotal += activity.Amount
|
||||
} else {
|
||||
a.Tx.DepositTotal += activity.Amount
|
||||
}
|
||||
}
|
||||
for _, activity := range activities.PaymentV2 {
|
||||
if activity.Payer == a.Address {
|
||||
paymentTotal := 0
|
||||
for _, payment := range activity.Payments {
|
||||
paymentTotal += payment.Amount
|
||||
}
|
||||
a.Tx.WithdrawalTotal += paymentTotal
|
||||
} else {
|
||||
for _, payment := range activity.Payments {
|
||||
if payment.Payee == a.Address {
|
||||
a.Tx.DepositTotal += payment.Amount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, activity := range activities.RewardsV1 {
|
||||
for _, reward := range activity.Rewards {
|
||||
a.Tx.DepositTotal += reward.Amount
|
||||
}
|
||||
}
|
||||
for _, activity := range activities.RewardsV2 {
|
||||
for _, reward := range activity.Rewards {
|
||||
a.Tx.DepositTotal += reward.Amount
|
||||
}
|
||||
}
|
||||
for _, activity := range activities.StakeValidatorV1 {
|
||||
a.Tx.WithdrawalTotal += activity.Stake
|
||||
}
|
||||
for _, activity := range activities.TokenBurnV1 {
|
||||
a.Tx.WithdrawalTotal += activity.Amount
|
||||
}
|
||||
for _, activity := range activities.TransferHotspotV1 {
|
||||
if activity.Buyer == a.Address {
|
||||
a.Tx.WithdrawalTotal += activity.AmountToSeller
|
||||
} else {
|
||||
a.Tx.DepositTotal += activity.AmountToSeller
|
||||
}
|
||||
}
|
||||
for _, activity := range activities.UnstakeValidatorV1 {
|
||||
a.Tx.WithdrawalTotal += activity.StakeAmount
|
||||
}
|
||||
a.Tx.LastUpdate = now
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
accountDepositsHnt.Desc, accountDepositsHnt.Type, float64(a.Tx.DepositTotal),
|
||||
a.Address,
|
||||
hotspotRewardsHnt.Desc, hotspotRewardsHnt.Type, hotspotRewardTotalsForAddress.Sum,
|
||||
account.Address, hotspotData.Address, hotspotData.Name,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
accountWithdrawalsHnt.Desc, accountWithdrawalsHnt.Type, float64(a.Tx.WithdrawalTotal),
|
||||
a.Address,
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
fApiUrl := flag.String("apiUrl", "https://api.helium.io", "The helium api url")
|
||||
fHeliumAccounts := flag.String("accounts", "", "A comma-delimited list of helium accounts to scrape (optional)")
|
||||
fMetricsPath := flag.String("metricpath", "/metrics", "The metrics path")
|
||||
fListenAddress := flag.String("listenAddress", "0.0.0.0", "The http server listen address")
|
||||
fListenPort := flag.String("listenPort", "9865", "The http server listen port")
|
||||
flag.Parse()
|
||||
|
||||
heliumapi.ApiUrl = *fApiUrl
|
||||
heliumAccounts := strings.Split(*fHeliumAccounts, ",")
|
||||
serverAddr := *fListenAddress + ":" + *fListenPort
|
||||
|
||||
|
@ -587,5 +640,8 @@ func main() {
|
|||
|
||||
http.Handle(*fMetricsPath, promhttp.HandlerFor(r, promhttp.HandlerOpts{}))
|
||||
fmt.Printf("listening on %v\n", serverAddr)
|
||||
http.ListenAndServe(serverAddr, nil)
|
||||
if err = http.ListenAndServe(serverAddr, nil); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,13 +18,13 @@ func GetAccountForAddress(account string) (*Account, error) {
|
|||
}
|
||||
|
||||
// unmarshal the response
|
||||
respobject := Account{}
|
||||
respobject := AccountResp{}
|
||||
err = json.Unmarshal(respBody, &respobject)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal response from path %v: %v", path, err)
|
||||
return nil, fmt.Errorf("failed to unmarshal response from %v: %v", path, err)
|
||||
}
|
||||
|
||||
return &respobject, nil
|
||||
return &respobject.Data, nil
|
||||
}
|
||||
|
||||
func GetActivityForAccount(account string, filterTypes []string, minTime *time.Time, maxTime *time.Time) (*activity.Activities, error) {
|
||||
|
@ -49,7 +49,7 @@ func GetActivityForAccount(account string, filterTypes []string, minTime *time.T
|
|||
activityResp := activity.ActivityResp{}
|
||||
err = json.Unmarshal(respBody, &activityResp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal response from path %v: %v", path, err)
|
||||
return nil, fmt.Errorf("failed to unmarshal response from %v: %v", path, err)
|
||||
}
|
||||
combinedResp.Data = append(combinedResp.Data, activityResp.Data...)
|
||||
}
|
||||
|
@ -67,13 +67,13 @@ func GetActivityCountsForAccount(account string) (*ActivityCounts, error) {
|
|||
}
|
||||
|
||||
// unmarshal the response
|
||||
respobject := ActivityCounts{}
|
||||
respobject := ActivityCountsResp{}
|
||||
err = json.Unmarshal(respBody, &respobject)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal response from path %v: %v", path, err)
|
||||
return nil, fmt.Errorf("failed to unmarshal response from %v: %v", path, err)
|
||||
}
|
||||
|
||||
return &respobject, nil
|
||||
return &respobject.Data, nil
|
||||
}
|
||||
|
||||
func GetRewardTotalsForAccount(account string, minTime *time.Time, maxTime *time.Time) (*RewardTotal, error) {
|
||||
|
@ -93,16 +93,16 @@ func GetRewardTotalsForAccount(account string, minTime *time.Time, maxTime *time
|
|||
}
|
||||
|
||||
// unmarshal the response
|
||||
respobject := RewardTotal{}
|
||||
respobject := RewardTotalResp{}
|
||||
err = json.Unmarshal(respBody, &respobject)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal response from path %v: %v", path, err)
|
||||
return nil, fmt.Errorf("failed to unmarshal response from %v: %v", path, err)
|
||||
}
|
||||
|
||||
return &respobject, nil
|
||||
return &respobject.Data, nil
|
||||
}
|
||||
|
||||
func GetHotspotsForAccount(account string) (*AccountHotspots, error) {
|
||||
func GetHotspotsForAccount(account string) (*[]AccountHotspot, error) {
|
||||
path := "/v1/accounts/" + account + "/hotspots"
|
||||
|
||||
// query the api
|
||||
|
@ -112,11 +112,11 @@ func GetHotspotsForAccount(account string) (*AccountHotspots, error) {
|
|||
}
|
||||
|
||||
// unmarshal the response
|
||||
respobject := AccountHotspots{}
|
||||
respobject := AccountHotspotsResp{}
|
||||
err = json.Unmarshal(respBody, &respobject)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal response from path %v: %v", path, err)
|
||||
return nil, fmt.Errorf("failed to unmarshal response from %v: %v", path, err)
|
||||
}
|
||||
|
||||
return &respobject, nil
|
||||
return &respobject.Data, nil
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ func NewActivities(resp ActivityResp) (*Activities, error) {
|
|||
if err := json.Unmarshal(activityRaw, &activityType); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal activity: %v", err)
|
||||
}
|
||||
fmt.Println(activityType.Type)
|
||||
switch activityType.Type {
|
||||
case "add_gateway_v1":
|
||||
addGatewayV1 := AddGatewayV1{}
|
||||
|
|
|
@ -16,13 +16,13 @@ func GetHotspotActivityCount(hotspot string) (*ActivityCounts, error) {
|
|||
}
|
||||
|
||||
// unmarshal the response
|
||||
respobject := ActivityCounts{}
|
||||
respobject := ActivityCountsResp{}
|
||||
err = json.Unmarshal(respBody, &respobject)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal response from path %v: %v", path, err)
|
||||
return nil, fmt.Errorf("failed to unmarshal response from %v: %v", path, err)
|
||||
}
|
||||
|
||||
return &respobject, nil
|
||||
return &respobject.Data, nil
|
||||
}
|
||||
|
||||
func GetRewardsTotalForHotspot(hotspot string, minTime *time.Time, maxTime *time.Time) (*RewardTotal, error) {
|
||||
|
@ -42,11 +42,11 @@ func GetRewardsTotalForHotspot(hotspot string, minTime *time.Time, maxTime *time
|
|||
}
|
||||
|
||||
// unmarshal the response
|
||||
respobject := RewardTotal{}
|
||||
respobject := RewardTotalResp{}
|
||||
err = json.Unmarshal(respBody, &respobject)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal response from path %v: %v", path, err)
|
||||
return nil, fmt.Errorf("failed to unmarshal response from %v: %v", path, err)
|
||||
}
|
||||
|
||||
return &respobject, nil
|
||||
return &respobject.Data, nil
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
)
|
||||
|
||||
func GetCurrentOraclePrice() (*CurrentOraclePrice, error) {
|
||||
const path = "/v1/oracle/prices/current"
|
||||
path := "/v1/oracle/prices/current"
|
||||
|
||||
// query the api
|
||||
respBody, err := getHeliumApi(path, nil)
|
||||
|
@ -15,11 +15,11 @@ func GetCurrentOraclePrice() (*CurrentOraclePrice, error) {
|
|||
}
|
||||
|
||||
// unmarshal the response
|
||||
respobject := CurrentOraclePrice{}
|
||||
respobject := CurrentOraclePriceResp{}
|
||||
err = json.Unmarshal(respBody, &respobject)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal response from path %v: %v", path, err)
|
||||
return nil, fmt.Errorf("failed to unmarshal response from %v: %v", path, err)
|
||||
}
|
||||
|
||||
return &respobject, nil
|
||||
return &respobject.Data, nil
|
||||
}
|
||||
|
|
|
@ -7,16 +7,13 @@ import (
|
|||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
apiUrl = "https://api.helium.io"
|
||||
)
|
||||
|
||||
var (
|
||||
ApiUrl = "https://api.helium.io"
|
||||
client = &http.Client{}
|
||||
)
|
||||
|
||||
func createGetRequest(path string, params map[string]string) (*http.Request, error) {
|
||||
req, err := http.NewRequest("GET", fmt.Sprintf("%s/%s", apiUrl, path), nil)
|
||||
req, err := http.NewRequest("GET", fmt.Sprintf("%s/%s", ApiUrl, path), nil)
|
||||
|
||||
// setup headers
|
||||
req.Header.Add("Accept", "application/json")
|
||||
|
@ -50,14 +47,14 @@ func getHeliumApi(path string, params *map[string]string) ([]byte, error) {
|
|||
// query the api
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query path %v: %v", path, err)
|
||||
return nil, fmt.Errorf("failed to query %v: %v", path, err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// read the response body
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response body of path %v: %v", path, err)
|
||||
return nil, fmt.Errorf("failed to read response body of %v: %v", path, err)
|
||||
}
|
||||
|
||||
return body, nil
|
||||
|
@ -84,14 +81,14 @@ func getHeliumApiWithCursor(path string, params *map[string]string) ([][]byte, e
|
|||
// query the api
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query path %v: %v", path, err)
|
||||
return nil, fmt.Errorf("failed to query %v: %v", path, err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// read the response body and add it to the result array
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response body of path %v: %v", path, err)
|
||||
return nil, fmt.Errorf("failed to read response body of %v: %v", path, err)
|
||||
}
|
||||
res = append(res, body)
|
||||
|
||||
|
@ -99,7 +96,7 @@ func getHeliumApiWithCursor(path string, params *map[string]string) ([][]byte, e
|
|||
respCursor.Cursor = ""
|
||||
err = json.Unmarshal(body, &respCursor)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal response from path %v: %v", path, err)
|
||||
return nil, fmt.Errorf("failed to unmarshal response from %v: %v", path, err)
|
||||
}
|
||||
|
||||
// continue querying until there is no longer a cursor
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
)
|
||||
|
||||
func GetBlockchainStats() (*BlockchainStats, error) {
|
||||
const path = "/v1/stats"
|
||||
path := "/v1/stats"
|
||||
|
||||
// query the api
|
||||
respBody, err := getHeliumApi(path, nil)
|
||||
|
@ -15,11 +15,11 @@ func GetBlockchainStats() (*BlockchainStats, error) {
|
|||
}
|
||||
|
||||
// unmarshal the response
|
||||
respobject := BlockchainStats{}
|
||||
respobject := BlockchainStatsResp{}
|
||||
err = json.Unmarshal(respBody, &respobject)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal response from path %v: %v", path, err)
|
||||
return nil, fmt.Errorf("failed to unmarshal response from %v: %v", path, err)
|
||||
}
|
||||
|
||||
return &respobject, nil
|
||||
return &respobject.Data, nil
|
||||
}
|
||||
|
|
|
@ -1,140 +1,152 @@
|
|||
package heliumapi
|
||||
|
||||
type AccountResp struct {
|
||||
Data Account `json:"data"`
|
||||
}
|
||||
|
||||
type Account struct {
|
||||
Data struct {
|
||||
Address string `json:"address"`
|
||||
Balance int `json:"balance"`
|
||||
Block int `json:"block"`
|
||||
DCBalance int `json:"dc_balance"`
|
||||
DCNonce int `json:"dc_nonce"`
|
||||
SECBalance int `json:"sec_balance"`
|
||||
SECNonce int `json:"sec_nonce"`
|
||||
SpeculativeNonce int `json:"speculative_nonce"`
|
||||
} `json:"data"`
|
||||
Address string `json:"address"`
|
||||
Balance int `json:"balance"`
|
||||
Block int `json:"block"`
|
||||
DCBalance int `json:"dc_balance"`
|
||||
DCNonce int `json:"dc_nonce"`
|
||||
SECBalance int `json:"sec_balance"`
|
||||
SECNonce int `json:"sec_nonce"`
|
||||
SpeculativeNonce int `json:"speculative_nonce"`
|
||||
}
|
||||
|
||||
type AccountHotspots struct {
|
||||
Data []struct {
|
||||
Lng float64 `json:"lng"`
|
||||
Lat float64 `json:"lat"`
|
||||
TimestampAdded string `json:"timestamp_added"`
|
||||
Status struct {
|
||||
Timestamp string `json:"timestamp"`
|
||||
Online string `json:"online"`
|
||||
ListenAddrs []string `json:"listen_addrs"`
|
||||
Height int `json:"height"`
|
||||
} `json:"status"`
|
||||
RewardScale float64 `json:"reward_scale"`
|
||||
Payer string `json:"payer"`
|
||||
Owner string `json:"owner"`
|
||||
Nonce int `json:"nonce"`
|
||||
Name string `json:"name"`
|
||||
Mode string `json:"mode"`
|
||||
LocationHex string `json:"location_hex"`
|
||||
Location string `json:"location"`
|
||||
LastPocChallenge int `json:"last_poc_challenge"`
|
||||
LastChangeBlock int `json:"last_change_block"`
|
||||
Geocode struct {
|
||||
ShortStreet string `json:"short_street"`
|
||||
ShortState string `json:"short_state"`
|
||||
ShortCountry string `json:"short_country"`
|
||||
ShortCity string `json:"short_city"`
|
||||
LongStreet string `json:"long_street"`
|
||||
LongState string `json:"long_state"`
|
||||
LongCountry string `json:"long_country"`
|
||||
LongCity string `json:"long_city"`
|
||||
CityID string `json:"city_id"`
|
||||
} `json:"geocode"`
|
||||
Gain int `json:"gain"`
|
||||
Elevation int `json:"elevation"`
|
||||
BlockAdded int `json:"block_added"`
|
||||
Block int `json:"block"`
|
||||
Address string `json:"address"`
|
||||
} `json:"data"`
|
||||
type AccountHotspotsResp struct {
|
||||
Data []AccountHotspot `json:"data"`
|
||||
}
|
||||
|
||||
type ActivityCounts struct {
|
||||
Data map[string]int
|
||||
type AccountHotspot struct {
|
||||
Lng float64 `json:"lng"`
|
||||
Lat float64 `json:"lat"`
|
||||
TimestampAdded string `json:"timestamp_added"`
|
||||
Status struct {
|
||||
Timestamp string `json:"timestamp"`
|
||||
Online string `json:"online"`
|
||||
ListenAddrs []string `json:"listen_addrs"`
|
||||
Height int `json:"height"`
|
||||
} `json:"status"`
|
||||
RewardScale float64 `json:"reward_scale"`
|
||||
Payer string `json:"payer"`
|
||||
Owner string `json:"owner"`
|
||||
Nonce int `json:"nonce"`
|
||||
Name string `json:"name"`
|
||||
Mode string `json:"mode"`
|
||||
LocationHex string `json:"location_hex"`
|
||||
Location string `json:"location"`
|
||||
LastPocChallenge int `json:"last_poc_challenge"`
|
||||
LastChangeBlock int `json:"last_change_block"`
|
||||
Geocode struct {
|
||||
ShortStreet string `json:"short_street"`
|
||||
ShortState string `json:"short_state"`
|
||||
ShortCountry string `json:"short_country"`
|
||||
ShortCity string `json:"short_city"`
|
||||
LongStreet string `json:"long_street"`
|
||||
LongState string `json:"long_state"`
|
||||
LongCountry string `json:"long_country"`
|
||||
LongCity string `json:"long_city"`
|
||||
CityID string `json:"city_id"`
|
||||
} `json:"geocode"`
|
||||
Gain int `json:"gain"`
|
||||
Elevation int `json:"elevation"`
|
||||
BlockAdded int `json:"block_added"`
|
||||
Block int `json:"block"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
||||
type RewardTotal struct {
|
||||
type ActivityCountsResp struct {
|
||||
Data ActivityCounts
|
||||
}
|
||||
|
||||
type ActivityCounts map[string]int
|
||||
|
||||
type RewardTotalResp struct {
|
||||
Meta struct {
|
||||
MinTime string `json:"min_time"`
|
||||
MaxTime string `json:"max_time"`
|
||||
} `json:"meta"`
|
||||
|
||||
Data struct {
|
||||
Total float64 `json:"total"`
|
||||
Sum float64 `json:"sum"`
|
||||
Stddev float64 `json:"stddev"`
|
||||
Min float64 `json:"min"`
|
||||
Median float64 `json:"median"`
|
||||
Max float64 `json:"max"`
|
||||
Avg float64 `json:"avg"`
|
||||
} `json:"data"`
|
||||
Data RewardTotal `json:"data"`
|
||||
}
|
||||
|
||||
type RewardTotal struct {
|
||||
Total float64 `json:"total"`
|
||||
Sum float64 `json:"sum"`
|
||||
Stddev float64 `json:"stddev"`
|
||||
Min float64 `json:"min"`
|
||||
Median float64 `json:"median"`
|
||||
Max float64 `json:"max"`
|
||||
Avg float64 `json:"avg"`
|
||||
}
|
||||
|
||||
type CurrentOraclePriceResp struct {
|
||||
Data CurrentOraclePrice `json:"data"`
|
||||
}
|
||||
|
||||
type CurrentOraclePrice struct {
|
||||
Data struct {
|
||||
Price int `json:"price"`
|
||||
Block int `json:"block"`
|
||||
} `json:"data"`
|
||||
Price int `json:"price"`
|
||||
Block int `json:"block"`
|
||||
}
|
||||
|
||||
type BlockchainStatsResp struct {
|
||||
Data BlockchainStats `json:"data"`
|
||||
}
|
||||
|
||||
type BlockchainStats struct {
|
||||
Data struct {
|
||||
BlockTime struct {
|
||||
LastDay struct {
|
||||
Avg float64 `json:"avg"`
|
||||
Stddev float64 `json:"stddev"`
|
||||
} `json:"last_day"`
|
||||
LastHour struct {
|
||||
Avg float64 `json:"avg"`
|
||||
Stddev float64 `json:"stddev"`
|
||||
} `json:"last_hour"`
|
||||
LastMonth struct {
|
||||
Avg float64 `json:"avg"`
|
||||
Stddev float64 `json:"stddev"`
|
||||
} `json:"last_month"`
|
||||
LastWeek struct {
|
||||
Avg float64 `json:"avg"`
|
||||
Stddev float64 `json:"stddev"`
|
||||
} `json:"last_week"`
|
||||
} `json:"block_times"`
|
||||
ChallengeCount struct {
|
||||
Active int `json:"active"`
|
||||
LastDay int `json:"last_day"`
|
||||
} `json:"challenge_counts"`
|
||||
Counts struct {
|
||||
Validators int `json:"validators"`
|
||||
Ouis int `json:"ouis"`
|
||||
HotspotsDataonly int `json:"hotspots_dataonly"`
|
||||
Blocks int `json:"blocks"`
|
||||
Challenges int `json:"challenges"`
|
||||
Cities int `json:"cities"`
|
||||
ConsensusGroups int `json:"consensus_groups"`
|
||||
Countries int `json:"countries"`
|
||||
Hotspots int `json:"hotspots"`
|
||||
Transactions int `json:"transactions"`
|
||||
} `json:"counts"`
|
||||
ElectionTimes struct {
|
||||
LastDay struct {
|
||||
Avg float64 `json:"avg"`
|
||||
Stddev float64 `json:"stddev"`
|
||||
} `json:"last_day"`
|
||||
LastHour struct {
|
||||
Avg float64 `json:"avg"`
|
||||
Stddev float64 `json:"stddev"`
|
||||
} `json:"last_hour"`
|
||||
LastMonth struct {
|
||||
Avg float64 `json:"avg"`
|
||||
Stddev float64 `json:"stddev"`
|
||||
} `json:"last_month"`
|
||||
LastWeek struct {
|
||||
Avg float64 `json:"avg"`
|
||||
Stddev float64 `json:"stddev"`
|
||||
} `json:"last_week"`
|
||||
} `json:"election_times"`
|
||||
TokenSupply float64 `json:"token_supply"`
|
||||
} `json:"data"`
|
||||
BlockTime struct {
|
||||
LastDay struct {
|
||||
Avg float64 `json:"avg"`
|
||||
Stddev float64 `json:"stddev"`
|
||||
} `json:"last_day"`
|
||||
LastHour struct {
|
||||
Avg float64 `json:"avg"`
|
||||
Stddev float64 `json:"stddev"`
|
||||
} `json:"last_hour"`
|
||||
LastMonth struct {
|
||||
Avg float64 `json:"avg"`
|
||||
Stddev float64 `json:"stddev"`
|
||||
} `json:"last_month"`
|
||||
LastWeek struct {
|
||||
Avg float64 `json:"avg"`
|
||||
Stddev float64 `json:"stddev"`
|
||||
} `json:"last_week"`
|
||||
} `json:"block_times"`
|
||||
ChallengeCount struct {
|
||||
Active int `json:"active"`
|
||||
LastDay int `json:"last_day"`
|
||||
} `json:"challenge_counts"`
|
||||
Counts struct {
|
||||
Validators int `json:"validators"`
|
||||
Ouis int `json:"ouis"`
|
||||
HotspotsDataonly int `json:"hotspots_dataonly"`
|
||||
Blocks int `json:"blocks"`
|
||||
Challenges int `json:"challenges"`
|
||||
Cities int `json:"cities"`
|
||||
ConsensusGroups int `json:"consensus_groups"`
|
||||
Countries int `json:"countries"`
|
||||
Hotspots int `json:"hotspots"`
|
||||
Transactions int `json:"transactions"`
|
||||
} `json:"counts"`
|
||||
ElectionTimes struct {
|
||||
LastDay struct {
|
||||
Avg float64 `json:"avg"`
|
||||
Stddev float64 `json:"stddev"`
|
||||
} `json:"last_day"`
|
||||
LastHour struct {
|
||||
Avg float64 `json:"avg"`
|
||||
Stddev float64 `json:"stddev"`
|
||||
} `json:"last_hour"`
|
||||
LastMonth struct {
|
||||
Avg float64 `json:"avg"`
|
||||
Stddev float64 `json:"stddev"`
|
||||
} `json:"last_month"`
|
||||
LastWeek struct {
|
||||
Avg float64 `json:"avg"`
|
||||
Stddev float64 `json:"stddev"`
|
||||
} `json:"last_week"`
|
||||
} `json:"election_times"`
|
||||
TokenSupply float64 `json:"token_supply"`
|
||||
}
|
||||
|
|
Reference in New Issue