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 }