diff --git a/src/apps/chifra/internal/config/handle_session.go b/src/apps/chifra/internal/config/handle_dump.go similarity index 52% rename from src/apps/chifra/internal/config/handle_session.go rename to src/apps/chifra/internal/config/handle_dump.go index e4f56cfce5..47e09c19e7 100644 --- a/src/apps/chifra/internal/config/handle_session.go +++ b/src/apps/chifra/internal/config/handle_dump.go @@ -1,14 +1,19 @@ package configPkg import ( + "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/config" "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/output" "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types" ) -// HandleSession returns an empty session -func (opts *ConfigOptions) HandleSession(rCtx *output.RenderCtx) error { +// HandleDump dumps a config to the screen +func (opts *ConfigOptions) HandleDump(rCtx *output.RenderCtx) error { fetchData := func(modelChan chan types.Modeler, errorChan chan error) { - modelChan <- &types.Session{} + var s types.Config + s.Config = *config.GetRootConfig() + modelChan <- &s } + + opts.Globals.NoHeader = true return output.StreamMany(rCtx, fetchData, opts.Globals.OutputOpts()) } diff --git a/src/apps/chifra/internal/config/options.go b/src/apps/chifra/internal/config/options.go index 3500b07b47..2591bff2b2 100644 --- a/src/apps/chifra/internal/config/options.go +++ b/src/apps/chifra/internal/config/options.go @@ -28,7 +28,7 @@ import ( type ConfigOptions struct { Mode string `json:"mode,omitempty"` // Either show or edit the configuration Paths bool `json:"paths,omitempty"` // Show the configuration paths for the system - Session bool `json:"session,omitempty"` // Standin for ui code - no purpose + Dump bool `json:"dump,omitempty"` // Dump the configuration to stdout Globals globals.GlobalOptions `json:"globals,omitempty"` // The global options Conn *rpc.Connection `json:"conn,omitempty"` // The connection to the RPC server BadFlag error `json:"badFlag,omitempty"` // An error flag if needed @@ -42,7 +42,7 @@ var defaultConfigOptions = ConfigOptions{} func (opts *ConfigOptions) testLog() { logger.TestLog(len(opts.Mode) > 0, "Mode: ", opts.Mode) logger.TestLog(opts.Paths, "Paths: ", opts.Paths) - logger.TestLog(opts.Session, "Session: ", opts.Session) + logger.TestLog(opts.Dump, "Dump: ", opts.Dump) opts.Conn.TestLog(opts.getCaches()) opts.Globals.TestLog() } @@ -72,8 +72,8 @@ func ConfigFinishParseInternal(w io.Writer, values url.Values) *ConfigOptions { opts.Mode = value[0] case "paths": opts.Paths = true - case "session": - opts.Session = true + case "dump": + opts.Dump = true default: if !copy.Globals.Caps.HasKey(key) { err := validate.Usage("Invalid key ({0}) in {1} route.", key, "config") @@ -118,6 +118,9 @@ func configFinishParse(args []string) *ConfigOptions { if len(opts.Mode) == 0 { opts.Mode = "" } + if opts.Dump { + opts.Globals.Format = "json" + } // EXISTING_CODE if len(opts.Globals.Format) == 0 || opts.Globals.Format == "none" { opts.Globals.Format = defFmt diff --git a/src/apps/chifra/internal/config/output.go b/src/apps/chifra/internal/config/output.go index 5daa67a29a..15843ba199 100644 --- a/src/apps/chifra/internal/config/output.go +++ b/src/apps/chifra/internal/config/output.go @@ -56,8 +56,8 @@ func (opts *ConfigOptions) ConfigInternal(rCtx *output.RenderCtx) error { // EXISTING_CODE if opts.Paths { err = opts.HandlePaths(rCtx) - } else if opts.Session { - err = opts.HandleSession(rCtx) + } else if opts.Dump { + err = opts.HandleDump(rCtx) } else { err = opts.HandleShow(rCtx) } diff --git a/src/apps/chifra/internal/init/handle_init_download.go b/src/apps/chifra/internal/init/handle_init_download.go index d20ef7a5e5..ec6ce93756 100644 --- a/src/apps/chifra/internal/init/handle_init_download.go +++ b/src/apps/chifra/internal/init/handle_init_download.go @@ -181,7 +181,7 @@ func (opts *InitOptions) updateLocalManifest(existing, remote *manifest.Manifest } } - return copy.SaveManifest(chain, config.PathToManifest(chain)) + return copy.SaveManifest(chain, config.PathToManifestFile(chain)) } var spaces = strings.Repeat(" ", 55) diff --git a/src/apps/chifra/pkg/config/paths.go b/src/apps/chifra/pkg/config/paths.go index 780dfb9ab6..cb669a3345 100644 --- a/src/apps/chifra/pkg/config/paths.go +++ b/src/apps/chifra/pkg/config/paths.go @@ -32,8 +32,8 @@ func PathToChainConfig(chain string) (string, error) { return cfgFolder, err } -// PathToManifest returns the path to the manifest database per chain -func PathToManifest(chain string) string { +// PathToManifestFile returns the path to the manifest database per chain +func PathToManifestFile(chain string) string { return filepath.Join(PathToIndex(chain), "manifest.json") } diff --git a/src/apps/chifra/pkg/configtypes/chain_group.go b/src/apps/chifra/pkg/configtypes/chain_group.go index 8090e95a8a..e99add6df8 100644 --- a/src/apps/chifra/pkg/configtypes/chain_group.go +++ b/src/apps/chifra/pkg/configtypes/chain_group.go @@ -8,7 +8,7 @@ type ChainGroup struct { IpfsGateway string `json:"ipfsGateway" toml:"ipfsGateway,omitempty"` KeyEndpoint string `json:"keyEndpoint" toml:"keyEndpoint,omitempty"` LocalExplorer string `json:"localExplorer" toml:"localExplorer,omitempty"` - RemoteExplorer string `json:"removeExplorer" toml:"remoteExplorer,omitempty"` + RemoteExplorer string `json:"remoteExplorer" toml:"remoteExplorer,omitempty"` RpcProvider string `json:"rpcProvider" toml:"rpcProvider"` Symbol string `json:"symbol" toml:"symbol"` Scrape ScrapeSettings `json:"scrape" toml:"scrape"` diff --git a/src/apps/chifra/pkg/types/types_abi.go b/src/apps/chifra/pkg/types/types_abi.go index 79948b17fc..05c46b79c1 100644 --- a/src/apps/chifra/pkg/types/types_abi.go +++ b/src/apps/chifra/pkg/types/types_abi.go @@ -130,4 +130,8 @@ func (s *Abi) FinishUnmarshal() { } // EXISTING_CODE +func (s *Abi) ShallowCopy() Abi { + return *s +} + // EXISTING_CODE diff --git a/src/apps/chifra/pkg/types/types_chunkstats.go b/src/apps/chifra/pkg/types/types_chunkstats.go index 4cf21fd106..828c20c3ce 100644 --- a/src/apps/chifra/pkg/types/types_chunkstats.go +++ b/src/apps/chifra/pkg/types/types_chunkstats.go @@ -98,4 +98,8 @@ func (s *ChunkStats) FinishUnmarshal() { } // EXISTING_CODE +func (s *ChunkStats) ShallowCopy() ChunkStats { + return *s +} + // EXISTING_CODE diff --git a/src/apps/chifra/pkg/types/types_config.go b/src/apps/chifra/pkg/types/types_config.go new file mode 100644 index 0000000000..2946308472 --- /dev/null +++ b/src/apps/chifra/pkg/types/types_config.go @@ -0,0 +1,44 @@ +// Copyright 2016, 2024 The TrueBlocks Authors. All rights reserved. +// Use of this source code is governed by a license that can +// be found in the LICENSE file. +package types + +import ( + "encoding/json" + + "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/configtypes" +) + +type Config struct { + configtypes.Config +} + +func (s Config) String() string { + bytes, _ := json.Marshal(s) + return string(bytes) +} + +func (s *Config) Model(chain, format string, verbose bool, extraOpts map[string]any) Model { + // keys := map[string]any{} + // for key, value := range s.Keys { + // keys[key] = value + // } + c := map[string]any{} + for key, value := range s.Chains { + c[key] = value + } + return Model{ + Data: map[string]any{ + "version": s.Version, + "settings": s.Settings, + "keys": s.Keys, + "pinnging": s.Pinning, + "unchained": s.Unchained, + "chains": s.Chains, + }, + Order: []string{}, + } +} + +func (s *Config) FinishUnmarshal() { +} diff --git a/src/apps/chifra/pkg/types/types_manifest.go b/src/apps/chifra/pkg/types/types_manifest.go index 7631e71a67..cb6ebf9d42 100644 --- a/src/apps/chifra/pkg/types/types_manifest.go +++ b/src/apps/chifra/pkg/types/types_manifest.go @@ -65,4 +65,12 @@ func (s *Manifest) FinishUnmarshal() { } // EXISTING_CODE +func (s *Manifest) ShallowCopy() Manifest { + return Manifest{ + Chain: s.Chain, + Specification: s.Specification, + Version: s.Version, + } +} + // EXISTING_CODE diff --git a/src/apps/chifra/pkg/types/types_session.go b/src/apps/chifra/pkg/types/types_session.go deleted file mode 100644 index 6d98ecd184..0000000000 --- a/src/apps/chifra/pkg/types/types_session.go +++ /dev/null @@ -1,442 +0,0 @@ -package types - -import ( - "context" - "encoding/json" - "errors" - "fmt" - - "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/file" - "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/utils" - "github.com/wailsapp/wails/v2/pkg/runtime" -) - -// Session stores ephemeral things such as last window position, -// last view, and recent file list. -type Session struct { - LastChain string `json:"lastChain"` - LastFile string `json:"lastFile"` - LastFolder string `json:"lastFolder"` - LastRoute string `json:"lastRoute"` - LastSub map[string]string `json:"lastSub"` - Window Window `json:"window"` - Wizard Wizard `json:"wizard"` - Toggles Toggles `json:"toggles"` - Chain string `json:"-"` -} - -func (s Session) String() string { - bytes, _ := json.Marshal(s) - return string(bytes) -} - -func (s *Session) Model(chain, format string, verbose bool, extraOpts map[string]any) Model { - var model = map[string]any{} - var order = []string{} - - model = map[string]any{ - "lastChain": s.LastChain, - "lastFile": s.LastFile, - "lastFolder": s.LastFolder, - "lastRoute": s.LastRoute, - "window": s.Window, - "wizard": s.Wizard, - "toggles": s.Toggles, - } - order = []string{ - "lastChain", - "lastFile", - "lastFolder", - "lastRoute", - "window", - "wizard", - "toggles", - } - - return Model{model, order} -} - -func (s *Session) FinishUnmarshal() { - // EXISTING_CODE - // EXISTING_CODE -} - -func (s *Session) ShallowCopy() Session { - return *s -} - -const theTitle = "Browse by TrueBlocks" - -var defLayout = Layout{ - Header: true, - Menu: true, - Help: true, - Footer: true, -} - -var defHeader = Headers{ - Project: false, - History: true, - Monitors: false, - Names: false, - Abis: false, - Indexes: false, - Manifests: false, - Status: true, - Settings: true, -} - -var defDaemons = Daemons{ - Freshen: true, -} - -var defaultSession = Session{ - LastChain: "mainnet", - LastFile: "Untitled.tbx", - LastRoute: "/wizard", - LastSub: map[string]string{"/history": "0xf503017d7baf7fbc0fff7492b751025c6a78179b"}, - Window: Window{ - X: 0, - Y: 0, - Width: 0, - Height: 0, - Title: theTitle, - }, - Wizard: Wizard{State: Welcome}, - Toggles: Toggles{ - Layout: defLayout, - Headers: defHeader, - Daemons: defDaemons, - }, -} - -// Save saves the session to the configuration folder. -func (s *Session) Save() error { - if fn, err := utils.GetConfigFn("browse", "session.json"); err != nil { - return err - } else { - if contents, _ := json.MarshalIndent(s, "", " "); len(contents) > 0 { - _ = file.StringToAsciiFile(fn, string(contents)) - } - return nil - } -} - -var ErrLoadingSession = errors.New("error loading session") - -// Load loads the session from the configuration folder. If the file contains -// data, we return true. False otherwise. -func (s *Session) Load() error { - loaded := false - defer func() { - if !loaded { - *s = defaultSession - } else { - // Ensure a valid file (if for example the user edited it) - if s.Wizard.State == Okay && s.LastRoute == "/wizard" { - s.LastRoute = "/" - } - if s.LastChain == "" { - s.LastChain = "mainnet" - } - if s.LastFile == "" { - s.LastFile = "Untitled.tbx" - } - } - _ = s.Save() // creates the session file if it doesn't already exist - }() - - fn, err := utils.GetConfigFn("browse", "session.json") - if err != nil { - return fmt.Errorf("%w: %v", ErrLoadingSession, err) - } - - contents := file.AsciiFileToString(fn) - if len(contents) == 0 { - // This is not an error (the default session will be used) - return nil - } - - if err = json.Unmarshal([]byte(contents), s); err != nil { - return fmt.Errorf("%w: %v", ErrLoadingSession, err) - } - - loaded = true - return nil -} - -func (s *Session) SetRoute(route, subRoute string) { - s.LastRoute = route - if len(subRoute) > 0 { - s.LastSub[route] = subRoute - } - _ = s.Save() -} - -var ErrScreenNotFound = errors.New("screen not found") - -// CleanWindowSize ensures a valid window size. (If the app has never run before -// or the session fails to load its width or height will be zero.) This function -// always returns a valid window size, but it may also return an error. -func (s *Session) CleanWindowSize(ctx context.Context) (Window, error) { - // Any window size other than 0,0 is already okay. - if s.Window.Width != 0 && s.Window.Height != 0 { - return s.Window, nil - } - - ret := Window{X: 30, Y: 30, Width: 1024, Height: 768} - defer func() { - _ = s.Save() - }() - - if screens, err := runtime.ScreenGetAll(ctx); err != nil { - return ret, fmt.Errorf("error getting screens %w", err) - - } else { - var fullScreen *Window = nil - for _, screen := range screens { - if screen.IsCurrent || screen.IsPrimary { - fullScreen = &Window{ - Width: screen.Size.Width, - Height: screen.Size.Height, - } - break - } - } - if fullScreen != nil { - // We found the screen, so we can set a reasonable window size. - s.Window.X = fullScreen.Width / 6 - s.Window.Y = fullScreen.Width / 6 - s.Window.Width = (5 * fullScreen.Width) / 6 - s.Window.Height = (5 * fullScreen.Width) / 6 - } - } - return s.Window, nil -} - -type Layout struct { - Header bool `json:"header"` - Menu bool `json:"menu"` - Help bool `json:"help"` - Footer bool `json:"footer"` -} - -type Headers struct { - Project bool `json:"project"` - History bool `json:"history"` - Monitors bool `json:"monitors"` - Names bool `json:"names"` - Abis bool `json:"abis"` - Indexes bool `json:"indexes"` - Manifests bool `json:"manifests"` - Status bool `json:"status"` - Settings bool `json:"settings"` -} - -type Daemons struct { - Freshen bool `json:"freshen"` - Scraper bool `json:"scraper"` - Ipfs bool `json:"ipfs"` -} - -type Toggles struct { - Layout Layout `json:"layout"` - Headers Headers `json:"headers"` - Daemons Daemons `json:"daemons"` -} - -func (t *Toggles) IsOn(which string) bool { - if which == "" { - which = "project" - } - switch which { - case "header": - return t.Layout.Header - case "menu": - return t.Layout.Menu - case "help": - return t.Layout.Help - case "footer": - return t.Layout.Footer - case "project": - return t.Headers.Project - case "history": - return t.Headers.History - case "monitors": - return t.Headers.Monitors - case "names": - return t.Headers.Names - case "abis": - return t.Headers.Abis - case "indexes": - return t.Headers.Indexes - case "manifests": - return t.Headers.Manifests - case "status": - return t.Headers.Status - case "settings": - return t.Headers.Settings - case "freshen": - return t.Daemons.Freshen - case "scraper": - return t.Daemons.Scraper - case "ipfs": - return t.Daemons.Ipfs - } - return false -} - -func (t *Toggles) SetState(which string, onOff bool) { - if which == "" { - which = "project" - } - switch which { - case "header": - t.Layout.Header = onOff - case "menu": - t.Layout.Menu = onOff - case "help": - t.Layout.Help = onOff - case "footer": - t.Layout.Footer = onOff - case "project": - t.Headers.Project = onOff - case "history": - t.Headers.History = onOff - case "monitors": - t.Headers.Monitors = onOff - case "names": - t.Headers.Names = onOff - case "abis": - t.Headers.Abis = onOff - case "indexes": - t.Headers.Indexes = onOff - case "manifests": - t.Headers.Manifests = onOff - case "status": - t.Headers.Status = onOff - case "settings": - t.Headers.Settings = onOff - case "freshen": - t.Daemons.Freshen = onOff - case "scraper": - t.Daemons.Scraper = onOff - case "ipfs": - t.Daemons.Ipfs = onOff - } -} - -// Window stores the last position and title of the window -type Window struct { - X int `json:"x"` - Y int `json:"y"` - Width int `json:"width"` - Height int `json:"height"` - Title string `json:"title"` -} - -func (w *Window) String() string { - bytes, _ := json.Marshal(w) - return string(bytes) -} - -type Wizard struct { - State WizState `json:"state"` -} - -var stateOrder = []WizState{ - Welcome, - Error, - TomlOkay, - RpcOkay, - BloomsOkay, - IndexOkay, - Okay, -} - -func (w *Wizard) Step(step WizStep) { - switch step { - case Reset: - w.State = Error - case Previous: - if w.State == TomlOkay { - w.State = Welcome - } else { - for i := range stateOrder { - if stateOrder[i] == w.State && i > 0 { - w.State = stateOrder[i-1] - break - } - } - } - case Next: - if w.State == Welcome { - w.State = TomlOkay - } else { - for i := range stateOrder { - if stateOrder[i] == w.State && i < len(stateOrder)-1 { - w.State = stateOrder[i+1] - break - } - } - } - case Finish: - w.State = Okay - } -} - -type WizState string - -const ( - Welcome WizState = "welcome" - TomlOkay WizState = "tomlOkay" - RpcOkay WizState = "rpcOkay" - BloomsOkay WizState = "bloomsOkay" - IndexOkay WizState = "indexOkay" - Error WizState = "error" - Okay WizState = "okay" -) - -// String returns the string representation of the WizState. -func (s WizState) String() string { - return string(s) -} - -// AllStates - all possible WizStates for the frontend codegen -var AllStates = []struct { - Value WizState `json:"value"` - TSName string `json:"tsName"` -}{ - {Welcome, "WELCOME"}, - {TomlOkay, "TOMLOKAY"}, - {RpcOkay, "RPCOKAY"}, - {BloomsOkay, "BLOOMSOKAY"}, - {IndexOkay, "INDEXOKAY"}, - {Error, "ERROR"}, - {Okay, "OKAY"}, -} - -type WizStep string - -const ( - Reset WizStep = "Reset" - Previous WizStep = "Previous" - Next WizStep = "Next" - Finish WizStep = "Finish" -) - -// String returns the string representation of the Step. -func (s WizStep) String() string { - return string(s) -} - -// AllSteps - all possible steps for the frontend codegen -var AllSteps = []struct { - Value WizStep `json:"value"` - TSName string `json:"tsName"` -}{ - {Reset, "RESET"}, - {Previous, "PREVIOUS"}, - {Next, "NEXT"}, - {Finish, "FINISH"}, -} diff --git a/src/apps/chifra/pkg/types/types_status.go b/src/apps/chifra/pkg/types/types_status.go index e4bc105b9f..34ff54a13f 100644 --- a/src/apps/chifra/pkg/types/types_status.go +++ b/src/apps/chifra/pkg/types/types_status.go @@ -157,6 +157,7 @@ func (s *Status) ShallowCopy() Status { s.Caches = nil ret := *s s.Caches = caches + ret.Chain = s.Chain return ret }