diff --git a/.github/workflows/contribs.yml b/.github/workflows/contribs.yml index 8fdcce9332c..f64e2ef27f7 100644 --- a/.github/workflows/contribs.yml +++ b/.github/workflows/contribs.yml @@ -30,4 +30,4 @@ jobs: with: modulepath: contribs/${{ matrix.program }} secrets: - codecov-token: ${{ secrets.CODECOV_TOKEN }} \ No newline at end of file + codecov-token: ${{ secrets.CODECOV_TOKEN }} diff --git a/contribs/Makefile b/contribs/Makefile index bfd1fcb9889..726ba627af4 100644 --- a/contribs/Makefile +++ b/contribs/Makefile @@ -3,6 +3,8 @@ help: @echo "Available make commands:" @cat Makefile | grep '^[a-z][^:]*:' | cut -d: -f1 | sort | sed 's/^/ /' +programs=$(wildcard */) + # command to run dependency utilities, like goimports. rundep=go run -modfile ../misc/devdeps/go.mod @@ -25,15 +27,29 @@ GOTEST_FLAGS ?= -v -p 1 -timeout=30m ######################################## # Dev tools .PHONY: install -install: install.gnomd install.gnodev install.gnofaucet +install: + @set -e; for program in $(programs); do ( set -e; \ + echo "[+] make -C $$program install"; \ + $(MAKE) -C $$program install; \ + ); done -install.gnomd:; cd gnomd && go install . -install.gnodev:; $(MAKE) -C ./gnodev install -install.gnofaucet:; $(MAKE) -C ./gnofaucet install +######################################## +# Test suite +.PHONY: test +test: + @set -e; for program in $(programs); do ( set -e; \ + echo "[+] make -C $$program test"; \ + $(MAKE) -C $$program test; \ + ); done -.PHONY: clean -clean: - rm -rf build +######################################## +# Lint +.PHONY: lint +lint: + @set -e; for program in $(programs); do ( set -e; \ + echo "[+] make -C $$program lint"; \ + $(MAKE) -C $$program lint; \ + ); done ######################################## # Dev tools @@ -51,17 +67,3 @@ tidy: cd $$dir; \ go mod tidy -v; \ ); done - -######################################## -# Test suite -.PHONY: test -test: test.gnodev -test.gnodev: - $(MAKE) -C ./gnodev test - -######################################## -# Lint -.PHONY: test -lint: lint.gnodev -lint.gnodev: - $(MAKE) -C ./gnodev test diff --git a/contribs/gnodev/main.go b/contribs/gnodev/main.go new file mode 100644 index 00000000000..cdb741719f4 --- /dev/null +++ b/contribs/gnodev/main.go @@ -0,0 +1,378 @@ +package main + +import ( + "context" + "flag" + "fmt" + "io" + "net" + "net/http" + "os" + "path/filepath" + "time" + + "github.com/fsnotify/fsnotify" + "github.com/gnolang/gno/contribs/gnodev/pkg/dev" + gnodev "github.com/gnolang/gno/contribs/gnodev/pkg/dev" + "github.com/gnolang/gno/contribs/gnodev/pkg/rawterm" + "github.com/gnolang/gno/gno.land/pkg/gnoweb" + "github.com/gnolang/gno/gnovm/pkg/gnoenv" + "github.com/gnolang/gno/gnovm/pkg/gnomod" + "github.com/gnolang/gno/tm2/pkg/commands" + tmlog "github.com/gnolang/gno/tm2/pkg/log" + osm "github.com/gnolang/gno/tm2/pkg/os" +) + +const ( + NodeLogName = "Node" + WebLogName = "GnoWeb" + KeyPressLogName = "KeyPress" + HotReloadLogName = "HotReload" +) + +type devCfg struct { + webListenerAddr string + minimal bool + verbose bool + noWatch bool +} + +var defaultDevOptions = &devCfg{ + webListenerAddr: "127.0.0.1:8888", +} + +func main() { + cfg := &devCfg{} + + stdio := commands.NewDefaultIO() + cmd := commands.NewCommand( + commands.Metadata{ + Name: "gnodev", + ShortUsage: "gnodev [flags] [path ...]", + ShortHelp: "Runs an in-memory node and gno.land web server for development purposes.", + LongHelp: `The gnodev command starts an in-memory node and a gno.land web interface +primarily for realm package development. It automatically loads the example folder and any +additional specified paths.`, + }, + cfg, + func(_ context.Context, args []string) error { + return execDev(cfg, args, stdio) + }) + + if err := cmd.ParseAndRun(context.Background(), os.Args[1:]); err != nil { + fmt.Fprintf(os.Stderr, "%+v\n", err) + os.Exit(1) + } +} + +func (c *devCfg) RegisterFlags(fs *flag.FlagSet) { + fs.StringVar( + &c.webListenerAddr, + "web-listener", + defaultDevOptions.webListenerAddr, + "web server listening address", + ) + + fs.BoolVar( + &c.minimal, + "minimal", + defaultDevOptions.verbose, + "do not load example folder packages", + ) + + fs.BoolVar( + &c.verbose, + "verbose", + defaultDevOptions.verbose, + "verbose output when deving", + ) + + fs.BoolVar( + &c.noWatch, + "no-watch", + defaultDevOptions.noWatch, + "do not watch for files change", + ) +} + +func execDev(cfg *devCfg, args []string, io commands.IO) error { + ctx, cancel := context.WithCancelCause(context.Background()) + defer cancel(nil) + + // guess root dir + gnoroot := gnoenv.RootDir() + + // Check and Parse packages + pkgpaths, err := parseArgsPackages(args) + if err != nil { + return fmt.Errorf("unable to parse package paths: %w", err) + } + + if !cfg.minimal { + examplesDir := filepath.Join(gnoroot, "examples") + pkgpaths = append(pkgpaths, examplesDir) + } + + // Setup Raw Terminal + rt, restore, err := setupRawTerm(io) + if err != nil { + return fmt.Errorf("unable to init raw term: %w", err) + } + defer restore() + + // Setup trap signal + osm.TrapSignal(func() { + restore() + cancel(nil) + }) + + // Setup Dev Node + // XXX: find a good way to export or display node logs + devNode, err := setupDevNode(ctx, rt, pkgpaths, gnoroot) + if err != nil { + return err + } + defer devNode.Close() + + rt.Taskf(NodeLogName, "Listener: %s\n", devNode.GetRemoteAddress()) + rt.Taskf(NodeLogName, "Default Address: %s\n", gnodev.DefaultCreator.String()) + rt.Taskf(NodeLogName, "Chain ID: %s\n", devNode.Config().ChainID()) + + // Setup packages watcher + pathChangeCh := make(chan []string, 1) + go func() { + defer close(pathChangeCh) + + cancel(runPkgsWatcher(ctx, cfg, devNode.ListPkgs(), pathChangeCh)) + }() + + // Setup GnoWeb listener + l, err := net.Listen("tcp", cfg.webListenerAddr) + if err != nil { + return fmt.Errorf("unable to listen to %q: %w", cfg.webListenerAddr, err) + } + defer l.Close() + + // Run GnoWeb server + go func() { + cancel(serveGnoWebServer(l, devNode, rt)) + }() + + rt.Taskf(WebLogName, "Listener: http://%s\n", l.Addr()) + + // GnoDev should be ready, run event loop + rt.Taskf("[Ready]", "for commands and help, press `h`") + + // Run the main event loop + return runEventLoop(ctx, cfg, rt, devNode, pathChangeCh) +} + +// XXX: Automatize this the same way command does +func printHelper(rt *rawterm.RawTerm) { + rt.Taskf("Helper", ` +Gno Dev Helper: + h, H Help - display this message + r, R Reload - Reload all packages to take change into account. + Ctrl+R Reset - Reset application state. + Ctrl+C Exit - Exit the application +`) +} + +func runEventLoop(ctx context.Context, + cfg *devCfg, + rt *rawterm.RawTerm, + dnode *dev.Node, + pathsCh <-chan []string, +) error { + nodeOut := rt.NamespacedWriter(NodeLogName) + keyOut := rt.NamespacedWriter(KeyPressLogName) + + keyPressCh := listenForKeyPress(keyOut, rt) + for { + var err error + + select { + case <-ctx.Done(): + return context.Cause(ctx) + case paths, ok := <-pathsCh: + if !ok { + return nil + } + + if cfg.verbose { + for _, path := range paths { + rt.Taskf(HotReloadLogName, "path %q has been modified", path) + } + } + + fmt.Fprintln(nodeOut, "Loading package updates...") + if err = dnode.UpdatePackages(paths...); err != nil { + checkForError(rt, err) + continue + } + + fmt.Fprintln(nodeOut, "Reloading...") + err = dnode.Reload(ctx) + checkForError(rt, err) + case key, ok := <-keyPressCh: + if !ok { + return nil + } + + if cfg.verbose { + fmt.Fprintf(keyOut, "<%s>\n", key.String()) + } + + switch key.Upper() { + case rawterm.KeyH: + printHelper(rt) + case rawterm.KeyR: + fmt.Fprintln(nodeOut, "Reloading all packages...") + checkForError(nodeOut, dnode.ReloadAll(ctx)) + case rawterm.KeyCtrlR: + fmt.Fprintln(nodeOut, "Reseting state...") + checkForError(nodeOut, dnode.Reset(ctx)) + case rawterm.KeyCtrlC: + return nil + default: + } + + // Listen for the next keypress + keyPressCh = listenForKeyPress(keyOut, rt) + } + } +} + +func runPkgsWatcher(ctx context.Context, cfg *devCfg, pkgs []gnomod.Pkg, changedPathsCh chan<- []string) error { + watcher, err := fsnotify.NewWatcher() + if err != nil { + return fmt.Errorf("unable to watch files: %w", err) + } + + if cfg.noWatch { + // noop watcher, wait until context has been cancel + <-ctx.Done() + return ctx.Err() + } + + for _, pkg := range pkgs { + if err := watcher.Add(pkg.Dir); err != nil { + return fmt.Errorf("unable to watch %q: %w", pkg.Dir, err) + } + } + + const timeout = time.Millisecond * 500 + + var debounceTimer <-chan time.Time + pathList := []string{} + + for { + select { + case <-ctx.Done(): + return ctx.Err() + case watchErr := <-watcher.Errors: + return fmt.Errorf("watch error: %w", watchErr) + case <-debounceTimer: + changedPathsCh <- pathList + // Reset pathList and debounceTimer + pathList = []string{} + debounceTimer = nil + case evt := <-watcher.Events: + if evt.Op != fsnotify.Write { + continue + } + + pathList = append(pathList, evt.Name) + debounceTimer = time.After(timeout) + } + } +} + +func setupRawTerm(io commands.IO) (rt *rawterm.RawTerm, restore func() error, err error) { + rt = rawterm.NewRawTerm() + + restore, err = rt.Init() + if err != nil { + return nil, nil, err + } + + // correctly format output for terminal + io.SetOut(commands.WriteNopCloser(rt)) + + return rt, restore, nil +} + +// setupDevNode initializes and returns a new DevNode. +func setupDevNode(ctx context.Context, rt *rawterm.RawTerm, pkgspath []string, gnoroot string) (*gnodev.Node, error) { + nodeOut := rt.NamespacedWriter("Node") + + logger := tmlog.NewTMLogger(nodeOut) + logger.SetLevel(tmlog.LevelError) + return gnodev.NewDevNode(ctx, logger, pkgspath) +} + +// setupGnowebServer initializes and starts the Gnoweb server. +func serveGnoWebServer(l net.Listener, dnode *gnodev.Node, rt *rawterm.RawTerm) error { + var server http.Server + + webConfig := gnoweb.NewDefaultConfig() + webConfig.RemoteAddr = dnode.GetRemoteAddress() + + loggerweb := tmlog.NewTMLogger(rt.NamespacedWriter("GnoWeb")) + loggerweb.SetLevel(tmlog.LevelDebug) + + app := gnoweb.MakeApp(loggerweb, webConfig) + + server.ReadHeaderTimeout = 60 * time.Second + server.Handler = app.Router + + if err := server.Serve(l); err != nil { + return fmt.Errorf("unable to serve GnoWeb: %w", err) + } + + return nil +} + +func parseArgsPackages(args []string) (paths []string, err error) { + paths = make([]string, len(args)) + for i, arg := range args { + abspath, err := filepath.Abs(arg) + if err != nil { + return nil, fmt.Errorf("invalid path %q: %w", arg, err) + } + + ppath, err := gnomod.FindRootDir(abspath) + if err != nil { + return nil, fmt.Errorf("unable to find root dir of %q: %w", abspath, err) + } + + paths[i] = ppath + } + + return paths, nil +} + +func listenForKeyPress(w io.Writer, rt *rawterm.RawTerm) <-chan rawterm.KeyPress { + cc := make(chan rawterm.KeyPress, 1) + go func() { + defer close(cc) + key, err := rt.ReadKeyPress() + if err != nil { + fmt.Fprintf(w, "unable to read keypress: %s\n", err.Error()) + return + } + + cc <- key + }() + + return cc +} + +func checkForError(w io.Writer, err error) { + if err != nil { + fmt.Fprintf(w, "[ERROR] - %s\n", err.Error()) + return + } + + fmt.Fprintln(w, "[DONE]") +} diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index d839091d328..4eef344e2a7 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -138,8 +138,154 @@ func (n *Node) Client() client.Client { return n.client } -func (n *Node) GetRemoteAddress() string { - return n.Node.Config().RPC.ListenAddress +func (d *Node) GetNodeReadiness() <-chan struct{} { + return gnoland.GetNodeReadiness(d.Node) +} + +func (d *Node) GetRemoteAddress() string { + return d.Node.Config().RPC.ListenAddress +} + +func (d *Node) UpdatePackages(paths ...string) error { + for _, path := range paths { + // list all packages from target path + pkgslist, err := gnomod.ListPkgs(path) + if err != nil { + return fmt.Errorf("failed to list gno packages for %q: %w", path, err) + } + + for _, pkg := range pkgslist { + d.pkgs[pkg.Dir] = pkg + } + } + + return nil +} + +func (d *Node) Reset(ctx context.Context) error { + if d.Node.IsRunning() { + if err := d.Node.Stop(); err != nil { + return fmt.Errorf("unable to stop the node: %w", err) + } + } + + // generate genesis + txs, err := d.pkgs.Load(DefaultCreator, DefaultFee, nil) + if err != nil { + return fmt.Errorf("unable to load pkgs: %w", err) + } + + genesis := gnoland.GnoGenesisState{ + Balances: DefaultBalance, + Txs: txs, + } + + return d.reset(ctx, genesis) +} + +func (d *Node) ReloadAll(ctx context.Context) error { + pkgs := d.ListPkgs() + paths := make([]string, len(pkgs)) + for i, pkg := range pkgs { + paths[i] = pkg.Dir + } + + if err := d.UpdatePackages(paths...); err != nil { + return fmt.Errorf("unable to reload packages: %w", err) + } + + return d.Reload(ctx) +} + +func (d *Node) Reload(ctx context.Context) error { + // save current state + state, err := d.saveState(ctx) + if err != nil { + return fmt.Errorf("unable to save state: %s", err.Error()) + } + + // stop the node if not already stopped + if d.Node.IsRunning() { + if err := d.Node.Stop(); err != nil { + return fmt.Errorf("unable to stop the node: %w", err) + } + } + + // generate genesis + txs, err := d.pkgs.Load(DefaultCreator, DefaultFee, nil) + if err != nil { + return fmt.Errorf("unable to load pkgs: %w", err) + } + + genesis := gnoland.GnoGenesisState{ + Balances: DefaultBalance, + Txs: txs, + } + + // try to reset the node + if err := d.reset(ctx, genesis); err != nil { + return fmt.Errorf("unable to reset the node: %w", err) + } + + for _, tx := range state { + // skip empty transaction + if len(tx.Msgs) == 0 { + continue + } + + if err := d.SendTransaction(&tx); err != nil { + return fmt.Errorf("unable to send transaction: %w", err) + } + } + + return nil +} + +func (d *Node) reset(ctx context.Context, genesis gnoland.GnoGenesisState) error { + var err error + + recoverError := func() { + if r := recover(); r != nil { + panicErr, ok := r.(error) + if !ok { + panic(r) + } + + err = panicErr + } + } + + createNode := func() { + defer recoverError() + + node, nodeErr := newNode(d.logger, genesis) + if nodeErr != nil { + err = fmt.Errorf("unable to create node: %w", nodeErr) + return + } + + if startErr := node.Start(); startErr != nil { + err = fmt.Errorf("unable to start the node: %w", startErr) + return + } + + d.Node = node + } + + // create the node + createNode() + if err != nil { + return err + } + + // wait for readiness + select { + case <-d.GetNodeReadiness(): // ok + case <-ctx.Done(): + return ctx.Err() + } + + return err } // GetBlockTransactions returns the transactions contained diff --git a/contribs/gnofaucet/Makefile b/contribs/gnofaucet/Makefile index 03ef409cac9..b520a17182f 100644 --- a/contribs/gnofaucet/Makefile +++ b/contribs/gnofaucet/Makefile @@ -5,3 +5,9 @@ install: .PHONY: build build: go build -o build/gnofaucet . + +test: + @echo "XXX: add tests" + +lint: + @echo "XXX: add lint" diff --git a/contribs/gnokeykc/Makefile b/contribs/gnokeykc/Makefile new file mode 100644 index 00000000000..f953631b529 --- /dev/null +++ b/contribs/gnokeykc/Makefile @@ -0,0 +1,8 @@ +install: + go install . + +test: + @echo "XXX: add tests" + +lint: + @echo "XXX: add lint" diff --git a/contribs/gnomd/Makefile b/contribs/gnomd/Makefile new file mode 100644 index 00000000000..f953631b529 --- /dev/null +++ b/contribs/gnomd/Makefile @@ -0,0 +1,8 @@ +install: + go install . + +test: + @echo "XXX: add tests" + +lint: + @echo "XXX: add lint" diff --git a/contribs/gnotray/Makefile b/contribs/gnotray/Makefile new file mode 100644 index 00000000000..8d2399f2b64 --- /dev/null +++ b/contribs/gnotray/Makefile @@ -0,0 +1,11 @@ +install: + go install . + +run: + go run . + +test: + @echo "XXX: add tests" + +lint: + @echo "XXX: add lint" diff --git a/contribs/gnotray/README.md b/contribs/gnotray/README.md new file mode 100644 index 00000000000..471ebcc1310 --- /dev/null +++ b/contribs/gnotray/README.md @@ -0,0 +1,15 @@ +# GnoTray + +Your essential Gno companion in the system tray. + +## Running GnoTray on MacOS + +Run the binary with `go run .`. + +TODO: screenshot. + +TODO: package gnotray as a macOS app. + +## Install on Linux, Windows, and other platforms + +TODO: test and explain. diff --git a/contribs/gnotray/go.mod b/contribs/gnotray/go.mod new file mode 100644 index 00000000000..4266dd34798 --- /dev/null +++ b/contribs/gnotray/go.mod @@ -0,0 +1,81 @@ +module github.com/gnolang/gno/contribs/gnotray + +go 1.21 + +require ( + github.com/getlantern/systray v1.2.2 + github.com/gnolang/gno v0.0.0-00010101000000-000000000000 + github.com/gnolang/gno/contribs/gnodev v0.0.0-00010101000000-000000000000 + github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 +) + +replace ( + github.com/gnolang/gno => ../.. + github.com/gnolang/gno/contribs/gnodev => ../gnodev +) + +require ( + dario.cat/mergo v1.0.0 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.3 // indirect + github.com/btcsuite/btcd/btcutil v1.1.5 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cockroachdb/apd/v3 v3.2.1 // indirect + github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 // indirect + github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 // indirect + github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 // indirect + github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 // indirect + github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 // indirect + github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f // indirect + github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-stack/stack v1.8.0 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/gorilla/mux v1.8.1 // indirect + github.com/gorilla/securecookie v1.1.1 // indirect + github.com/gorilla/sessions v1.2.1 // indirect + github.com/gorilla/websocket v1.5.1 // indirect + github.com/gotuna/gotuna v0.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect + github.com/libp2p/go-buffer-pool v0.1.0 // indirect + github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/peterbourgon/ff/v3 v3.4.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/rs/cors v1.10.1 // indirect + github.com/rs/xid v1.5.0 // indirect + github.com/stretchr/testify v1.9.0 // indirect + github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect + github.com/zondax/hid v0.9.2 // indirect + github.com/zondax/ledger-go v0.14.3 // indirect + go.etcd.io/bbolt v1.3.9 // indirect + go.opentelemetry.io/otel v1.25.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.25.0 // indirect + go.opentelemetry.io/otel/metric v1.25.0 // indirect + go.opentelemetry.io/otel/sdk v1.25.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.25.0 // indirect + go.opentelemetry.io/otel/trace v1.25.0 // indirect + go.opentelemetry.io/proto/otlp v1.1.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + go.uber.org/zap/exp v0.2.0 // indirect + golang.org/x/crypto v0.21.0 // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.16.0 // indirect + golang.org/x/net v0.23.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/term v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.19.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect + google.golang.org/grpc v1.63.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/contribs/gnotray/go.sum b/contribs/gnotray/go.sum new file mode 100644 index 00000000000..554d0116979 --- /dev/null +++ b/contribs/gnotray/go.sum @@ -0,0 +1,264 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= +github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd h1:js1gPwhcFflTZ7Nzl7WHaOTlTr5hIrR4n1NM4v9n4Kw= +github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= +github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= +github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= +github.com/btcsuite/btcd/btcec/v2 v2.3.3 h1:6+iXlDKE8RMtKsvK0gshlXIuPbyWM/h84Ensb7o3sC0= +github.com/btcsuite/btcd/btcec/v2 v2.3.3/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= +github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= +github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8= +github.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= +github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= +github.com/cosmos/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5nvue4rK+yM= +github.com/cosmos/ledger-cosmos-go v0.13.3/go.mod h1:HENcEP+VtahZFw38HZ3+LS3Iv5XV6svsnkk9vdJtLr8= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4= +github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY= +github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 h1:6uJ+sZ/e03gkbqZ0kUG6mfKoqDb4XMAzMIwlajq19So= +github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A= +github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 h1:guBYzEaLz0Vfc/jv0czrr2z7qyzTOGC9hiQ0VC+hKjk= +github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7/go.mod h1:zx/1xUUeYPy3Pcmet8OSXLbF47l+3y6hIPpyLWoR9oc= +github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 h1:micT5vkcr9tOVk1FiH8SWKID8ultN44Z+yzd2y/Vyb0= +github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o= +github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 h1:XYzSdCbkzOC0FDNrgJqGRo8PCMFOBFL9py72DRs7bmc= +github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA= +github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f h1:wrYrQttPS8FHIRSlsrcuKazukx/xqO/PpLZzZXsF+EA= +github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA= +github.com/getlantern/systray v1.2.2 h1:dCEHtfmvkJG7HZ8lS/sLklTH4RKUcIsKrAD9sThoEBE= +github.com/getlantern/systray v1.2.2/go.mod h1:pXFOI1wwqwYXEhLPm9ZGjS2u/vVELeIgNMY5HvhHhcE= +github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 h1:GKvsK3oLWG9B1GL7WP/VqwM6C92j5tIvB844oggL9Lk= +github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216/go.mod h1:xJhtEL7ahjM1WJipt89gel8tHzfIl/LyMY+lCYh38d8= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/csrf v1.7.0/go.mod h1:+a/4tCmqhG6/w4oafeAZ9pEa3/NZOWYVbD9fV0FwIQA= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/gotuna/gotuna v0.6.0 h1:N1lQKXEi/lwRp8u3sccTYLhzOffA4QasExz/1M5Riws= +github.com/gotuna/gotuna v0.6.0/go.mod h1:F/ecRt29ChB6Ycy1AFIBpBiMNK0j7Heq+gFbLWquhjc= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= +github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= +github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= +github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ= +github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= +github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= +github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc= +github.com/peterbourgon/ff/v3 v3.4.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= +github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U= +github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= +github.com/zondax/ledger-go v0.14.3 h1:wEpJt2CEcBJ428md/5MgSLsXLBos98sBOyxNmCjfUCw= +github.com/zondax/ledger-go v0.14.3/go.mod h1:IKKaoxupuB43g4NxeQmbLXv7T9AlQyie1UpHb342ycI= +go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= +go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= +go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k= +go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.25.0 h1:hDKnobznDpcdTlNzO0S/owRB8tyVr1OoeZZhDoqY+Cs= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.25.0/go.mod h1:kUDQaUs1h8iTIHbQTk+iJRiUvSfJYMMKTtMCaiVu7B0= +go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA= +go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s= +go.opentelemetry.io/otel/sdk v1.25.0 h1:PDryEJPC8YJZQSyLY5eqLeafHtG+X7FWnf3aXMtxbqo= +go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw= +go.opentelemetry.io/otel/sdk/metric v1.25.0 h1:7CiHOy08LbrxMAp4vWpbiPcklunUshVpAvGBrdDRlGw= +go.opentelemetry.io/otel/sdk/metric v1.25.0/go.mod h1:LzwoKptdbBBdYfvtGCzGwk6GWMA3aUzBOwtQpR6Nz7o= +go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM= +go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I= +go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= +go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap/exp v0.2.0 h1:FtGenNNeCATRB3CmB/yEUnjEFeJWpB/pMcy7e2bKPYs= +go.uber.org/zap/exp v0.2.0/go.mod h1:t0gqAIdh1MfKv9EwN/dLwfZnJxe9ITAZN78HEWPFWDQ= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= +golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= +golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.63.0 h1:WjKe+dnvABXyPJMD7KDNLxtoGk5tgk+YFWN6cBWjZE8= +google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/contribs/gnotray/main.go b/contribs/gnotray/main.go new file mode 100644 index 00000000000..75a6c8673ec --- /dev/null +++ b/contribs/gnotray/main.go @@ -0,0 +1,200 @@ +package main + +import ( + "context" + "fmt" + "log" + "net" + "net/http" + "os" + "path/filepath" + "time" + + gnodev "github.com/gnolang/gno/contribs/gnodev/pkg/dev" + "github.com/gnolang/gno/gno.land/pkg/gnoweb" + "github.com/gnolang/gno/gno.land/pkg/integration" + "github.com/gnolang/gno/gnovm/pkg/gnoenv" + tmlog "github.com/gnolang/gno/tm2/pkg/log" + osm "github.com/gnolang/gno/tm2/pkg/os" + + "github.com/getlantern/systray" + "github.com/skratchdot/open-golang/open" +) + +func main() { + systray.Run(onReady, onExit) +} + +const ( + startGnodevStr = "Start Gnodev..." + stopGnodevStr = "Stop Gnodev..." + openGnolandStr = "Open Gnoland RPC in browser" + openGnowebStr = "Open Gnoweb in browser" + openGnodevStr = "Open Gnodev Folder" + helpStr = "Help" + quitStr = "Quit" +) + +func onReady() { + var ( + gnowebListener net.Listener + node *gnodev.Node + nodeCancel context.CancelCauseFunc = func(error) {} // noop + ) + + systray.SetTitle("Gnodev 👋") // TODO: use a small icon instead of a title. + systray.SetTooltip("Local Gno.land Node Manager") + + // TODO: when ready -> green dot + // TODO: when error -> red dot + + mStartGnodev := systray.AddMenuItem(startGnodevStr, "") + mStopGnodev := systray.AddMenuItem(stopGnodevStr, "") + mStopGnodev.Disable() + mOpenGnolandRPC := systray.AddMenuItem(openGnolandStr, "") + mOpenGnolandRPC.Disable() + mOpenGnoweb := systray.AddMenuItem(openGnowebStr, "") + mOpenGnoweb.Disable() + mOpenFolder := systray.AddMenuItem(openGnodevStr, "") + mOpenGnoweb.Disable() + systray.AddSeparator() + // mSettings := systray.AddMenuItem("Settings", "Settings") + // mSettings.AddSubMenuItemCheckbox("Open at login", "TODO", false) + // mSettings.AddSubMenuItemCheckbox("Debug/Verbose", "TODO", false) + mHelp := systray.AddMenuItem(helpStr, "") + mQuit := systray.AddMenuItem(quitStr, "") + + // show git sha version + // show port + // show metrics (memory, txs, height, etc) + // check for update, recommend rebuilding + // "reset realms' state" + // "save archive/dump" + + _ = integration.TestingInMemoryNode + // node, remoteAddr := integration.TestingInMemoryNode(t, log.NewNopLogger(), config) + // println(node, remoteAddr) + + go func() { + for { + select { + case <-mStartGnodev.ClickedCh: + systray.SetTitle("Gnodev 🪫") + mStartGnodev.SetTitle("Starting...") + mStartGnodev.Disable() + ctx, cancel := context.WithCancelCause(context.Background()) + nodeCancel = cancel + defer cancel(nil) + gnoroot := gnoenv.RootDir() + examplesDir := filepath.Join(gnoroot, "examples") + // pkgpaths, err := parseArgsPackages(args); if err + // pkgpaths = append(pkgpaths, examplesDir) + pkgpaths := []string{examplesDir} + osm.TrapSignal(func() { + cancel(nil) + }) + nodeOut := os.Stdout + logger := tmlog.NewTMLogger(nodeOut) + logger.SetLevel(tmlog.LevelError) + var err error + node, err = gnodev.NewDevNode(ctx, logger, pkgpaths) + if err != nil { + panic(err) + } + + log.Printf("Listener: %s\n", node.GetRemoteAddress()) + log.Printf("Default Address: %s\n", gnodev.DefaultCreator.String()) + log.Printf("Chain ID: %s\n", node.Config().ChainID()) + + gnowebListen := ":8000" // TODO: make custom? + + // TODO: auto-reload + + // gnoweb + gnowebListener, err = net.Listen("tcp", gnowebListen) + if err != nil { + panic(fmt.Errorf("unable to listen to %q: %w", gnowebListen, err)) + } + serveGnoWebServer := func(l net.Listener, dnode *gnodev.Node) error { + var server http.Server + + webConfig := gnoweb.NewDefaultConfig() + webConfig.RemoteAddr = dnode.GetRemoteAddress() + + loggerweb := tmlog.NewTMLogger(os.Stdout) + loggerweb.SetLevel(tmlog.LevelDebug) + + app := gnoweb.MakeApp(loggerweb, webConfig) + + server.ReadHeaderTimeout = 60 * time.Second + server.Handler = app.Router + + if err := server.Serve(l); err != nil { + return fmt.Errorf("unable to serve GnoWeb: %w", err) + } + + return nil + } + go func() { + cancel(serveGnoWebServer(gnowebListener, node)) + }() + log.Printf("Listener: http://%s\n", gnowebListener.Addr().String()) + + go func() { + started := time.Now() + ticker := time.NewTicker(1 * time.Second) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + since := formatDuration(time.Since(started)) + mStartGnodev.SetTitle("Running... " + since) + } + } + }() + mStartGnodev.SetTitle("Running...") + mStopGnodev.Enable() + systray.SetTitle("Gnodev 🟢") + case <-mStopGnodev.ClickedCh: + mStopGnodev.Disable() + mStopGnodev.SetTitle("Stopping...") + nodeCancel(nil) + node.Close() + mStopGnodev.SetTitle("Stopped") + + case <-mOpenGnolandRPC.ClickedCh: + // open.Run("http://127.0.0.1:XXX/") + log.Println("NOT IMPLEMENTED") + case <-mOpenGnoweb.ClickedCh: + // open.Run("http://127.0.0.1:XXX/") + log.Println("NOT IMPLEMENTED") + case <-mOpenFolder.ClickedCh: + // open.Open("./...") + log.Println("NOT IMPLEMENTED") + case <-mHelp.ClickedCh: + open.Run("https://github.com/gnolang/gno/tree/master/contribs/gnolandtray") + case <-mQuit.ClickedCh: + mStartGnodev.SetTitle("Stopping...") + systray.Quit() + return + } + } + }() +} + +func onExit() { + // clean up here + log.Println("Exited.") +} + +func formatDuration(d time.Duration) string { + totalSeconds := int(d.Seconds()) + seconds := totalSeconds % 60 + minutes := (totalSeconds / 60) % 60 + hours := totalSeconds / 3600 + + return fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds) +}