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