github.com/hashgraph/hedera-sdk-go/v2@v2.48.0/address_book_query.go (about)

     1  package hedera
     2  
     3  /*-
     4   *
     5   * Hedera Go SDK
     6   *
     7   * Copyright (C) 2020 - 2024 Hedera Hashgraph, LLC
     8   *
     9   * Licensed under the Apache License, Version 2.0 (the "License");
    10   * you may not use this file except in compliance with the License.
    11   * You may obtain a copy of the License at
    12   *
    13   *      http://www.apache.org/licenses/LICENSE-2.0
    14   *
    15   * Unless required by applicable law or agreed to in writing, software
    16   * distributed under the License is distributed on an "AS IS" BASIS,
    17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    18   * See the License for the specific language governing permissions and
    19   * limitations under the License.
    20   *
    21   */
    22  
    23  import (
    24  	"context"
    25  	"io"
    26  	"math"
    27  	"time"
    28  
    29  	"github.com/hashgraph/hedera-protobufs-go/services"
    30  
    31  	"github.com/hashgraph/hedera-protobufs-go/mirror"
    32  	"google.golang.org/grpc/status"
    33  )
    34  
    35  // AddressBookQuery query an address book for its list of nodes
    36  type AddressBookQuery struct {
    37  	attempt     uint64
    38  	maxAttempts uint64
    39  	fileID      *FileID
    40  	limit       int32
    41  }
    42  
    43  // Query the mirror node for the address book.
    44  func NewAddressBookQuery() *AddressBookQuery {
    45  	return &AddressBookQuery{
    46  		fileID: nil,
    47  		limit:  0,
    48  	}
    49  }
    50  
    51  // SetFileID set the ID of the address book file on the network. Can be either 0.0.101 or 0.0.102.
    52  func (q *AddressBookQuery) SetFileID(id FileID) *AddressBookQuery {
    53  	q.fileID = &id
    54  	return q
    55  }
    56  
    57  func (q *AddressBookQuery) GetFileID() FileID {
    58  	if q.fileID == nil {
    59  		return FileID{}
    60  	}
    61  
    62  	return *q.fileID
    63  }
    64  
    65  // SetLimit
    66  // Set the maximum number of node addresses to receive before stopping.
    67  // If not set or set to zero it will return all node addresses in the database.
    68  func (q *AddressBookQuery) SetLimit(limit int32) *AddressBookQuery {
    69  	q.limit = limit
    70  	return q
    71  }
    72  
    73  func (q *AddressBookQuery) GetLimit() int32 {
    74  	return q.limit
    75  }
    76  
    77  func (q *AddressBookQuery) SetMaxAttempts(maxAttempts uint64) *AddressBookQuery {
    78  	q.maxAttempts = maxAttempts
    79  	return q
    80  }
    81  
    82  func (q *AddressBookQuery) GetMaxAttempts() uint64 {
    83  	return q.maxAttempts
    84  }
    85  
    86  func (q *AddressBookQuery) validateNetworkOnIDs(client *Client) error {
    87  	if client == nil || !client.autoValidateChecksums {
    88  		return nil
    89  	}
    90  
    91  	if q.fileID != nil {
    92  		if err := q.fileID.ValidateChecksum(client); err != nil {
    93  			return err
    94  		}
    95  	}
    96  
    97  	return nil
    98  }
    99  
   100  func (q *AddressBookQuery) build() *mirror.AddressBookQuery {
   101  	body := &mirror.AddressBookQuery{
   102  		Limit: q.limit,
   103  	}
   104  	if q.fileID != nil {
   105  		body.FileId = q.fileID._ToProtobuf()
   106  	}
   107  
   108  	return body
   109  }
   110  
   111  // Execute executes the Query with the provided client
   112  func (q *AddressBookQuery) Execute(client *Client) (NodeAddressBook, error) {
   113  	var cancel func()
   114  	var ctx context.Context
   115  	var subClientError error
   116  	err := q.validateNetworkOnIDs(client)
   117  	if err != nil {
   118  		return NodeAddressBook{}, err
   119  	}
   120  
   121  	pb := q.build()
   122  
   123  	messages := make([]*services.NodeAddress, 0)
   124  
   125  	channel, err := client.mirrorNetwork._GetNextMirrorNode()._GetNetworkServiceClient()
   126  	if err != nil {
   127  		return NodeAddressBook{}, err
   128  	}
   129  	ch := make(chan byte, 1)
   130  
   131  	go func() {
   132  		var subClient mirror.NetworkService_GetNodesClient
   133  		var err error
   134  
   135  		for {
   136  			if err != nil {
   137  				cancel()
   138  
   139  				if grpcErr, ok := status.FromError(err); ok { // nolint
   140  					if q.attempt < q.maxAttempts {
   141  						subClient = nil
   142  
   143  						delay := math.Min(250.0*math.Pow(2.0, float64(q.attempt)), 8000)
   144  						time.Sleep(time.Duration(delay) * time.Millisecond)
   145  						q.attempt++
   146  					} else {
   147  						subClientError = grpcErr.Err()
   148  						break
   149  					}
   150  				} else if err == io.EOF {
   151  					break
   152  				} else {
   153  					subClientError = err
   154  					break
   155  				}
   156  			}
   157  
   158  			if subClient == nil {
   159  				ctx, cancel = context.WithCancel(client.networkUpdateContext)
   160  
   161  				subClient, err = (*channel).GetNodes(ctx, pb)
   162  				if err != nil {
   163  					continue
   164  				}
   165  			}
   166  
   167  			var resp *services.NodeAddress
   168  			resp, err = subClient.Recv()
   169  
   170  			if err != nil {
   171  				continue
   172  			}
   173  
   174  			if pb.Limit > 0 {
   175  				pb.Limit--
   176  			}
   177  
   178  			messages = append(messages, resp)
   179  		}
   180  		ch <- 1
   181  	}()
   182  	<-ch
   183  
   184  	result := make([]NodeAddress, 0)
   185  
   186  	for _, k := range messages {
   187  		result = append(result, _NodeAddressFromProtobuf(k))
   188  	}
   189  
   190  	return NodeAddressBook{
   191  		NodeAddresses: result,
   192  	}, subClientError
   193  }