github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/internal/traces/handle_count.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 tracesPkg 6 7 import ( 8 "context" 9 "fmt" 10 "sort" 11 12 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/identifiers" 13 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger" 14 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/output" 15 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types" 16 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/utils" 17 ) 18 19 func (opts *TracesOptions) HandleCount(rCtx *output.RenderCtx) error { 20 chain := opts.Globals.Chain 21 testMode := opts.Globals.TestMode 22 nErrors := 0 23 24 fetchData := func(modelChan chan types.Modeler, errorChan chan error) { 25 apps, _, err := identifiers.IdsToApps(chain, opts.TransactionIds) 26 if err != nil { 27 errorChan <- err 28 rCtx.Cancel() 29 } 30 31 if sliceOfMaps, cnt, err := types.AsSliceOfMaps[types.Transaction](apps, false); err != nil { 32 errorChan <- err 33 rCtx.Cancel() 34 35 } else if cnt == 0 { 36 errorChan <- fmt.Errorf("no transactions found") 37 rCtx.Cancel() 38 39 } else { 40 showProgress := opts.Globals.ShowProgress() 41 bar := logger.NewBar(logger.BarOptions{ 42 Enabled: showProgress, 43 Total: int64(cnt), 44 }) 45 46 for _, thisMap := range sliceOfMaps { 47 if rCtx.WasCanceled() { 48 return 49 } 50 51 for app := range thisMap { 52 thisMap[app] = new(types.Transaction) 53 } 54 55 iterFunc := func(app types.Appearance, value *types.Transaction) error { 56 if tx, err := opts.Conn.GetTransactionByAppearance(&app, true); err != nil { 57 delete(thisMap, app) 58 return fmt.Errorf("transaction at %s returned an error: %w", app.Orig(), err) 59 60 } else if tx == nil || len(tx.Traces) == 0 { 61 delete(thisMap, app) 62 return fmt.Errorf("transaction at %s has no traces", app.Orig()) 63 64 } else { 65 *value = *tx 66 bar.Tick() 67 return nil 68 } 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 items := make([]*types.Transaction, 0, len(thisMap)) 83 for _, tx := range thisMap { 84 items = append(items, tx) 85 } 86 sort.Slice(items, func(i, j int) bool { 87 if items[i].BlockNumber == items[j].BlockNumber { 88 return items[i].TransactionIndex < items[j].TransactionIndex 89 } 90 return items[i].BlockNumber < items[j].BlockNumber 91 }) 92 93 for _, item := range items { 94 counter := types.TraceCount{ 95 BlockNumber: item.BlockNumber, 96 TransactionIndex: item.TransactionIndex, 97 TransactionHash: item.Hash, 98 Timestamp: item.Timestamp, 99 TracesCnt: uint64(len(item.Traces)), 100 } 101 modelChan <- &counter 102 } 103 } 104 bar.Finish(true /* newLine */) 105 } 106 } 107 108 return output.StreamMany(rCtx, fetchData, opts.Globals.OutputOpts()) 109 }