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