github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/internal/blocks/handle_hashes.go (about) 1 // Copyright 2021 The TrueBlocks Authors. All rights reserved. 2 // Use of this source code is governed by a license that can 3 // be found in the LICENSE file. 4 5 package blocksPkg 6 7 import ( 8 "context" 9 "fmt" 10 "sort" 11 12 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base" 13 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/identifiers" 14 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger" 15 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/output" 16 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types" 17 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/utils" 18 ) 19 20 func (opts *BlocksOptions) HandleHashes(rCtx *output.RenderCtx) error { 21 chain := opts.Globals.Chain 22 testMode := opts.Globals.TestMode 23 nErrors := 0 24 25 fetchData := func(modelChan chan types.Modeler, errorChan chan error) { 26 apps, _, err := identifiers.IdsToApps(chain, opts.BlockIds) 27 if err != nil { 28 errorChan <- err 29 rCtx.Cancel() 30 } 31 32 if sliceOfMaps, cnt, err := types.AsSliceOfMaps[types.LightBlock](apps, false); err != nil { 33 errorChan <- err 34 rCtx.Cancel() 35 36 } else if cnt == 0 { 37 errorChan <- fmt.Errorf("no blocks found for the query") 38 rCtx.Cancel() 39 40 } else { 41 showProgress := opts.Globals.ShowProgress() 42 bar := logger.NewBar(logger.BarOptions{ 43 Enabled: showProgress, 44 Total: int64(cnt), 45 }) 46 47 for _, thisMap := range sliceOfMaps { 48 if rCtx.WasCanceled() { 49 return 50 } 51 52 for app := range thisMap { 53 thisMap[app] = new(types.LightBlock) 54 } 55 56 items := make([]*types.LightBlock, 0, len(thisMap)) 57 iterFunc := func(app types.Appearance, value *types.LightBlock) error { 58 bn := base.Blknum(app.BlockNumber) 59 if block, err := opts.Conn.GetBlockHeaderByNumber(bn); err != nil { 60 errMutex.Lock() 61 defer errMutex.Unlock() 62 delete(thisMap, app) 63 return err 64 } else { 65 *value = block 66 bar.Tick() 67 } 68 return nil 69 } 70 71 iterErrorChan := make(chan error) 72 iterCtx, iterCancel := context.WithCancel(context.Background()) 73 defer iterCancel() 74 go utils.IterateOverMap(iterCtx, iterErrorChan, thisMap, iterFunc) 75 for err := range iterErrorChan { 76 if !testMode || nErrors == 0 { 77 errorChan <- err 78 nErrors++ 79 } 80 } 81 82 for _, item := range thisMap { 83 items = append(items, item) 84 } 85 sort.Slice(items, func(i, j int) bool { 86 if items[i].BlockNumber == items[j].BlockNumber { 87 return items[i].Hash.Hex() < items[j].Hash.Hex() 88 } 89 return items[i].BlockNumber < items[j].BlockNumber 90 }) 91 92 for _, item := range items { 93 modelChan <- item 94 } 95 } 96 bar.Finish(true /* newLine */) 97 } 98 } 99 100 extraOpts := map[string]any{ 101 "uncles": opts.Uncles, 102 "articulate": opts.Articulate, 103 } 104 105 return output.StreamMany(rCtx, fetchData, opts.Globals.OutputOptsWithExtra(extraOpts)) 106 }