Skip to content

Commit

Permalink
fix and refactor gex app
Browse files Browse the repository at this point in the history
  • Loading branch information
Pantani authored and Pantani committed Mar 25, 2024
1 parent 9c90202 commit 355778f
Show file tree
Hide file tree
Showing 8 changed files with 480 additions and 123 deletions.
14 changes: 12 additions & 2 deletions explorer/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package cmd

import "github.com/ignite/cli/v28/ignite/services/plugin"

const flagRPCAddress = "rpc-address"

// GetCommands returns the list of explorer app commands.
func GetCommands() []*plugin.Command {
return []*plugin.Command{
Expand All @@ -11,9 +13,17 @@ func GetCommands() []*plugin.Command {
Aliases: []string{"e"},
Commands: []*plugin.Command{
{
Use: "gex [rpc_url]",
Short: "Run gex",
Use: "gex",
Short: "Run gex explorer",
Aliases: []string{"g"},
Flags: []*plugin.Flag{
{
Name: flagRPCAddress,
Usage: "The chain RPC address",
DefaultValue: "http://localhost:26657",
Type: plugin.FlagTypeString,
},
},
},
},
},
Expand Down
49 changes: 20 additions & 29 deletions explorer/cmd/gex.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,40 @@ package cmd

import (
"context"
"net/url"
"os"

"github.com/ignite/cli/v28/ignite/pkg/errors"
"github.com/ignite/cli/v28/ignite/services/plugin"

"github.com/ignite/apps/explorer/gex"
"github.com/ignite/apps/explorer/pkg/xurl"
)

const maxNumArgs = 1

// ExecuteGex executes explorer gex subcommand.
func ExecuteGex(ctx context.Context, cmd *plugin.ExecutedCommand) error {
argc := len(cmd.Args)
if argc > maxNumArgs {
return errors.Errorf("accepts at most %d arg(s), received %d", maxNumArgs, argc)
flags, err := cmd.NewFlags()
if err != nil {
return err
}

ssl := false
host := "localhost"
port := "26657"

if argc == 1 {
rpcURL, err := url.Parse(cmd.Args[0])
if err != nil {
return errors.Wrapf(err, "failed to parse RPC URL %s", cmd.Args[0])
}

ssl = rpcURL.Scheme == "https"
host = rpcURL.Hostname()
port = rpcURL.Port()
if port == "" {
if ssl {
port = "443"
} else {
port = "80"
}
}
rpcAddress, _ := flags.GetString(flagRPCAddress)
if err != nil {
return errors.Errorf("could not get --%s flag: %s", flagRPCAddress, err)
}

g, err := gex.New()
rpcURL, err := xurl.Parse(rpcAddress)
if err != nil {
return errors.Wrapf(err, "failed to parse RPC URL %s", rpcAddress)
}

g, err := gex.New(
gex.WithHost(rpcURL.Hostname()),
gex.WithPort(rpcURL.Port()),
gex.WithSSL(xurl.IsSSL(rpcURL)),
)
if err != nil {
return errors.Wrap(err, "failed to initialize Gex")
}
return g.Run(ctx, os.Stdout, os.Stderr, host, port, ssl)
defer g.Cleanup()

return g.Run(ctx)
}
111 changes: 90 additions & 21 deletions explorer/gex/gex.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,84 @@ import (
"github.com/ignite/ignite-files/gex"
)

// Gex represents the Gex binary structure.
type Gex struct {
path string
cleanup func()
type (
// Gex represents the Gex binary structure.
Gex struct {
path string
host string
port string
ssl bool
stdout io.Writer
stderr io.Writer
stdin io.Reader
cleanup func()
}
// Option configures the gex options.
Option func(*Gex)
)

// newGex returns a Gex with default options.
func newGex() *Gex {
return &Gex{
host: "localhost",
port: "26657",
ssl: false,
stdout: os.Stdout,
stderr: os.Stderr,
stdin: os.Stdin,
cleanup: nil,
}
}

// WithHost set the gex host.
func WithHost(host string) Option {
return func(m *Gex) {
m.host = host
}
}

// WithPort set the gex port.
func WithPort(port string) Option {
return func(m *Gex) {
m.port = port
}
}

// WithSSL set gex SSL.
func WithSSL(ssl bool) Option {
return func(m *Gex) {
m.ssl = ssl
}
}

// WithStdout set gex Stdout.
func WithStdout(stdout io.Writer) Option {
return func(m *Gex) {
m.stdout = stdout
}
}

// WithStdErr set gex StdErr.
func WithStdErr(stderr io.Writer) Option {
return func(m *Gex) {
m.stderr = stderr
}
}

// WithStdIn set gex StdIn.
func WithStdIn(stdin io.Reader) Option {
return func(m *Gex) {
m.stdin = stdin
}
}

// New returns the Gex binary executable.
func New() (*Gex, error) {
func New(options ...Option) (*Gex, error) {
g := newGex()
for _, apply := range options {
apply(g)
}

// untar the binary.
gzr, err := gzip.NewReader(bytes.NewReader(gex.Binary()))
if err != nil {
Expand All @@ -40,15 +110,12 @@ func New() (*Gex, error) {
return nil, errors.Wrap(err, "failed to read tar entry")
}

path, cleanup, err := localfs.SaveBytesTemp(binary, "gex", 0o755)
g.path, g.cleanup, err = localfs.SaveBytesTemp(binary, "gex", 0o755)
if err != nil {
return nil, errors.Wrap(err, "failed to save gex binary as temp file")
}

return &Gex{
path: path,
cleanup: cleanup,
}, nil
return g, nil
}

// Cleanup clean the temporary Gex binary.
Expand All @@ -58,18 +125,20 @@ func (g *Gex) Cleanup() error {
}

// Run runs gex with provided parameters.
func (g *Gex) Run(ctx context.Context, stdout, stderr io.Writer, host, port string, ssl bool) error {
cmd := []string{g.path}

if host != "" {
cmd = append(cmd, "-h", host)
}
if port != "" {
cmd = append(cmd, "-p", port)
func (g *Gex) Run(ctx context.Context) error {
cmd := []string{
g.path,
"-h", g.host,
"-p", g.port,
}
if ssl {
if g.ssl {
cmd = append(cmd, "-s")
}

return exec.Exec(ctx, cmd, exec.StepOption(step.Stdout(stdout)), exec.StepOption(step.Stderr(stderr)))
return exec.Exec(
ctx,
cmd,
exec.StepOption(step.Stdout(g.stdout)),
exec.StepOption(step.Stderr(g.stderr)),
exec.StepOption(step.Stdin(g.stdin)),
)
}
90 changes: 90 additions & 0 deletions explorer/integration/app_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package integration_test

import (
"bytes"
"context"
"os"
"path/filepath"
"testing"
"time"

pluginsconfig "github.com/ignite/cli/v28/ignite/config/plugins"
"github.com/ignite/cli/v28/ignite/pkg/cmdrunner/step"
"github.com/ignite/cli/v28/ignite/services/plugin"
envtest "github.com/ignite/cli/v28/integration"
"github.com/stretchr/testify/require"
)

func TestGexExplorer(t *testing.T) {
var (
require = require.New(t)
env = envtest.New(t)
app = env.Scaffold("github.com/test/explorer")
servers = app.RandomizeServerPorts()
ctx, cancel = context.WithCancel(env.Ctx())
)

dir, err := os.Getwd()
require.NoError(err)
pluginPath := filepath.Join(filepath.Dir(filepath.Dir(dir)), "explorer")

env.Must(env.Exec("add explorer plugin locally",
step.NewSteps(step.New(
step.Exec(envtest.IgniteApp, "app", "install", pluginPath),
step.Workdir(app.SourcePath()),
)),
))

// One local plugin expected
assertLocalPlugins(t, app, []pluginsconfig.Plugin{{Path: pluginPath}})
assertGlobalPlugins(t, nil)

var (
isRetrieved bool
got string
output = &bytes.Buffer{}
stepCtx, stepCancel = context.WithCancel(env.Ctx())
)
steps := step.NewSteps(
step.New(
step.Stdout(output),
step.Workdir(app.SourcePath()),
step.PreExec(func() error {
return env.IsAppServed(ctx, servers.API)
}),
step.Exec(envtest.IgniteApp, "e", "gex", "--rpc-address", servers.RPC),
step.InExec(func() error {
time.Sleep(15 * time.Second)
stepCancel()
return nil
}),
),
)

go func() {
defer cancel()
isRetrieved = env.Exec("run gex", steps, envtest.ExecRetry(), envtest.ExecCtx(stepCtx))
}()

env.Must(app.Serve("should serve", envtest.ExecCtx(ctx)))

if !isRetrieved {
t.FailNow()
}
}

func assertLocalPlugins(t *testing.T, app envtest.App, expectedPlugins []pluginsconfig.Plugin) {
t.Helper()
cfg, err := pluginsconfig.ParseDir(app.SourcePath())
require.NoError(t, err)
require.ElementsMatch(t, expectedPlugins, cfg.Apps, "unexpected local apps")
}

func assertGlobalPlugins(t *testing.T, expectedPlugins []pluginsconfig.Plugin) {
t.Helper()
cfgPath, err := plugin.PluginsPath()
require.NoError(t, err)
cfg, err := pluginsconfig.ParseDir(cfgPath)
require.NoError(t, err)
require.ElementsMatch(t, expectedPlugins, cfg.Apps, "unexpected global apps")
}
68 changes: 0 additions & 68 deletions explorer/integration/gex_test.go

This file was deleted.

Loading

0 comments on commit 355778f

Please sign in to comment.