github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/internal/chunks/handle_appearances.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 chunksPkg
     6  
     7  import (
     8  	"encoding/binary"
     9  	"fmt"
    10  	"io"
    11  
    12  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
    13  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/file"
    14  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/index"
    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/walk"
    18  )
    19  
    20  func (opts *ChunksOptions) HandleAppearances(rCtx *output.RenderCtx, blockNums []base.Blknum) error {
    21  	chain := opts.Globals.Chain
    22  
    23  	fetchData := func(modelChan chan types.Modeler, errorChan chan error) {
    24  		showAppearances := func(walker *walk.CacheWalker, path string, first bool) (bool, error) {
    25  			if path != index.ToBloomPath(path) {
    26  				return false, fmt.Errorf("should not happen in showAppearances")
    27  			}
    28  
    29  			path = index.ToIndexPath(path)
    30  			if !file.FileExists(path) {
    31  				// Bloom files exist, but index files don't. It's okay.
    32  				return true, nil
    33  			}
    34  
    35  			indexChunk, err := index.OpenIndex(path, true /* check */)
    36  			if err != nil {
    37  				return false, err
    38  			}
    39  			defer indexChunk.Close()
    40  
    41  			_, err = indexChunk.File.Seek(indexChunk.AppTableStart, io.SeekStart)
    42  			if err != nil {
    43  				return false, err
    44  			}
    45  
    46  			for i := 0; i < int(indexChunk.Header.AppearanceCount); i++ {
    47  				if opts.Globals.TestMode && i > walker.MaxTests() {
    48  					continue
    49  				}
    50  				rec := types.AppRecord{}
    51  				if err := binary.Read(indexChunk.File, binary.LittleEndian, &rec); err != nil {
    52  					return false, err
    53  				}
    54  
    55  				s := types.Appearance{
    56  					BlockNumber:      rec.BlockNumber,
    57  					TransactionIndex: rec.TransactionIndex,
    58  				}
    59  
    60  				modelChan <- &s
    61  			}
    62  
    63  			return true, nil
    64  		}
    65  
    66  		walker := walk.NewCacheWalker(
    67  			chain,
    68  			opts.Globals.TestMode,
    69  			10, /* maxTests */
    70  			showAppearances,
    71  		)
    72  
    73  		if err := walker.WalkBloomFilters(blockNums); err != nil {
    74  			errorChan <- err
    75  			rCtx.Cancel()
    76  		}
    77  	}
    78  
    79  	extraOpts := map[string]any{
    80  		"appearances": true,
    81  	}
    82  	return output.StreamMany(rCtx, fetchData, opts.Globals.OutputOptsWithExtra(extraOpts))
    83  }