github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/internal/export/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 exportPkg 6 7 import ( 8 "context" 9 "fmt" 10 "sort" 11 12 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/articulate" 13 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base" 14 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/filter" 15 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger" 16 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/monitor" 17 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/output" 18 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types" 19 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/utils" 20 ) 21 22 func (opts *ExportOptions) HandleShow(rCtx *output.RenderCtx, monitorArray []monitor.Monitor) error { 23 abiCache := articulate.NewAbiCache(opts.Conn, opts.Articulate) 24 filter := filter.NewFilter( 25 opts.Reversed, 26 opts.Reverted, 27 opts.Fourbytes, 28 base.BlockRange{First: opts.FirstBlock, Last: opts.LastBlock}, 29 base.RecordRange{First: opts.FirstRecord, Last: opts.GetMax()}, 30 ) 31 32 fetchData := func(modelChan chan types.Modeler, errorChan chan error) { 33 for _, mon := range monitorArray { 34 if apps, cnt, err := mon.ReadAndFilterAppearances(filter, false /* withCount */); err != nil { 35 errorChan <- err 36 rCtx.Cancel() 37 38 } else if cnt == 0 { 39 errorChan <- fmt.Errorf("no blocks found for the query") 40 continue 41 42 } else { 43 if sliceOfMaps, _, err := types.AsSliceOfMaps[types.Transaction](apps, filter.Reversed); err != nil { 44 errorChan <- err 45 rCtx.Cancel() 46 47 } else { 48 showProgress := opts.Globals.ShowProgress() 49 bar := logger.NewBar(logger.BarOptions{ 50 Prefix: mon.Address.Hex(), 51 Enabled: showProgress, 52 Total: int64(cnt), 53 }) 54 55 // TODO: BOGUS - THIS IS NOT CONCURRENCY SAFE 56 finished := false 57 for _, thisMap := range sliceOfMaps { 58 if rCtx.WasCanceled() { 59 return 60 } 61 62 if finished { 63 continue 64 } 65 66 for app := range thisMap { 67 thisMap[app] = new(types.Transaction) 68 } 69 70 iterFunc := func(app types.Appearance, value *types.Transaction) error { 71 if tx, err := opts.Conn.GetTransactionByAppearance(&app, false); err != nil { 72 return err 73 } else { 74 passes, _ := filter.ApplyTxFilters(tx) 75 if passes { 76 *value = *tx 77 } 78 if bar != nil { 79 bar.Tick() 80 } 81 return nil 82 } 83 } 84 85 // Set up and interate over the map calling iterFunc for each appearance 86 iterCtx, iterCancel := context.WithCancel(context.Background()) 87 defer iterCancel() 88 errChan := make(chan error) 89 go utils.IterateOverMap(iterCtx, errChan, thisMap, iterFunc) 90 if stepErr := <-errChan; stepErr != nil { 91 errorChan <- stepErr 92 return 93 } 94 95 items := make([]*types.Transaction, 0, len(thisMap)) 96 for _, tx := range thisMap { 97 if opts.Articulate { 98 if err = abiCache.ArticulateTransaction(tx); err != nil { 99 errorChan <- err // continue even on error 100 } 101 } 102 items = append(items, tx) 103 } 104 105 sort.Slice(items, func(i, j int) bool { 106 if opts.Reversed { 107 i, j = j, i 108 } 109 if items[i].BlockNumber == items[j].BlockNumber { 110 return items[i].TransactionIndex < items[j].TransactionIndex 111 } 112 return items[i].BlockNumber < items[j].BlockNumber 113 }) 114 115 for _, item := range items { 116 if item.BlockHash.IsZero() { 117 continue 118 } 119 var passes bool 120 passes, finished = filter.ApplyCountFilter() 121 if passes { 122 modelChan <- item 123 } 124 if finished { 125 break 126 } 127 } 128 } 129 bar.Finish(true /* newLine */) 130 } 131 } 132 } 133 } 134 135 extraOpts := map[string]any{ 136 "articulate": opts.Articulate, 137 "export": true, 138 } 139 140 return output.StreamMany(rCtx, fetchData, opts.Globals.OutputOptsWithExtra(extraOpts)) 141 }