github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/internal/scrape/validate.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 scrapePkg 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/logger" 16 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/utils" 17 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/validate" 18 ) 19 20 // TODO: this is a much more elegant way to do error strings: 21 // TODO: https://github.com/storj/uplink/blob/v1.7.0/bucket.go#L19 22 23 func (opts *ScrapeOptions) validateScrape() error { 24 chain := opts.Globals.Chain 25 testMode := opts.Globals.TestMode 26 27 opts.testLog() 28 29 if opts.BadFlag != nil { 30 return opts.BadFlag 31 } 32 33 if !config.IsChainConfigured(chain) { 34 return validate.Usage("chain {0} is not properly configured.", chain) 35 } 36 37 if opts.Notify { 38 if !NotifyConfigured() { 39 return validate.Usage("The {0} feature is {1}.", "--notify", "not properly configured. See the README.md") 40 } 41 if !config.IpfsRunning() { 42 return validate.Usage("The {0} option requires {1}.", "--notify", "a locally running IPFS daemon") 43 } 44 } else if !testMode && NotifyConfigured() && !opts.DryRun { 45 msg := validate.Usage("The notify feature is configured but not running. Enable it with the {0} flag.", "--notify").Error() 46 logger.Warn(msg) 47 } 48 49 err, ok := opts.Conn.IsNodeTracing() 50 if !ok { 51 return validate.Usage("{0} requires {1}, try {2} instead. Error: {3}", "chifra scrape", "tracing", "chifra init", err.Error()) 52 } 53 54 if !opts.Conn.IsNodeArchive() { 55 return validate.Usage("{0} requires {1}, try {2} instead.", "chifra scrape", "an archive node", "chifra init") 56 } 57 58 if opts.Globals.IsApiMode() { 59 return validate.Usage("chifra scrape is not available in API mode") 60 } 61 62 if opts.Sleep < .25 { 63 return validate.Usage("The {0} option ({1}) must {2}.", "--sleep", fmt.Sprintf("%f", opts.Sleep), "be at least .25") 64 } 65 66 if opts.BlockCnt < 10 { 67 return validate.Usage("Specify at least {0} with {0}.", "10 blocks per round", "chifra scrape") 68 } 69 70 // We can't really test this code, so we just report and quit 71 if opts.Globals.TestMode && !opts.DryRun { 72 return validate.Usage("Cannot test block scraper") 73 } 74 75 meta, err := opts.Conn.GetMetaData(opts.Globals.TestMode) 76 if err != nil { 77 return err 78 } 79 m := base.Max(meta.Ripe, base.Max(meta.Staging, meta.Finalized)) + 1 80 if !opts.DryRun && m > meta.Latest { 81 fmt.Println(validate.Usage("The index ({0}) is ahead of the chain ({1}).", fmt.Sprintf("%d", m), fmt.Sprintf("%d", meta.Latest))) 82 } 83 84 if len(opts.Publisher) > 0 { 85 err := validate.ValidateExactlyOneAddr([]string{opts.Publisher}) 86 if err != nil { 87 return err 88 } 89 } 90 91 ret := opts.Globals.Validate() 92 93 pidPath := opts.getPidFilePath() 94 if file.FileExists(pidPath) { 95 pid := base.MustParseInt64(file.AsciiFileToString(pidPath)) 96 // fmt.Println("Pid file exists with contents:", pid) 97 if running, err := utils.PidExists(pid); err == nil && running { 98 return validate.Usage("The {0} is already running. If it is not, remove {1} and try again.", "scraper", pidPath) 99 } else if err != nil { 100 return validate.Usage("The {0} is already running. If it is not, remove {1} and try again.", "scraper", pidPath) 101 } 102 // fmt.Println("Removing pid file") 103 os.Remove(pidPath) 104 } 105 // If we've gotten this far, we're the only one running. As we enter the forever 106 // loop, we want to make sure no-one else runs. We do this by writing our pid to 107 // a file. Note that this probably doesn't work in the server. 108 if err := os.MkdirAll(filepath.Dir(pidPath), 0700); err != nil { 109 return fmt.Errorf("creating temp directory: %w", err) 110 } 111 if err := file.StringToAsciiFile(pidPath, fmt.Sprintf("%d", os.Getpid())); err != nil { 112 return fmt.Errorf("creating scrape.pid file: %w", err) 113 } 114 115 return ret 116 }