github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/internal/tokens/options.go (about)

     1  // Copyright 2016, 2024 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   * Parts of this file were auto generated. Edit only those parts of
     6   * the code inside of 'EXISTING_CODE' tags.
     7   */
     8  
     9  package tokensPkg
    10  
    11  import (
    12  	// EXISTING_CODE
    13  	"encoding/json"
    14  	"io"
    15  	"net/http"
    16  	"net/url"
    17  	"strings"
    18  
    19  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/internal/globals"
    20  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
    21  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/caps"
    22  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/identifiers"
    23  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger"
    24  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/rpc"
    25  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/validate"
    26  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/walk"
    27  	// EXISTING_CODE
    28  )
    29  
    30  // TokensOptions provides all command options for the chifra tokens command.
    31  type TokensOptions struct {
    32  	Addrs    []string                 `json:"addrs,omitempty"`    // Two or more addresses (0x...), the first is an ERC20 token, balances for the rest are reported
    33  	Blocks   []string                 `json:"blocks,omitempty"`   // An optional list of one or more blocks at which to report balances, defaults to 'latest'
    34  	BlockIds []identifiers.Identifier `json:"blockIds,omitempty"` // Block identifiers
    35  	Parts    []string                 `json:"parts,omitempty"`    // Which parts of the token information to retrieve
    36  	ByAcct   bool                     `json:"byAcct,omitempty"`   // Consider each address an ERC20 token except the last, whose balance is reported for each token
    37  	Changes  bool                     `json:"changes,omitempty"`  // Only report a balance when it changes from one block to the next
    38  	NoZero   bool                     `json:"noZero,omitempty"`   // Suppress the display of zero balance accounts
    39  	Globals  globals.GlobalOptions    `json:"globals,omitempty"`  // The global options
    40  	Conn     *rpc.Connection          `json:"conn,omitempty"`     // The connection to the RPC server
    41  	BadFlag  error                    `json:"badFlag,omitempty"`  // An error flag if needed
    42  	// EXISTING_CODE
    43  	// EXISTING_CODE
    44  }
    45  
    46  var defaultTokensOptions = TokensOptions{}
    47  
    48  // testLog is used only during testing to export the options for this test case.
    49  func (opts *TokensOptions) testLog() {
    50  	logger.TestLog(len(opts.Addrs) > 0, "Addrs: ", opts.Addrs)
    51  	logger.TestLog(len(opts.Blocks) > 0, "Blocks: ", opts.Blocks)
    52  	logger.TestLog(len(opts.Parts) > 0, "Parts: ", opts.Parts)
    53  	logger.TestLog(opts.ByAcct, "ByAcct: ", opts.ByAcct)
    54  	logger.TestLog(opts.Changes, "Changes: ", opts.Changes)
    55  	logger.TestLog(opts.NoZero, "NoZero: ", opts.NoZero)
    56  	opts.Conn.TestLog(opts.getCaches())
    57  	opts.Globals.TestLog()
    58  }
    59  
    60  // String implements the Stringer interface
    61  func (opts *TokensOptions) String() string {
    62  	b, _ := json.MarshalIndent(opts, "", "  ")
    63  	return string(b)
    64  }
    65  
    66  // tokensFinishParseApi finishes the parsing for server invocations. Returns a new TokensOptions.
    67  func tokensFinishParseApi(w http.ResponseWriter, r *http.Request) *TokensOptions {
    68  	values := r.URL.Query()
    69  	if r.Header.Get("User-Agent") == "testRunner" {
    70  		values.Set("testRunner", "true")
    71  	}
    72  	return TokensFinishParseInternal(w, values)
    73  }
    74  
    75  func TokensFinishParseInternal(w io.Writer, values url.Values) *TokensOptions {
    76  	copy := defaultTokensOptions
    77  	copy.Globals.Caps = getCaps()
    78  	opts := &copy
    79  	for key, value := range values {
    80  		switch key {
    81  		case "addrs":
    82  			for _, val := range value {
    83  				s := strings.Split(val, " ") // may contain space separated items
    84  				opts.Addrs = append(opts.Addrs, s...)
    85  			}
    86  		case "blocks":
    87  			for _, val := range value {
    88  				s := strings.Split(val, " ") // may contain space separated items
    89  				opts.Blocks = append(opts.Blocks, s...)
    90  			}
    91  		case "parts":
    92  			for _, val := range value {
    93  				s := strings.Split(val, " ") // may contain space separated items
    94  				opts.Parts = append(opts.Parts, s...)
    95  			}
    96  		case "byAcct":
    97  			opts.ByAcct = true
    98  		case "changes":
    99  			opts.Changes = true
   100  		case "noZero":
   101  			opts.NoZero = true
   102  		default:
   103  			if !copy.Globals.Caps.HasKey(key) {
   104  				err := validate.Usage("Invalid key ({0}) in {1} route.", key, "tokens")
   105  				if opts.BadFlag == nil || opts.BadFlag.Error() > err.Error() {
   106  					opts.BadFlag = err
   107  				}
   108  			}
   109  		}
   110  	}
   111  	opts.Conn = opts.Globals.FinishParseApi(w, values, opts.getCaches())
   112  
   113  	// EXISTING_CODE
   114  	if len(opts.Addrs) == 1 && len(opts.Parts) == 0 {
   115  		opts.Parts = append(opts.Parts, "all")
   116  	}
   117  	if len(opts.Blocks) == 0 {
   118  		if opts.Globals.TestMode {
   119  			opts.Blocks = []string{"17000000"}
   120  		} else {
   121  			opts.Blocks = []string{"latest"}
   122  		}
   123  	}
   124  	// EXISTING_CODE
   125  	opts.Addrs, _ = opts.Conn.GetEnsAddresses(opts.Addrs)
   126  
   127  	return opts
   128  }
   129  
   130  // tokensFinishParse finishes the parsing for command line invocations. Returns a new TokensOptions.
   131  func tokensFinishParse(args []string) *TokensOptions {
   132  	// remove duplicates from args if any (not needed in api mode because the server does it).
   133  	dedup := map[string]int{}
   134  	if len(args) > 0 {
   135  		tmp := []string{}
   136  		for _, arg := range args {
   137  			if value := dedup[arg]; value == 0 {
   138  				tmp = append(tmp, arg)
   139  			}
   140  			dedup[arg]++
   141  		}
   142  		args = tmp
   143  	}
   144  
   145  	defFmt := "txt"
   146  	opts := GetOptions()
   147  	opts.Conn = opts.Globals.FinishParse(args, opts.getCaches())
   148  
   149  	// EXISTING_CODE
   150  	if len(args) > 0 {
   151  		// The first argument in the list is the token, so not a dup...
   152  		cnt := dedup[args[0]]
   153  		if cnt > 1 {
   154  			// The first token was present more than once, which is okay for
   155  			// tokens who happen to own themselves, so add it back in.
   156  			args = append(args, args[0])
   157  		}
   158  
   159  		// we need to separate blocks from addresses
   160  		for _, arg := range args {
   161  			if base.IsValidAddress(arg) {
   162  				opts.Addrs = append(opts.Addrs, arg)
   163  			} else {
   164  				opts.Blocks = append(opts.Blocks, arg)
   165  			}
   166  		}
   167  	}
   168  	if len(opts.Addrs) == 1 && len(opts.Parts) == 0 {
   169  		opts.Parts = append(opts.Parts, "all")
   170  	}
   171  	if len(opts.Blocks) == 0 {
   172  		if opts.Globals.TestMode {
   173  			opts.Blocks = []string{"17000000"}
   174  		} else {
   175  			opts.Blocks = []string{"latest"}
   176  		}
   177  	}
   178  	// EXISTING_CODE
   179  	opts.Addrs, _ = opts.Conn.GetEnsAddresses(opts.Addrs)
   180  	if len(opts.Globals.Format) == 0 || opts.Globals.Format == "none" {
   181  		opts.Globals.Format = defFmt
   182  	}
   183  
   184  	return opts
   185  }
   186  
   187  func GetOptions() *TokensOptions {
   188  	// EXISTING_CODE
   189  	// EXISTING_CODE
   190  	return &defaultTokensOptions
   191  }
   192  
   193  func getCaps() caps.Capability {
   194  	var capabilities caps.Capability // capabilities for chifra tokens
   195  	capabilities = capabilities.Add(caps.Default)
   196  	capabilities = capabilities.Add(caps.Caching)
   197  	capabilities = capabilities.Add(caps.Names)
   198  	// EXISTING_CODE
   199  	// EXISTING_CODE
   200  	return capabilities
   201  }
   202  
   203  func ResetOptions(testMode bool) {
   204  	// We want to keep writer between command file calls
   205  	w := GetOptions().Globals.Writer
   206  	opts := TokensOptions{}
   207  	globals.SetDefaults(&opts.Globals)
   208  	opts.Globals.TestMode = testMode
   209  	opts.Globals.Writer = w
   210  	opts.Globals.Caps = getCaps()
   211  	defaultTokensOptions = opts
   212  }
   213  
   214  func (opts *TokensOptions) getCaches() (caches map[walk.CacheType]bool) {
   215  	// EXISTING_CODE
   216  	caches = map[walk.CacheType]bool{
   217  		walk.Cache_Tokens: true,
   218  	}
   219  	// EXISTING_CODE
   220  	return
   221  }
   222  
   223  // EXISTING_CODE
   224  // EXISTING_CODE