88 "io"
99 "net/http"
1010 "strings"
11+ "sync"
1112 "time"
1213
1314 "github.com/anilcse/cosmoscope/internal/portfolio"
@@ -21,61 +22,15 @@ var (
2122 chainInfoCache = make (map [string ]* ChainInfo )
2223 assetListCache = make (map [string ]AssetList )
2324 registryBaseURL = "https://raw.githubusercontent.com/cosmos/chain-registry/master"
25+ cacheMutex sync.RWMutex
2426)
2527
26- // getActiveEndpoint tries each REST endpoint until it finds one that responds
27- func getActiveEndpoint (endpoints []RestEndpoint ) string {
28- ctx , cancel := context .WithTimeout (context .Background (), 3 * time .Second )
29- defer cancel ()
30-
31- type result struct {
32- endpoint string
33- err error
34- }
35- resultChan := make (chan result )
36-
37- // Try all endpoints concurrently
38- for _ , endpoint := range endpoints {
39- go func (addr string ) {
40- client := & http.Client {Timeout : 2 * time .Second }
41- req , err := http .NewRequestWithContext (ctx , "GET" , addr + "/cosmos/base/tendermint/v1beta1/node_info" , nil )
42- if err != nil {
43- resultChan <- result {endpoint : addr , err : err }
44- return
45- }
46-
47- resp , err := client .Do (req )
48- if err != nil {
49- resultChan <- result {endpoint : addr , err : err }
50- return
51- }
52- defer resp .Body .Close ()
53-
54- if resp .StatusCode == http .StatusOK {
55- resultChan <- result {endpoint : addr , err : nil }
56- } else {
57- resultChan <- result {endpoint : addr , err : fmt .Errorf ("endpoint returned status %d" , resp .StatusCode )}
58- }
59- }(endpoint .Address )
60- }
61-
62- // Return the first successful endpoint
63- for range endpoints {
64- select {
65- case r := <- resultChan :
66- if r .err == nil {
67- return r .endpoint
68- }
69- case <- ctx .Done ():
70- return ""
71- }
72- }
73-
74- return ""
75- }
76-
7728func FetchChainInfo (network string ) (* ChainInfo , error ) {
78- if info , exists := chainInfoCache [network ]; exists {
29+ // Try to read from cache first
30+ cacheMutex .RLock ()
31+ info , exists := chainInfoCache [network ]
32+ cacheMutex .RUnlock ()
33+ if exists {
7934 return info , nil
8035 }
8136
@@ -93,12 +48,20 @@ func FetchChainInfo(network string) (*ChainInfo, error) {
9348 return nil , fmt .Errorf ("error decoding chain info: %v" , err )
9449 }
9550
51+ // Store in cache with write lock
52+ cacheMutex .Lock ()
9653 chainInfoCache [network ] = & chainInfo
54+ cacheMutex .Unlock ()
55+
9756 return & chainInfo , nil
9857}
9958
10059func fetchAssetList (network string ) (* AssetList , error ) {
101- if assetList , exists := assetListCache [network ]; exists {
60+ // Try to read from cache first
61+ cacheMutex .RLock ()
62+ assetList , exists := assetListCache [network ]
63+ cacheMutex .RUnlock ()
64+ if exists {
10265 return & assetList , nil
10366 }
10467
@@ -111,12 +74,15 @@ func fetchAssetList(network string) (*AssetList, error) {
11174 }
11275 defer resp .Body .Close ()
11376
114- var assetList AssetList
11577 if err := json .NewDecoder (resp .Body ).Decode (& assetList ); err != nil {
11678 return nil , fmt .Errorf ("error decoding asset list: %v" , err )
11779 }
11880
81+ // Store in cache with write lock
82+ cacheMutex .Lock ()
11983 assetListCache [network ] = assetList
84+ cacheMutex .Unlock ()
85+
12086 return & assetList , nil
12187}
12288
@@ -331,3 +297,54 @@ func getHexAddress(address string) string {
331297 }
332298 return hex .EncodeToString (bz )
333299}
300+
301+ // getActiveEndpoint tries each REST endpoint until it finds one that responds
302+ func getActiveEndpoint (endpoints []RestEndpoint ) string {
303+ ctx , cancel := context .WithTimeout (context .Background (), 3 * time .Second )
304+ defer cancel ()
305+
306+ type result struct {
307+ endpoint string
308+ err error
309+ }
310+ resultChan := make (chan result )
311+
312+ // Try all endpoints concurrently
313+ for _ , endpoint := range endpoints {
314+ go func (addr string ) {
315+ client := & http.Client {Timeout : 2 * time .Second }
316+ req , err := http .NewRequestWithContext (ctx , "GET" , addr + "/cosmos/base/tendermint/v1beta1/node_info" , nil )
317+ if err != nil {
318+ resultChan <- result {endpoint : addr , err : err }
319+ return
320+ }
321+
322+ resp , err := client .Do (req )
323+ if err != nil {
324+ resultChan <- result {endpoint : addr , err : err }
325+ return
326+ }
327+ defer resp .Body .Close ()
328+
329+ if resp .StatusCode == http .StatusOK {
330+ resultChan <- result {endpoint : addr , err : nil }
331+ } else {
332+ resultChan <- result {endpoint : addr , err : fmt .Errorf ("endpoint returned status %d" , resp .StatusCode )}
333+ }
334+ }(endpoint .Address )
335+ }
336+
337+ // Return the first successful endpoint
338+ for range endpoints {
339+ select {
340+ case r := <- resultChan :
341+ if r .err == nil {
342+ return r .endpoint
343+ }
344+ case <- ctx .Done ():
345+ return ""
346+ }
347+ }
348+
349+ return ""
350+ }
0 commit comments