Skip to content

Commit

Permalink
Starts to incorporate parts of trueblocks-node
Browse files Browse the repository at this point in the history
  • Loading branch information
tjayrush committed Jan 7, 2025
1 parent 98bba17 commit f683096
Show file tree
Hide file tree
Showing 21 changed files with 1,098 additions and 312 deletions.
15 changes: 9 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
file
save
coverage
x
.vscode/launch.json
*.exe
*.exe~
*.dll
*.so
*.dylib
*.test
*.out
# vendor/
go.work
go.work.sum
.env
shit
x
khedra
khedra.log
config.yaml
.DS_Store
file
save
coverage
trueblocks-node
config.yaml
trueBlocks.toml
121 changes: 119 additions & 2 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"log/slog"
"os"

"github.com/TrueBlocks/trueblocks-khedra/v2/pkg/config"
"github.com/TrueBlocks/trueblocks-khedra/v2/pkg/types"
"github.com/urfave/cli/v2"
)
Expand All @@ -18,7 +17,7 @@ type KhedraApp struct {
}

func NewKhedraApp() *KhedraApp {
cfg, err := config.LoadConfig()
cfg, _, err := LoadConfig()
if err != nil {
log.Fatalf("failed to load config: %v", err)
}
Expand All @@ -40,3 +39,121 @@ func NewKhedraApp() *KhedraApp {
func (k *KhedraApp) Run() error {
return k.Cli.Run(os.Args)
}

/*
// Feature is a type that represents the features of the app
type Feature string
func (f Feature) String() string {
return string(f)
}
const (
// Scrape represents the scraper feature. The scraper may not be disabled.
Scrape Feature = "scrape"
// Api represents the API feature. The api is On by default. Disable it
// with the `--api off` option.
Api Feature = "api"
// Ipfs represents the IPFS feature. The ipfs is Off by default. Turn it
// on with the `--ipfs on` option.
Ipfs Feature = "ipfs"
// Monitor represents the monitor feature. The monitor is Off by default. Enable
// it with the `--monitor on` option.
Monitor Feature = "monitor"
)
// InitMode is a type that represents the initialization for the Unchained Index. It
// applies to the `--init` option.
type InitMode string
const (
// All cause the initialization to download both the bloom filters and the index
// portions of the Unchained Index.
All InitMode = "all"
// Blooms cause the initialization to download only the bloom filters portion of
// the Unchained Index.
Blooms InitMode = "blooms"
// None cause the app to not download any part of the Unchained Index. It will be
// built from scratch with the scraper.
None InitMode = "none"
)
// OnOff is a type that represents a boolean value that can be either "on" or "off".
type OnOff string
const (
// On is the "on" value for a feature. It applies to the `--monitor` and `--api` options.
On OnOff = "on"
// Off is the "off" value for a feature. It applies to the `--monitor` and `--api` options.
Off OnOff = "off"
)
// App is the main struct for the app. It contains the logger, the configuration, and the
// state of the app.
type App struct {
Logger *slog.Logger
Config config.Config
InitMode InitMode
Scrape OnOff
Api OnOff
Ipfs OnOff
Monitor OnOff
Sleep int
BlockCnt int
LogLevel slog.Level
}
// NewApp creates a new App instance with the default values.
func NewApp() *App {
blockCnt := 2000
if bc, ok := os.LookupEnv("TB_NODE_BLOCKCNT"); ok {
blockCnt = int(base.MustParseUint64(bc))
}
customLogger, logLevel := NewCustomLogger()
app := &App{
Logger: customLogger,
LogLevel: logLevel,
Sleep: 6,
Scrape: Off,
Api: Off,
Ipfs: Off,
Monitor: Off,
InitMode: Blooms,
BlockCnt: blockCnt,
Config: config.Config{
ProviderMap: make(map[string]string),
},
}
return app
}
// IsOn returns true if the given feauture is enabled. It returns false otherwise.
func (a *App) IsOn(feature Feature) bool {
switch feature {
case Scrape:
return a.Scrape == On
case Api:
return a.Api == On
case Ipfs:
return a.Ipfs == On
case Monitor:
return a.Monitor == On
}
return false
}
// State returns "on" or "off" depending if the feature is on or off.
func (a *App) State(feature Feature) string {
if a.IsOn(feature) {
return "on"
}
return "off"
}
func (a *App) Fatal(err error) {
fmt.Printf("Error: %s%s%s\n", colors.Red, err.Error(), colors.Off)
os.Exit(1)
}
*/
190 changes: 190 additions & 0 deletions app/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,193 @@ func initializeCli() *cli.App {
},
}
}

/*
var (
ErrMissingArgument = errors.New("missing argument")
ErrInvalidValue = errors.New("invalid value")
)
func (a *App) ParseArgs() (bool, []services.Servicer, error) {
var activeServices []services.Servicer
hasValue := func(i int) bool {
return i+1 < len(os.Args) && os.Args[i+1][0] != '-'
}
handleInit := func(i int) (int, error) {
if hasValue(i) {
if mode, err := validateMode(os.Args[i+1]); err == nil {
a.InitMode = mode
return i + 1, nil
} else {
return i, fmt.Errorf("parsing --init: %w", err)
}
}
return i, fmt.Errorf("%w for --init", ErrMissingArgument)
}
handleService := func(i int, feature Feature) (int, error) {
if hasValue(i) {
if mode, err := validateOnOff(os.Args[i+1]); err == nil {
switch feature {
case Scrape:
a.Scrape = mode
if a.IsOn(Scrape) {
scrapeSvc := services.NewScrapeService(
a.Logger,
string(a.InitMode),
a.Config.Targets,
a.Sleep,
a.BlockCnt,
)
activeServices = append(activeServices, scrapeSvc)
}
case Api:
a.Api = mode
if a.IsOn(Api) {
apiSvc := services.NewApiService(a.Logger)
activeServices = append(activeServices, apiSvc)
}
case Ipfs:
a.Ipfs = mode
if a.IsOn(Ipfs) {
ipfsSvc := services.NewIpfsService(a.Logger)
activeServices = append(activeServices, ipfsSvc)
}
case Monitor:
a.Monitor = mode
if a.IsOn(Monitor) {
monSvc := services.NewMonitorService(a.Logger)
activeServices = append(activeServices, monSvc)
}
}
return i + 1, nil
} else {
return i, fmt.Errorf("parsing --%s: %w", feature.String(), err)
}
}
return i, fmt.Errorf("%w for --%s", ErrMissingArgument, feature.String())
}
handleSleep := func(i int) (int, error) {
if hasValue(i) {
if sleep, err := validateSleep(os.Args[i+1]); err == nil {
a.Sleep = sleep
return i + 1, nil
} else {
return i, fmt.Errorf("parsing --sleep: %w", err)
}
}
return i, fmt.Errorf("%w for --sleep", ErrMissingArgument)
}
a.Logger.Debug("Parsing command line arguments", "args", os.Args)
for i := 1; i < len(os.Args); i++ {
arg := os.Args[i]
var err error
switch arg {
case "--scrape":
if i, err = handleService(i, Scrape); err != nil {
return true, nil, err
}
case "--api":
if i, err = handleService(i, Api); err != nil {
return true, nil, err
}
case "--ipfs":
if i, err = handleService(i, Ipfs); err != nil {
return true, nil, err
}
case "--monitor":
if i, err = handleService(i, Monitor); err != nil {
return true, nil, err
}
case "--init":
i, err = handleInit(i)
case "--sleep":
i, err = handleSleep(i)
case "--version":
fmt.Println("trueblocks-node " + sdk.Version())
return false, nil, nil
default:
if arg != "--help" {
return true, nil, fmt.Errorf("unknown option:%s\n%s", os.Args[i], helpText)
}
fmt.Printf("%s\n", helpText)
return false, nil, nil
}
if err != nil {
return true, nil, err
}
}
if len(activeServices) == 0 && os.Getenv("TEST_MODE") != "true" {
return true, nil, fmt.Errorf("you must enable at least one of the services\n%s", helpText)
}
controlService := services.NewControlService(a.Logger)
activeServices = append([]services.Servicer{controlService}, activeServices...)
a.Logger.Debug("Command line parsing complete", "services", len(activeServices))
return true, activeServices, nil
}
func validateEnum[T ~string](value T, validOptions []T, name string) (T, error) {
for _, option := range validOptions {
if value == option {
return value, nil
}
}
return value, fmt.Errorf("invalid value for %s: %s", name, value)
}
func validateMode(value string) (InitMode, error) {
return validateEnum(InitMode(value), []InitMode{All, Blooms, None}, "mode")
}
func validateOnOff(value string) (OnOff, error) {
return validateEnum(OnOff(value), []OnOff{On, Off}, "onOff")
}
func validateSleep(value string) (int, error) {
var sleep int
if _, err := fmt.Sscanf(value, "%d", &sleep); err != nil || sleep < 1 {
return 1, fmt.Errorf("invalid value for sleep: %s", value)
}
return sleep, nil
}
const helpText = `Usage: trueblocks-node <options>
Options:
---------
--init [all|blooms|none*] download from the unchained index smart contract (default: none)
--scrape [on|off*] enable/disable the Unchained Index scraper (default: off)
--api [on|off*] enable/disable API server (default: off)
--ipfs [on|off*] enable/disable IPFS daemon (default: off)
--monitor [on|off*] enable/disable address monitoring (currently disabled, default: off)
--sleep int the number of seconds to sleep between updates (default: 30)
--version display the version string
--help display this help text
Notes:
-------
If --scrape is on, --init must be either blooms or all. If you choose --all, you must always choose --all.
Environment:
-------------
You MUST export the following values to the environment:
TB_NODE_DATADIR: A directory to store the indexer's data (required, created if necessary)
TB_NODE_MAINNETRPC: A valid RPC endpoint for Ethereum mainnet (required)
You MAY also export these environment variables:
TB_NODE_CHAINS: A comma-separated list of chains to index (default: "mainnet")
TB_NODE_<CHAIN>RPC: For each CHAIN in the TB_NODE_CHAINS list, a valid RPC endpoint
(example: TB_NODE_SEPOLIARPC=http://localhost:8548)
You may put these values in a .env file in the current folder. See env.example.`
*/
Loading

0 comments on commit f683096

Please sign in to comment.