github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/internal/init/handle_init.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 initPkg
     6  
     7  import (
     8  	"fmt"
     9  	"os"
    10  	"path/filepath"
    11  
    12  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
    13  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/config"
    14  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/file"
    15  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/history"
    16  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger"
    17  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/manifest"
    18  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/output"
    19  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
    20  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/walk"
    21  )
    22  
    23  // HandleInit initializes local copy of UnchainedIndex by downloading manifests and chunks
    24  func (opts *InitOptions) HandleInit(rCtx *output.RenderCtx) error {
    25  	// Make the code below cleaner...
    26  	chain := opts.Globals.Chain
    27  
    28  	// TODO: BOGUS - IF THE SCRAPER IS RUNNING, THIS WILL CAUSE PROBLEMS
    29  	// Make sure that the temporary scraper folders are empty, so that, when the
    30  	// scraper starts, it starts on the correct block.
    31  	cleanList := []string{"ripe", "unripe", "maps", "staging"}
    32  	isHeadless := os.Getenv("TB_NODE_HEADLESS") == "true"
    33  	if isHeadless {
    34  		cleanList = []string{"ripe", "unripe"}
    35  	}
    36  	_ = file.CleanFolder(chain, config.PathToIndex(chain), cleanList)
    37  
    38  	existing, err := manifest.LoadManifest(chain, opts.PublisherAddr, manifest.LocalCache)
    39  	if err != nil {
    40  		return err
    41  	}
    42  
    43  	remote, err := manifest.LoadManifest(chain, opts.PublisherAddr, manifest.FromContract)
    44  	if err != nil {
    45  		return err
    46  	}
    47  
    48  	if err = opts.updateLocalManifest(existing, remote); err != nil {
    49  		return err
    50  	}
    51  
    52  	// Get the list of things we need to download
    53  	chunksToDownload, nToDownload, nDeleted, err := opts.prepareDownloadList(chain, remote, []base.Blknum{})
    54  	if err != nil {
    55  		return err
    56  	}
    57  
    58  	// Tell the user what we're doing
    59  	logger.InfoTable("Unchained Index:", config.GetUnchained().SmartContract)
    60  	logger.InfoTable("PreferredPublisher:", opts.Publisher)
    61  	logger.InfoTable("Specification:", manifest.Specification())
    62  	logger.InfoTable("Config Folder:", config.MustGetPathToChainConfig(chain))
    63  	logger.InfoTable("Index Folder:", config.PathToIndex(chain))
    64  	logger.InfoTable("Chunks in manifest:", fmt.Sprintf("%d", len(remote.Chunks)))
    65  	logger.InfoTable("Files deleted:", fmt.Sprintf("%d", nDeleted))
    66  	logger.InfoTable("Files downloaded:", fmt.Sprintf("%d", nToDownload))
    67  
    68  	historyFile := filepath.Join(config.PathToCache(chain), "tmp/history.txt")
    69  	if opts.All && !history.FromHistoryBool(historyFile, "init") {
    70  		_ = history.ToHistory(historyFile, "init", "true")
    71  	}
    72  
    73  	// Open a channel to receive a message when all the blooms have been downloaded...
    74  	bloomsDoneChannel := make(chan bool)
    75  	defer close(bloomsDoneChannel)
    76  
    77  	// Open a channel to receive a message when all the indexes have been downloaded (if we're downloading them)
    78  	indexDoneChannel := make(chan bool)
    79  	defer close(indexDoneChannel)
    80  
    81  	getChunks := func(chunkType walk.CacheType) {
    82  		failedChunks, cancelled := opts.downloadAndReportProgress(chunksToDownload, chunkType, nToDownload)
    83  		if cancelled {
    84  			// The user hit the control+c, we don't want to continue...
    85  			return
    86  		}
    87  
    88  		// The download finished...
    89  		if len(failedChunks) > 0 {
    90  			// ...if there were failed downloads, try them again (3 times if necessary)...
    91  			retry(failedChunks, 3, func(items []types.ChunkRecord) ([]types.ChunkRecord, bool) {
    92  				logger.Info("Retrying", len(items), "bloom(s)")
    93  				return opts.downloadAndReportProgress(items, chunkType, nToDownload)
    94  			})
    95  		}
    96  	}
    97  
    98  	// Set up a go routine to download the bloom filters...
    99  	go func() {
   100  		getChunks(walk.Index_Bloom)
   101  		bloomsDoneChannel <- true
   102  	}()
   103  
   104  	// TODO: BOGUS - WHY DOES THERE NEED TO BE TWO OF THESE?
   105  	// Set up another go routine to download the index chunks if the user told us to...
   106  	go func() {
   107  		getChunks(walk.Index_Final)
   108  		indexDoneChannel <- true
   109  	}()
   110  
   111  	// Wait for the index to download. This will block until getChunks for index chunks returns
   112  	<-indexDoneChannel
   113  
   114  	// Wait for the bloom filters to download. This will block until getChunks for blooms returns
   115  	<-bloomsDoneChannel
   116  
   117  	if nDeleted+nToDownload > 0 {
   118  		logger.Warn("The on-disk index has changed. You must invalidate your monitor cache by removing it.")
   119  	}
   120  
   121  	return nil
   122  }
   123  
   124  // HandleShow initializes local copy of UnchainedIndex by downloading manifests and chunks
   125  func (opts *InitOptions) HandleShow(rCtx *output.RenderCtx) error {
   126  	return opts.HandleInit(rCtx)
   127  }