From 434943c9645b88da88841ca06dfe193d18165c1d Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Mon, 9 Jan 2023 14:16:08 -0500 Subject: [PATCH 01/32] zrokdir.Load().Client() (#136) --- cmd/zrok/accessPrivate.go | 20 ++--- cmd/zrok/adminCreateFrontend.go | 7 +- cmd/zrok/adminCreateIdentity.go | 7 +- cmd/zrok/adminDeleteFrontend.go | 7 +- cmd/zrok/adminListFrontends.go | 7 +- cmd/zrok/adminUpdateFrontend.go | 7 +- cmd/zrok/disable.go | 19 +++-- cmd/zrok/enable.go | 12 +-- cmd/zrok/invite.go | 7 +- cmd/zrok/loop.go | 11 ++- cmd/zrok/main.go | 3 - cmd/zrok/release.go | 18 +++-- cmd/zrok/reserve.go | 17 +++-- cmd/zrok/sharePrivate.go | 17 +++-- cmd/zrok/sharePublic.go | 20 +++-- cmd/zrok/shareReserved.go | 14 +++- cmd/zrok/status.go | 14 ++-- zrokdir/client.go | 37 ++++++---- zrokdir/config.go | 6 +- zrokdir/environment.go | 19 ++++- zrokdir/identity.go | 7 +- zrokdir/zrokdir.go | 126 ++++++++++++++++++++++++++++++++ 22 files changed, 306 insertions(+), 96 deletions(-) diff --git a/cmd/zrok/accessPrivate.go b/cmd/zrok/accessPrivate.go index b0bd1d26..798001d2 100644 --- a/cmd/zrok/accessPrivate.go +++ b/cmd/zrok/accessPrivate.go @@ -48,14 +48,16 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) { panic(err) } - env, err := zrokdir.LoadEnvironment() + zrd, err := zrokdir.Load() if err != nil { - if !panicInstead { - showError("unable to load environment; did you 'zrok enable'?", err) - } - panic(err) + showError("unable to load zrokdir", err) } - zrok, err := zrokdir.ZrokClient(env.ApiEndpoint) + + if zrd.Env == nil { + showError("unable to load environment; did you 'zrok enable'?", nil) + } + + zrok, err := zrd.Client() if err != nil { if !panicInstead { showError("unable to create zrok client", err) @@ -63,11 +65,11 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) { panic(err) } - auth := httptransport.APIKeyAuth("X-TOKEN", "header", env.Token) + auth := httptransport.APIKeyAuth("X-TOKEN", "header", zrd.Env.Token) req := share.NewAccessParams() req.Body = &rest_model_zrok.AccessRequest{ ShrToken: shrToken, - EnvZID: env.ZId, + EnvZID: zrd.Env.ZId, } accessResp, err := zrok.Share.Access(req, auth) if err != nil { @@ -86,7 +88,7 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) { signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { <-c - cmd.destroy(accessResp.Payload.FrontendToken, env.ZId, shrToken, zrok, auth) + cmd.destroy(accessResp.Payload.FrontendToken, zrd.Env.ZId, shrToken, zrok, auth) os.Exit(0) }() diff --git a/cmd/zrok/adminCreateFrontend.go b/cmd/zrok/adminCreateFrontend.go index c79a5990..b4ab75b3 100644 --- a/cmd/zrok/adminCreateFrontend.go +++ b/cmd/zrok/adminCreateFrontend.go @@ -33,7 +33,12 @@ func (cmd *adminCreateFrontendCommand) run(_ *cobra.Command, args []string) { publicName := args[1] urlTemplate := args[2] - zrok, err := zrokdir.ZrokClient(apiEndpoint) + zrd, err := zrokdir.Load() + if err != nil { + panic(err) + } + + zrok, err := zrd.Client() if err != nil { panic(err) } diff --git a/cmd/zrok/adminCreateIdentity.go b/cmd/zrok/adminCreateIdentity.go index 66305413..20421f5a 100644 --- a/cmd/zrok/adminCreateIdentity.go +++ b/cmd/zrok/adminCreateIdentity.go @@ -41,7 +41,12 @@ func (cmd *adminCreateIdentity) run(_ *cobra.Command, args []string) { os.Exit(1) } - zrok, err := zrokdir.ZrokClient(apiEndpoint) + zrd, err := zrokdir.Load() + if err != nil { + panic(err) + } + + zrok, err := zrd.Client() if err != nil { panic(err) } diff --git a/cmd/zrok/adminDeleteFrontend.go b/cmd/zrok/adminDeleteFrontend.go index 1e714d1e..51d41146 100644 --- a/cmd/zrok/adminDeleteFrontend.go +++ b/cmd/zrok/adminDeleteFrontend.go @@ -31,7 +31,12 @@ func newAdminDeleteFrontendCommand() *adminDeleteFrontendCommand { func (cmd *adminDeleteFrontendCommand) run(_ *cobra.Command, args []string) { feToken := args[0] - zrok, err := zrokdir.ZrokClient(apiEndpoint) + zrd, err := zrokdir.Load() + if err != nil { + panic(err) + } + + zrok, err := zrd.Client() if err != nil { panic(err) } diff --git a/cmd/zrok/adminListFrontends.go b/cmd/zrok/adminListFrontends.go index 14ec756d..9fffb41f 100644 --- a/cmd/zrok/adminListFrontends.go +++ b/cmd/zrok/adminListFrontends.go @@ -31,7 +31,12 @@ func newAdminListFrontendsCommand() *adminListFrontendsCommand { } func (cmd *adminListFrontendsCommand) run(_ *cobra.Command, args []string) { - zrok, err := zrokdir.ZrokClient(apiEndpoint) + zrd, err := zrokdir.Load() + if err != nil { + panic(err) + } + + zrok, err := zrd.Client() if err != nil { panic(err) } diff --git a/cmd/zrok/adminUpdateFrontend.go b/cmd/zrok/adminUpdateFrontend.go index 9153e2e7..3fc8949c 100644 --- a/cmd/zrok/adminUpdateFrontend.go +++ b/cmd/zrok/adminUpdateFrontend.go @@ -38,7 +38,12 @@ func (cmd *adminUpdateFrontendCommand) run(_ *cobra.Command, args []string) { panic("must specify at least one of public name or url template") } - zrok, err := zrokdir.ZrokClient(apiEndpoint) + zrd, err := zrokdir.Load() + if err != nil { + panic(err) + } + + zrok, err := zrd.Client() if err != nil { panic(err) } diff --git a/cmd/zrok/disable.go b/cmd/zrok/disable.go index b41c81e5..7df40a03 100644 --- a/cmd/zrok/disable.go +++ b/cmd/zrok/disable.go @@ -29,25 +29,30 @@ func newDisableCommand() *disableCommand { return command } -func (cmd *disableCommand) run(_ *cobra.Command, args []string) { - env, err := zrokdir.LoadEnvironment() +func (cmd *disableCommand) run(_ *cobra.Command, _ []string) { + zrd, err := zrokdir.Load() if err != nil { if !panicInstead { - showError("could not load environment; not active?", err) + showError("unable to load zrokdir", err) } panic(err) } - zrok, err := zrokdir.ZrokClient(env.ApiEndpoint) + + if zrd.Env == nil { + showError("no environment found; nothing to disable!", nil) + } + + zrok, err := zrd.Client() if err != nil { if !panicInstead { showError("could not create zrok client", err) } panic(err) } - auth := httptransport.APIKeyAuth("X-TOKEN", "header", env.Token) + auth := httptransport.APIKeyAuth("X-TOKEN", "header", zrd.Env.Token) req := environment.NewDisableParams() req.Body = &rest_model_zrok.DisableRequest{ - Identity: env.ZId, + Identity: zrd.Env.ZId, } _, err = zrok.Environment.Disable(req, auth) if err != nil { @@ -64,5 +69,5 @@ func (cmd *disableCommand) run(_ *cobra.Command, args []string) { showError("error removing zrok backend identity", err) } } - fmt.Printf("zrok environment '%v' disabled for '%v'\n", env.ZId, env.Token) + fmt.Printf("zrok environment '%v' disabled for '%v'\n", zrd.Env.ZId, zrd.Env.Token) } diff --git a/cmd/zrok/enable.go b/cmd/zrok/enable.go index af983f05..faa7b6e0 100644 --- a/cmd/zrok/enable.go +++ b/cmd/zrok/enable.go @@ -33,11 +33,10 @@ func newEnableCommand() *enableCommand { } func (cmd *enableCommand) run(_ *cobra.Command, args []string) { - env, err := zrokdir.LoadEnvironment() - if err == nil { - showError(fmt.Sprintf("you already have an environment '%v' for '%v'", env.ZId, env.Token), nil) + zrd, err := zrokdir.Load() + if err != nil { + panic(err) } - token := args[0] hostName, hostDetail, err := getHost() @@ -53,7 +52,7 @@ func (cmd *enableCommand) run(_ *cobra.Command, args []string) { cmd.description = fmt.Sprintf("%v@%v", user.Username, hostName) } - zrok, err := zrokdir.ZrokClient(apiEndpoint) + zrok, err := zrd.Client() if err != nil { panic(err) } @@ -70,7 +69,8 @@ func (cmd *enableCommand) run(_ *cobra.Command, args []string) { } panic(err) } - if err := zrokdir.SaveEnvironment(&zrokdir.Environment{Token: token, ZId: resp.Payload.Identity, ApiEndpoint: apiEndpoint}); err != nil { + zrd.Env = &zrokdir.Environment{Token: token, ZId: resp.Payload.Identity, ApiEndpoint: zrd.ApiEndpoint()} + if err := zrd.Save(); err != nil { if !panicInstead { showError("there was an error saving the new environment", err) } diff --git a/cmd/zrok/invite.go b/cmd/zrok/invite.go index 668884f9..9654d363 100644 --- a/cmd/zrok/invite.go +++ b/cmd/zrok/invite.go @@ -45,7 +45,12 @@ func (cmd *inviteCommand) run(_ *cobra.Command, _ []string) { showError("entered emails do not match... aborting!", nil) } - zrok, err := zrokdir.ZrokClient(apiEndpoint) + zrd, err := zrokdir.Load() + if err != nil { + showError("error loading zrokdir", err) + } + + zrok, err := zrd.Client() if err != nil { if !panicInstead { showError("error creating zrok api client", err) diff --git a/cmd/zrok/loop.go b/cmd/zrok/loop.go index 7522b1b5..74bd3778 100644 --- a/cmd/zrok/loop.go +++ b/cmd/zrok/loop.go @@ -170,16 +170,21 @@ func (l *looper) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (l *looper) startup() { logrus.Infof("starting #%d", l.id) - var err error - l.env, err = zrokdir.LoadEnvironment() + zrd, err := zrokdir.Load() if err != nil { panic(err) } + + if zrd.Env == nil { + showError("unable to load environment; did you 'zrok enable'?", nil) + } + l.env = zrd.Env + l.zif, err = zrokdir.ZitiIdentityFile("backend") if err != nil { panic(err) } - l.zrok, err = zrokdir.ZrokClient(l.env.ApiEndpoint) + l.zrok, err = zrd.Client() if err != nil { panic(err) } diff --git a/cmd/zrok/main.go b/cmd/zrok/main.go index a8afd890..c0495160 100644 --- a/cmd/zrok/main.go +++ b/cmd/zrok/main.go @@ -2,7 +2,6 @@ package main import ( "github.com/michaelquigley/pfxlog" - "github.com/openziti-test-kitchen/zrok/zrokdir" "github.com/sirupsen/logrus" "github.com/spf13/cobra" "os" @@ -14,7 +13,6 @@ func init() { pfxlog.GlobalInit(logrus.InfoLevel, pfxlog.DefaultOptions().SetTrimPrefix("github.com/openziti-test-kitchen/")) rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Enable verbose logging") rootCmd.PersistentFlags().BoolVarP(&panicInstead, "panic", "p", false, "Panic instead of showing pretty errors") - zrokdir.AddZrokApiEndpointFlag(&apiEndpoint, rootCmd.PersistentFlags()) rootCmd.AddCommand(accessCmd) adminCmd.AddCommand(adminCreateCmd) adminCmd.AddCommand(adminDeleteCmd) @@ -36,7 +34,6 @@ var rootCmd = &cobra.Command{ } var verbose bool var panicInstead bool -var apiEndpoint string var accessCmd = &cobra.Command{ Use: "access", diff --git a/cmd/zrok/release.go b/cmd/zrok/release.go index 06a2c2d4..f16e4b8a 100644 --- a/cmd/zrok/release.go +++ b/cmd/zrok/release.go @@ -1,7 +1,6 @@ package main import ( - ui "github.com/gizak/termui/v3" httptransport "github.com/go-openapi/runtime/client" "github.com/openziti-test-kitchen/zrok/rest_client_zrok/share" "github.com/openziti-test-kitchen/zrok/rest_model_zrok" @@ -31,27 +30,30 @@ func newReleaseCommand() *releaseCommand { func (cmd *releaseCommand) run(_ *cobra.Command, args []string) { shrToken := args[0] - env, err := zrokdir.LoadEnvironment() + zrd, err := zrokdir.Load() if err != nil { - ui.Close() if !panicInstead { - showError("unable to load environment; did you 'zrok enable'?", err) + showError("unable to load zrokdir", err) } panic(err) } - zrok, err := zrokdir.ZrokClient(env.ApiEndpoint) + if zrd.Env == nil { + showError("unable to load environment; did you 'zrok enable'?", nil) + } + + zrok, err := zrd.Client() if err != nil { - ui.Close() if !panicInstead { showError("unable to create zrok client", err) } panic(err) } - auth := httptransport.APIKeyAuth("X-TOKEN", "header", env.Token) + + auth := httptransport.APIKeyAuth("X-TOKEN", "header", zrd.Env.Token) req := share.NewUnshareParams() req.Body = &rest_model_zrok.UnshareRequest{ - EnvZID: env.ZId, + EnvZID: zrd.Env.ZId, ShrToken: shrToken, Reserved: true, } diff --git a/cmd/zrok/reserve.go b/cmd/zrok/reserve.go index a4f19e54..50e315b3 100644 --- a/cmd/zrok/reserve.go +++ b/cmd/zrok/reserve.go @@ -1,7 +1,6 @@ package main import ( - ui "github.com/gizak/termui/v3" httptransport "github.com/go-openapi/runtime/client" "github.com/openziti-test-kitchen/zrok/model" "github.com/openziti-test-kitchen/zrok/rest_client_zrok/share" @@ -54,27 +53,29 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) { targetEndpoint.Scheme = "https" } - env, err := zrokdir.LoadEnvironment() + zrd, err := zrokdir.Load() if err != nil { - ui.Close() if !panicInstead { - showError("unable to load environment; did you 'zrok enable'?", err) + showError("error loading zrokdir", err) } panic(err) } - zrok, err := zrokdir.ZrokClient(env.ApiEndpoint) + if zrd.Env == nil { + showError("unable to load environment; did you 'zrok enable'?", nil) + } + + zrok, err := zrd.Client() if err != nil { - ui.Close() if !panicInstead { showError("unable to create zrok client", err) } panic(err) } - auth := httptransport.APIKeyAuth("X-TOKEN", "header", env.Token) + auth := httptransport.APIKeyAuth("X-TOKEN", "header", zrd.Env.Token) req := share.NewShareParams() req.Body = &rest_model_zrok.ShareRequest{ - EnvZID: env.ZId, + EnvZID: zrd.Env.ZId, ShareMode: shareMode, BackendMode: "proxy", BackendProxyEndpoint: targetEndpoint.String(), diff --git a/cmd/zrok/sharePrivate.go b/cmd/zrok/sharePrivate.go index 93a14bd1..6d225d42 100644 --- a/cmd/zrok/sharePrivate.go +++ b/cmd/zrok/sharePrivate.go @@ -70,13 +70,18 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { showError(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web}", cmd.backendMode), nil) } - env, err := zrokdir.LoadEnvironment() + zrd, err := zrokdir.Load() if err != nil { if !panicInstead { - showError("unable to load environment; did you 'zrok enable'?", err) + showError("unable to load zrokdir", err) } panic(err) } + + if zrd.Env == nil { + showError("unable to load environment; did you 'zrok enable'?", nil) + } + zif, err := zrokdir.ZitiIdentityFile("backend") if err != nil { if !panicInstead { @@ -85,7 +90,7 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { panic(err) } - zrok, err := zrokdir.ZrokClient(env.ApiEndpoint) + zrok, err := zrd.Client() if err != nil { if !panicInstead { showError("unable to create zrok client", err) @@ -93,10 +98,10 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { panic(err) } - auth := httptransport.APIKeyAuth("X-TOKEN", "header", env.Token) + auth := httptransport.APIKeyAuth("X-TOKEN", "header", zrd.Env.Token) req := share.NewShareParams() req.Body = &rest_model_zrok.ShareRequest{ - EnvZID: env.ZId, + EnvZID: zrd.Env.ZId, ShareMode: "private", BackendMode: "proxy", BackendProxyEndpoint: target, @@ -127,7 +132,7 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { <-c - cmd.destroy(env.ZId, resp.Payload.ShrToken, zrok, auth) + cmd.destroy(zrd.Env.ZId, resp.Payload.ShrToken, zrok, auth) os.Exit(0) }() diff --git a/cmd/zrok/sharePublic.go b/cmd/zrok/sharePublic.go index f608ae93..93d6542e 100644 --- a/cmd/zrok/sharePublic.go +++ b/cmd/zrok/sharePublic.go @@ -87,14 +87,20 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { tb.SetInputMode(tb.InputEsc) } - env, err := zrokdir.LoadEnvironment() + zrd, err := zrokdir.Load() if err != nil { ui.Close() if !panicInstead { - showError("unable to load environment; did you 'zrok enable'?", err) + showError("unable to load zrokdir", nil) } panic(err) } + + if zrd.Env == nil { + ui.Close() + showError("unable to load environment; did you 'zrok enable'?", nil) + } + zif, err := zrokdir.ZitiIdentityFile("backend") if err != nil { ui.Close() @@ -104,7 +110,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { panic(err) } - zrok, err := zrokdir.ZrokClient(env.ApiEndpoint) + zrok, err := zrd.Client() if err != nil { ui.Close() if !panicInstead { @@ -112,10 +118,10 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { } panic(err) } - auth := httptransport.APIKeyAuth("X-TOKEN", "header", env.Token) + auth := httptransport.APIKeyAuth("X-TOKEN", "header", zrd.Env.Token) req := share.NewShareParams() req.Body = &rest_model_zrok.ShareRequest{ - EnvZID: env.ZId, + EnvZID: zrd.Env.ZId, ShareMode: "public", FrontendSelection: cmd.frontendSelection, BackendMode: "proxy", @@ -147,7 +153,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { <-c - cmd.destroy(env.ZId, resp.Payload.ShrToken, zrok, auth) + cmd.destroy(zrd.Env.ZId, resp.Payload.ShrToken, zrok, auth) os.Exit(0) }() @@ -229,7 +235,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { switch e.ID { case "q", "": ui.Close() - cmd.destroy(env.ZId, resp.Payload.ShrToken, zrok, auth) + cmd.destroy(zrd.Env.ZId, resp.Payload.ShrToken, zrok, auth) os.Exit(0) } } diff --git a/cmd/zrok/shareReserved.go b/cmd/zrok/shareReserved.go index 08dc21bd..70dffd1d 100644 --- a/cmd/zrok/shareReserved.go +++ b/cmd/zrok/shareReserved.go @@ -51,15 +51,21 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { targetEndpoint = e.String() } - env, err := zrokdir.LoadEnvironment() + zrd, err := zrokdir.Load() if err != nil { ui.Close() if !panicInstead { - showError("unable to load environment; did you 'zrok enable'?", err) + showError("error loading zrokdir", err) } panic(err) } - zrok, err := zrokdir.ZrokClient(env.ApiEndpoint) + + if zrd.Env == nil { + ui.Close() + showError("unable to load environment; did you 'zrok enable'?", nil) + } + + zrok, err := zrd.Client() if err != nil { ui.Close() if !panicInstead { @@ -67,7 +73,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { } panic(err) } - auth := httptransport.APIKeyAuth("X-TOKEN", "header", env.Token) + auth := httptransport.APIKeyAuth("X-TOKEN", "header", zrd.Env.Token) req := metadata.NewGetShareDetailParams() req.ShrToken = shrToken resp, err := zrok.Metadata.GetShareDetail(req, auth) diff --git a/cmd/zrok/status.go b/cmd/zrok/status.go index 56abfc18..371cbf04 100644 --- a/cmd/zrok/status.go +++ b/cmd/zrok/status.go @@ -31,9 +31,13 @@ func newStatusCommand() *statusCommand { func (cmd *statusCommand) run(_ *cobra.Command, _ []string) { _, _ = fmt.Fprintf(os.Stderr, "\n") - env, err := zrokdir.LoadEnvironment() + zrd, err := zrokdir.Load() if err != nil { - _, _ = fmt.Fprintf(os.Stderr, "%v: Unable to load your local environment! (%v)\n\n", warningLabel, err) + showError("unable to load zrokdir", err) + } + + if zrd.Env == nil { + _, _ = fmt.Fprintf(os.Stderr, "%v: Unable to load your local environment!\n\n", warningLabel) _, _ = fmt.Fprintf(os.Stderr, "To create a local environment use the %v command.\n", codeStyle.Render("zrok enable")) } else { _, _ = fmt.Fprintf(os.Stdout, codeStyle.Render("Environment"+":\n")) @@ -43,9 +47,9 @@ func (cmd *statusCommand) run(_ *cobra.Command, _ []string) { t.SetOutputMirror(os.Stdout) t.SetStyle(table.StyleColoredDark) t.AppendHeader(table.Row{"Property", "Value"}) - t.AppendRow(table.Row{"API Endpoint", env.ApiEndpoint}) - t.AppendRow(table.Row{"Secret Token", env.Token}) - t.AppendRow(table.Row{"Ziti Identity", env.ZId}) + t.AppendRow(table.Row{"API Endpoint", zrd.Env.ApiEndpoint}) + t.AppendRow(table.Row{"Secret Token", zrd.Env.Token}) + t.AppendRow(table.Row{"Ziti Identity", zrd.Env.ZId}) t.Render() } diff --git a/zrokdir/client.go b/zrokdir/client.go index 1b95c856..2725d3c3 100644 --- a/zrokdir/client.go +++ b/zrokdir/client.go @@ -7,24 +7,16 @@ import ( "github.com/openziti-test-kitchen/zrok/build" "github.com/openziti-test-kitchen/zrok/rest_client_zrok" "github.com/pkg/errors" - "github.com/spf13/pflag" "net/url" "os" "strings" ) -func AddZrokApiEndpointFlag(v *string, flags *pflag.FlagSet) { - defaultEndpoint := os.Getenv("ZROK_API_ENDPOINT") - if defaultEndpoint == "" { - defaultEndpoint = "https://api.zrok.io" - } - flags.StringVarP(v, "endpoint", "e", defaultEndpoint, "zrok API endpoint address") -} - -func ZrokClient(endpoint string) (*rest_client_zrok.Zrok, error) { - apiUrl, err := url.Parse(endpoint) +func (zrd *ZrokDir) Client() (*rest_client_zrok.Zrok, error) { + apiEndpoint := zrd.ApiEndpoint() + apiUrl, err := url.Parse(apiEndpoint) if err != nil { - return nil, errors.Wrapf(err, "error parsing api endpoint '%v'", endpoint) + return nil, errors.Wrapf(err, "error parsing api endpoint '%v'", zrd) } transport := httptransport.New(apiUrl.Host, "/api/v1", []string{apiUrl.Scheme}) transport.Producers["application/zrok.v1+json"] = runtime.JSONProducer() @@ -33,7 +25,7 @@ func ZrokClient(endpoint string) (*rest_client_zrok.Zrok, error) { zrok := rest_client_zrok.New(transport, strfmt.Default) v, err := zrok.Metadata.Version(nil) if err != nil { - return nil, errors.Wrapf(err, "error getting version from api endpoint '%v': %v", endpoint, err) + return nil, errors.Wrapf(err, "error getting version from api endpoint '%v': %v", apiEndpoint, err) } if !strings.HasPrefix(string(v.Payload), build.Series) { return nil, errors.Errorf("expected a '%v' version, received: '%v'", build.Series, v.Payload) @@ -41,3 +33,22 @@ func ZrokClient(endpoint string) (*rest_client_zrok.Zrok, error) { return zrok, nil } + +func (zrd *ZrokDir) ApiEndpoint() string { + apiEndpoint := "https://api.zrok.io" + + if zrd.Cfg != nil && zrd.Cfg.ApiEndpoint != "" { + apiEndpoint = zrd.Cfg.ApiEndpoint + } + + env := os.Getenv("ZROK_API_ENDPOINT") + if env != "" { + apiEndpoint = env + } + + if zrd.Env != nil && zrd.Env.ApiEndpoint != "" { + apiEndpoint = zrd.Env.ApiEndpoint + } + + return apiEndpoint +} diff --git a/zrokdir/config.go b/zrokdir/config.go index cf796b5d..d8e77cfd 100644 --- a/zrokdir/config.go +++ b/zrokdir/config.go @@ -11,7 +11,7 @@ type Config struct { ApiEndpoint string `json:"api_endpoint"` } -func HasConfig() (bool, error) { +func hasConfig() (bool, error) { cf, err := configFile() if err != nil { return false, errors.Wrap(err, "error getting config file path") @@ -26,7 +26,7 @@ func HasConfig() (bool, error) { return true, nil } -func LoadConfig() (*Config, error) { +func loadConfig() (*Config, error) { cf, err := configFile() if err != nil { return nil, errors.Wrap(err, "error getting config file path") @@ -42,7 +42,7 @@ func LoadConfig() (*Config, error) { return cfg, nil } -func SaveConfig(cfg *Config) error { +func saveConfig(cfg *Config) error { data, err := json.MarshalIndent(cfg, "", " ") if err != nil { return errors.Wrap(err, "error marshaling config") diff --git a/zrokdir/environment.go b/zrokdir/environment.go index 7020f516..56b50227 100644 --- a/zrokdir/environment.go +++ b/zrokdir/environment.go @@ -13,7 +13,22 @@ type Environment struct { ApiEndpoint string `json:"api_endpoint"` } -func LoadEnvironment() (*Environment, error) { +func hasEnvironment() (bool, error) { + ef, err := environmentFile() + if err != nil { + return false, errors.Wrap(err, "error getting environment file path") + } + _, err = os.Stat(ef) + if os.IsNotExist(err) { + return false, nil + } + if err != nil { + return false, errors.Wrapf(err, "error stat-ing environment file '%v'", ef) + } + return true, nil +} + +func loadEnvironment() (*Environment, error) { ef, err := environmentFile() if err != nil { return nil, errors.Wrap(err, "error getting environment file") @@ -29,7 +44,7 @@ func LoadEnvironment() (*Environment, error) { return env, nil } -func SaveEnvironment(env *Environment) error { +func saveEnvironment(env *Environment) error { data, err := json.MarshalIndent(env, "", " ") if err != nil { return errors.Wrap(err, "error marshaling environment") diff --git a/zrokdir/identity.go b/zrokdir/identity.go index a69b8121..4c912ebc 100644 --- a/zrokdir/identity.go +++ b/zrokdir/identity.go @@ -1,18 +1,13 @@ package zrokdir import ( - "fmt" "github.com/pkg/errors" "os" "path/filepath" ) func ZitiIdentityFile(name string) (string, error) { - zrd, err := zrokDir() - if err != nil { - return "", err - } - return filepath.Join(zrd, "identities", fmt.Sprintf("%v.json", name)), nil + return identityFile(name) } func SaveZitiIdentity(name, data string) error { diff --git a/zrokdir/zrokdir.go b/zrokdir/zrokdir.go index 9110774b..56913d2a 100644 --- a/zrokdir/zrokdir.go +++ b/zrokdir/zrokdir.go @@ -1,10 +1,120 @@ package zrokdir import ( + "fmt" + "github.com/pkg/errors" "os" "path/filepath" + "strings" ) +type ZrokDir struct { + Env *Environment + Cfg *Config + identities map[string]struct{} +} + +func Initialize() (*ZrokDir, error) { + zrd, err := zrokDir() + if err != nil { + return nil, errors.Wrap(err, "error getting zrokdir path") + } + if err := os.MkdirAll(zrd, os.FileMode(0700)); err != nil { + return nil, errors.Wrapf(err, "error creating zrokdir root path '%v'", zrd) + } + if err := DeleteEnvironment(); err != nil { + return nil, errors.Wrap(err, "error deleting environment") + } + idd, err := identitiesDir() + if err != nil { + return nil, errors.Wrap(err, "error getting zrokdir identities path") + } + if err := os.MkdirAll(idd, os.FileMode(0700)); err != nil { + return nil, errors.Wrapf(err, "error creating zrokdir identities root path '%v'", idd) + } + return Load() +} + +func Load() (*ZrokDir, error) { + zrd := &ZrokDir{} + + ids, err := listIdentities() + if err != nil { + return nil, err + } + zrd.identities = ids + + hasCfg, err := hasConfig() + if err != nil { + return nil, err + } + if hasCfg { + cfg, err := loadConfig() + if err != nil { + return nil, err + } + zrd.Cfg = cfg + } + + hasEnv, err := hasEnvironment() + if err != nil { + return nil, err + } + if hasEnv { + env, err := loadEnvironment() + if err != nil { + return nil, err + } + zrd.Env = env + } + + return zrd, nil +} + +func (zrd *ZrokDir) Save() error { + if zrd.Env != nil { + if err := saveEnvironment(zrd.Env); err != nil { + return errors.Wrap(err, "error saving environment") + } + } + if zrd.Cfg != nil { + if err := saveConfig(zrd.Cfg); err != nil { + return errors.Wrap(err, "error saving config") + } + } + return nil +} + +func Obliterate() error { + zrd, err := zrokDir() + if err != nil { + return err + } + if err := os.RemoveAll(zrd); err != nil { + return err + } + return nil +} + +func listIdentities() (map[string]struct{}, error) { + idd, err := identitiesDir() + if err != nil { + return nil, errors.Wrap(err, "error getting zrokdir identities path") + } + des, err := os.ReadDir(idd) + if err != nil { + return nil, errors.Wrapf(err, "error listing zrokdir identities from '%v'", idd) + } + ids := make(map[string]struct{}) + for _, de := range des { + if strings.HasSuffix(de.Name(), ".json") && !de.IsDir() { + name := strings.TrimSuffix(de.Name(), ".json") + ids[name] = struct{}{} + } + } + return ids, nil +} + func configFile() (string, error) { zrd, err := zrokDir() if err != nil { @@ -21,6 +131,22 @@ func environmentFile() (string, error) { return filepath.Join(zrd, "environment.json"), nil } +func identityFile(name string) (string, error) { + idd, err := identitiesDir() + if err != nil { + return "", err + } + return filepath.Join(idd, fmt.Sprintf("%v.json", name)), nil +} + +func identitiesDir() (string, error) { + zrd, err := zrokDir() + if err != nil { + return "", err + } + return filepath.Join(zrd, "identities"), nil +} + func zrokDir() (string, error) { home, err := os.UserHomeDir() if err != nil { From 5bd11e46a5d4b4db5f48ba9af1df5bd32bb48c58 Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Mon, 9 Jan 2023 14:33:17 -0500 Subject: [PATCH 02/32] zrok status now shows origination for api endpoint (#136) --- cmd/zrok/enable.go | 3 ++- cmd/zrok/status.go | 17 ++++++++++++----- zrokdir/client.go | 12 ++++++++---- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/cmd/zrok/enable.go b/cmd/zrok/enable.go index faa7b6e0..9469e60c 100644 --- a/cmd/zrok/enable.go +++ b/cmd/zrok/enable.go @@ -69,7 +69,8 @@ func (cmd *enableCommand) run(_ *cobra.Command, args []string) { } panic(err) } - zrd.Env = &zrokdir.Environment{Token: token, ZId: resp.Payload.Identity, ApiEndpoint: zrd.ApiEndpoint()} + apiEndpoint, _ := zrd.ApiEndpoint() + zrd.Env = &zrokdir.Environment{Token: token, ZId: resp.Payload.Identity, ApiEndpoint: apiEndpoint} if err := zrd.Save(); err != nil { if !panicInstead { showError("there was an error saving the new environment", err) diff --git a/cmd/zrok/status.go b/cmd/zrok/status.go index 371cbf04..d7f815c5 100644 --- a/cmd/zrok/status.go +++ b/cmd/zrok/status.go @@ -36,22 +36,29 @@ func (cmd *statusCommand) run(_ *cobra.Command, _ []string) { showError("unable to load zrokdir", err) } + _, _ = fmt.Fprintf(os.Stdout, codeStyle.Render("Config")+":\n\n") + t := table.NewWriter() + t.SetOutputMirror(os.Stdout) + t.SetStyle(table.StyleColoredDark) + t.AppendHeader(table.Row{"Property", "Value", "Source"}) + apiEndpoint, from := zrd.ApiEndpoint() + t.AppendRow(table.Row{"API Endpoint", apiEndpoint, from}) + t.Render() + _, _ = fmt.Fprintf(os.Stderr, "\n") + if zrd.Env == nil { _, _ = fmt.Fprintf(os.Stderr, "%v: Unable to load your local environment!\n\n", warningLabel) _, _ = fmt.Fprintf(os.Stderr, "To create a local environment use the %v command.\n", codeStyle.Render("zrok enable")) } else { - _, _ = fmt.Fprintf(os.Stdout, codeStyle.Render("Environment"+":\n")) - _, _ = fmt.Fprintf(os.Stdout, "\n") + _, _ = fmt.Fprintf(os.Stdout, codeStyle.Render("Environment")+":\n\n") t := table.NewWriter() t.SetOutputMirror(os.Stdout) t.SetStyle(table.StyleColoredDark) t.AppendHeader(table.Row{"Property", "Value"}) - t.AppendRow(table.Row{"API Endpoint", zrd.Env.ApiEndpoint}) t.AppendRow(table.Row{"Secret Token", zrd.Env.Token}) t.AppendRow(table.Row{"Ziti Identity", zrd.Env.ZId}) t.Render() } - - _, _ = fmt.Fprintf(os.Stderr, "\n") + _, _ = fmt.Fprintf(os.Stdout, "\n") } diff --git a/zrokdir/client.go b/zrokdir/client.go index 2725d3c3..ede9e5e3 100644 --- a/zrokdir/client.go +++ b/zrokdir/client.go @@ -13,7 +13,7 @@ import ( ) func (zrd *ZrokDir) Client() (*rest_client_zrok.Zrok, error) { - apiEndpoint := zrd.ApiEndpoint() + apiEndpoint, _ := zrd.ApiEndpoint() apiUrl, err := url.Parse(apiEndpoint) if err != nil { return nil, errors.Wrapf(err, "error parsing api endpoint '%v'", zrd) @@ -34,21 +34,25 @@ func (zrd *ZrokDir) Client() (*rest_client_zrok.Zrok, error) { return zrok, nil } -func (zrd *ZrokDir) ApiEndpoint() string { - apiEndpoint := "https://api.zrok.io" +func (zrd *ZrokDir) ApiEndpoint() (apiEndpoint string, from string) { + apiEndpoint = "https://api.zrok.io" + from = "binary" if zrd.Cfg != nil && zrd.Cfg.ApiEndpoint != "" { apiEndpoint = zrd.Cfg.ApiEndpoint + from = "config" } env := os.Getenv("ZROK_API_ENDPOINT") if env != "" { apiEndpoint = env + from = "ZROK_API_ENDPOINT" } if zrd.Env != nil && zrd.Env.ApiEndpoint != "" { apiEndpoint = zrd.Env.ApiEndpoint + from = "env" } - return apiEndpoint + return apiEndpoint, from } From 38132f2e7c9be8c0020a7cfa5891a41db59ce28a Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Mon, 9 Jan 2023 15:24:01 -0500 Subject: [PATCH 03/32] zrok config (#136) --- cmd/zrok/adminListFrontends.go | 2 +- cmd/zrok/configGet.go | 46 +++++++++++++++++++++++++++ cmd/zrok/configSet.go | 58 ++++++++++++++++++++++++++++++++++ cmd/zrok/main.go | 6 ++++ cmd/zrok/status.go | 4 +-- 5 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 cmd/zrok/configGet.go create mode 100644 cmd/zrok/configSet.go diff --git a/cmd/zrok/adminListFrontends.go b/cmd/zrok/adminListFrontends.go index 9fffb41f..6167de90 100644 --- a/cmd/zrok/adminListFrontends.go +++ b/cmd/zrok/adminListFrontends.go @@ -30,7 +30,7 @@ func newAdminListFrontendsCommand() *adminListFrontendsCommand { return command } -func (cmd *adminListFrontendsCommand) run(_ *cobra.Command, args []string) { +func (cmd *adminListFrontendsCommand) run(_ *cobra.Command, _ []string) { zrd, err := zrokdir.Load() if err != nil { panic(err) diff --git a/cmd/zrok/configGet.go b/cmd/zrok/configGet.go new file mode 100644 index 00000000..57403215 --- /dev/null +++ b/cmd/zrok/configGet.go @@ -0,0 +1,46 @@ +package main + +import ( + "fmt" + "github.com/openziti-test-kitchen/zrok/zrokdir" + "github.com/spf13/cobra" +) + +func init() { + configCmd.AddCommand(newConfigGetCommand().cmd) +} + +type configGetCommand struct { + cmd *cobra.Command +} + +func newConfigGetCommand() *configGetCommand { + cmd := &cobra.Command{ + Use: "get ", + Short: "Get a value from the environment config", + Args: cobra.ExactArgs(1), + } + command := &configGetCommand{cmd: cmd} + cmd.Run = command.run + return command +} + +func (cmd *configGetCommand) run(_ *cobra.Command, args []string) { + configName := args[0] + + zrd, err := zrokdir.Load() + if err != nil { + panic(err) + } + + switch configName { + case "apiEndpoint": + if zrd.Cfg != nil && zrd.Cfg.ApiEndpoint != "" { + fmt.Printf("apiEndpoint = %v\n", zrd.Cfg.ApiEndpoint) + } else { + fmt.Println("apiEndpoint = ") + } + default: + fmt.Printf("unknown config name '%v'\n", configName) + } +} diff --git a/cmd/zrok/configSet.go b/cmd/zrok/configSet.go new file mode 100644 index 00000000..8f7f0abd --- /dev/null +++ b/cmd/zrok/configSet.go @@ -0,0 +1,58 @@ +package main + +import ( + "fmt" + "github.com/openziti-test-kitchen/zrok/zrokdir" + "github.com/spf13/cobra" + "os" +) + +func init() { + configCmd.AddCommand(newConfigSetCommand().cmd) +} + +type configSetCommand struct { + cmd *cobra.Command +} + +func newConfigSetCommand() *configSetCommand { + cmd := &cobra.Command{ + Use: "set ", + Short: "Set a value into the environment config", + Args: cobra.ExactArgs(2), + } + command := &configSetCommand{cmd: cmd} + cmd.Run = command.run + return command +} + +func (cmd *configSetCommand) run(_ *cobra.Command, args []string) { + configName := args[0] + value := args[1] + + zrd, err := zrokdir.Load() + if err != nil { + panic(err) + } + + modified := false + switch configName { + case "apiEndpoint": + if zrd.Cfg == nil { + zrd.Cfg = &zrokdir.Config{} + } + zrd.Cfg.ApiEndpoint = value + modified = true + + default: + fmt.Printf("unknown config name '%v'\n", configName) + os.Exit(1) + } + + if modified { + if err := zrd.Save(); err != nil { + panic(err) + } + fmt.Println("zrok configuration updated") + } +} diff --git a/cmd/zrok/main.go b/cmd/zrok/main.go index c0495160..112cd02c 100644 --- a/cmd/zrok/main.go +++ b/cmd/zrok/main.go @@ -19,6 +19,7 @@ func init() { adminCmd.AddCommand(adminListCmd) adminCmd.AddCommand(adminUpdateCmd) rootCmd.AddCommand(adminCmd) + rootCmd.AddCommand(configCmd) rootCmd.AddCommand(shareCmd) rootCmd.AddCommand(testCmd) } @@ -65,6 +66,11 @@ var adminUpdateCmd = &cobra.Command{ Short: "Update global resources", } +var configCmd = &cobra.Command{ + Use: "config", + Short: "Configure your zrok environment", +} + var shareCmd = &cobra.Command{ Use: "share", Short: "Create backend access for shares", diff --git a/cmd/zrok/status.go b/cmd/zrok/status.go index d7f815c5..3d8620cb 100644 --- a/cmd/zrok/status.go +++ b/cmd/zrok/status.go @@ -40,9 +40,9 @@ func (cmd *statusCommand) run(_ *cobra.Command, _ []string) { t := table.NewWriter() t.SetOutputMirror(os.Stdout) t.SetStyle(table.StyleColoredDark) - t.AppendHeader(table.Row{"Property", "Value", "Source"}) + t.AppendHeader(table.Row{"Config", "Value", "Source"}) apiEndpoint, from := zrd.ApiEndpoint() - t.AppendRow(table.Row{"API Endpoint", apiEndpoint, from}) + t.AppendRow(table.Row{"apiEndpoint", apiEndpoint, from}) t.Render() _, _ = fmt.Fprintf(os.Stderr, "\n") From b8f566bf6a9bcc10726cead0e4c3df2ea13a3b9d Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Mon, 9 Jan 2023 16:28:54 -0500 Subject: [PATCH 04/32] zrokdir versioning (#134) --- zrokdir/version.go | 47 ++++++++++++++++++++++++++++++++++++++++++++++ zrokdir/zrokdir.go | 15 +++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 zrokdir/version.go diff --git a/zrokdir/version.go b/zrokdir/version.go new file mode 100644 index 00000000..0f191cfb --- /dev/null +++ b/zrokdir/version.go @@ -0,0 +1,47 @@ +package zrokdir + +import ( + "encoding/json" + "github.com/pkg/errors" + "os" +) + +const V = "v0.3" + +type Metadata struct { + V string `json:"v"` +} + +func checkMetadata() error { + mf, err := metadataFile() + if err != nil { + return err + } + data, err := os.ReadFile(mf) + if err != nil { + return errors.Wrapf(err, "error reading metadata file '%v'", mf) + } + m := &Metadata{} + if err := json.Unmarshal(data, m); err != nil { + return errors.Wrapf(err, "error unmarshaling metadata file '%v'", mf) + } + if m.V != V { + return errors.Errorf("invalid zrokdir metadata version '%v'", m.V) + } + return nil +} + +func writeMetadata() error { + mf, err := metadataFile() + if err != nil { + return err + } + data, err := json.Marshal(&Metadata{V: V}) + if err != nil { + return err + } + if err := os.WriteFile(mf, data, os.FileMode(0400)); err != nil { + return err + } + return nil +} diff --git a/zrokdir/zrokdir.go b/zrokdir/zrokdir.go index 56913d2a..a81a433b 100644 --- a/zrokdir/zrokdir.go +++ b/zrokdir/zrokdir.go @@ -36,6 +36,10 @@ func Initialize() (*ZrokDir, error) { } func Load() (*ZrokDir, error) { + if err := checkMetadata(); err != nil { + return nil, err + } + zrd := &ZrokDir{} ids, err := listIdentities() @@ -72,6 +76,9 @@ func Load() (*ZrokDir, error) { } func (zrd *ZrokDir) Save() error { + if err := writeMetadata(); err != nil { + return errors.Wrap(err, "error saving metadata") + } if zrd.Env != nil { if err := saveEnvironment(zrd.Env); err != nil { return errors.Wrap(err, "error saving environment") @@ -147,6 +154,14 @@ func identitiesDir() (string, error) { return filepath.Join(zrd, "identities"), nil } +func metadataFile() (string, error) { + zrd, err := zrokDir() + if err != nil { + return "", err + } + return filepath.Join(zrd, "metadata.json"), nil +} + func zrokDir() (string, error) { home, err := os.UserHomeDir() if err != nil { From ee7c0fcca6d45d726ee24042d07efb75d8071f6b Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Mon, 9 Jan 2023 17:24:35 -0500 Subject: [PATCH 05/32] rip out old tui; full backend data feed for requests (#56) --- cmd/zrok/sharePrivate.go | 7 +-- cmd/zrok/sharePublic.go | 95 ++-------------------------------- cmd/zrok/shareReserved.go | 6 --- endpoints/proxyBackend/http.go | 2 + endpoints/webBackend/web.go | 12 ++++- go.mod | 8 +-- go.sum | 9 ---- 7 files changed, 21 insertions(+), 118 deletions(-) diff --git a/cmd/zrok/sharePrivate.go b/cmd/zrok/sharePrivate.go index 6d225d42..0ee7c686 100644 --- a/cmd/zrok/sharePrivate.go +++ b/cmd/zrok/sharePrivate.go @@ -2,7 +2,6 @@ package main import ( "fmt" - ui "github.com/gizak/termui/v3" "github.com/go-openapi/runtime" httptransport "github.com/go-openapi/runtime/client" "github.com/openziti-test-kitchen/zrok/endpoints/proxyBackend" @@ -103,7 +102,7 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { req.Body = &rest_model_zrok.ShareRequest{ EnvZID: zrd.Env.ZId, ShareMode: "private", - BackendMode: "proxy", + BackendMode: cmd.backendMode, BackendProxyEndpoint: target, AuthScheme: string(model.None), } @@ -121,7 +120,6 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { } resp, err := zrok.Share.Share(req, auth) if err != nil { - ui.Close() if !panicInstead { showError("unable to create share", err) } @@ -145,7 +143,6 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { } _, err = cmd.proxyBackendMode(cfg) if err != nil { - ui.Close() if !panicInstead { showError("unable to create proxy backend handler", err) } @@ -160,7 +157,6 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { } _, err = cmd.webBackendMode(cfg) if err != nil { - ui.Close() if !panicInstead { showError("unable to create web backend handler", err) } @@ -168,7 +164,6 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { } default: - ui.Close() showError("invalid backend mode", nil) } diff --git a/cmd/zrok/sharePublic.go b/cmd/zrok/sharePublic.go index 93d6542e..0163f94b 100644 --- a/cmd/zrok/sharePublic.go +++ b/cmd/zrok/sharePublic.go @@ -2,11 +2,8 @@ package main import ( "fmt" - ui "github.com/gizak/termui/v3" - "github.com/gizak/termui/v3/widgets" "github.com/go-openapi/runtime" httptransport "github.com/go-openapi/runtime/client" - tb "github.com/nsf/termbox-go" "github.com/openziti-test-kitchen/zrok/endpoints/proxyBackend" "github.com/openziti-test-kitchen/zrok/endpoints/webBackend" "github.com/openziti-test-kitchen/zrok/model" @@ -30,7 +27,6 @@ func init() { } type sharePublicCommand struct { - quiet bool basicAuth []string frontendSelection []string backendMode string @@ -44,7 +40,6 @@ func newSharePublicCommand() *sharePublicCommand { Args: cobra.ExactArgs(1), } command := &sharePublicCommand{cmd: cmd} - cmd.Flags().BoolVarP(&command.quiet, "quiet", "q", false, "Disable TUI 'chrome' for quiet operation") cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (,...)") cmd.Flags().StringArrayVar(&command.frontendSelection, "frontends", []string{"public"}, "Selected frontends to use for the share") cmd.Flags().StringVar(&command.backendMode, "backend-mode", "proxy", "The backend mode {proxy, web}") @@ -76,20 +71,8 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { showError(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web}", cmd.backendMode), nil) } - if !cmd.quiet { - if err := ui.Init(); err != nil { - if !panicInstead { - showError("unable to initialize user interface", err) - } - panic(err) - } - defer ui.Close() - tb.SetInputMode(tb.InputEsc) - } - zrd, err := zrokdir.Load() if err != nil { - ui.Close() if !panicInstead { showError("unable to load zrokdir", nil) } @@ -97,13 +80,11 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { } if zrd.Env == nil { - ui.Close() showError("unable to load environment; did you 'zrok enable'?", nil) } zif, err := zrokdir.ZitiIdentityFile("backend") if err != nil { - ui.Close() if !panicInstead { showError("unable to load ziti identity configuration", err) } @@ -112,7 +93,6 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { zrok, err := zrd.Client() if err != nil { - ui.Close() if !panicInstead { showError("unable to create zrok client", err) } @@ -124,7 +104,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { EnvZID: zrd.Env.ZId, ShareMode: "public", FrontendSelection: cmd.frontendSelection, - BackendMode: "proxy", + BackendMode: cmd.backendMode, BackendProxyEndpoint: target, AuthScheme: string(model.None), } @@ -142,7 +122,6 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { } resp, err := zrok.Share.Share(req, auth) if err != nil { - ui.Close() if !panicInstead { showError("unable to create tunnel", err) } @@ -167,7 +146,6 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { } bh, err = cmd.proxyBackendMode(cfg) if err != nil { - ui.Close() if !panicInstead { showError("unable to create proxy backend handler", err) } @@ -182,7 +160,6 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { } bh, err = cmd.webBackendMode(cfg) if err != nil { - ui.Close() if !panicInstead { showError("unable to create web backend handler", err) } @@ -190,75 +167,13 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { } default: - ui.Close() showError("invalid backend mode", nil) } - if !cmd.quiet { - ui.Clear() - w, h := ui.TerminalDimensions() - - p := widgets.NewParagraph() - p.Border = true - p.Title = " access your zrok share " - p.Text = fmt.Sprintf("%v%v", strings.Repeat(" ", (((w-12)-len(resp.Payload.FrontendProxyEndpoints[0]))/2)-1), resp.Payload.FrontendProxyEndpoints[0]) - p.TextStyle = ui.Style{Fg: ui.ColorWhite} - p.PaddingTop = 1 - p.SetRect(5, 5, w-10, 10) - - lastRequests := float64(0) - var requestData []float64 - spk := widgets.NewSparkline() - spk.Title = " requests " - spk.Data = requestData - spk.LineColor = ui.ColorCyan - - slg := widgets.NewSparklineGroup(spk) - slg.SetRect(5, 11, w-10, h-5) - - ui.Render(p, slg) - - ticker := time.NewTicker(time.Second).C - uiEvents := ui.PollEvents() - for { - select { - case e := <-uiEvents: - switch e.Type { - case ui.ResizeEvent: - ui.Clear() - w, h = ui.TerminalDimensions() - p.SetRect(5, 5, w-10, 10) - slg.SetRect(5, 11, w-10, h-5) - ui.Render(p, slg) - - case ui.KeyboardEvent: - switch e.ID { - case "q", "": - ui.Close() - cmd.destroy(zrd.Env.ZId, resp.Payload.ShrToken, zrok, auth) - os.Exit(0) - } - } - - case <-ticker: - currentRequests := float64(bh.Requests()()) - deltaRequests := currentRequests - lastRequests - requestData = append(requestData, deltaRequests) - lastRequests = currentRequests - requestData = append(requestData, deltaRequests) - for len(requestData) > w-17 { - requestData = requestData[1:] - } - spk.Title = fmt.Sprintf(" requests (%d) ", int(currentRequests)) - spk.Data = requestData - ui.Render(p, slg) - } - } - } else { - logrus.Infof("access your zrok share: %v", resp.Payload.FrontendProxyEndpoints[0]) - for { - time.Sleep(30 * time.Second) - } + logrus.Infof("access your zrok share: %v", resp.Payload.FrontendProxyEndpoints[0]) + for { + time.Sleep(5 * time.Second) + logrus.Infof("requests: %d", bh.Requests()()) } } diff --git a/cmd/zrok/shareReserved.go b/cmd/zrok/shareReserved.go index 70dffd1d..c0ea9f86 100644 --- a/cmd/zrok/shareReserved.go +++ b/cmd/zrok/shareReserved.go @@ -1,7 +1,6 @@ package main import ( - ui "github.com/gizak/termui/v3" httptransport "github.com/go-openapi/runtime/client" "github.com/openziti-test-kitchen/zrok/endpoints/proxyBackend" "github.com/openziti-test-kitchen/zrok/rest_client_zrok/metadata" @@ -53,7 +52,6 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { zrd, err := zrokdir.Load() if err != nil { - ui.Close() if !panicInstead { showError("error loading zrokdir", err) } @@ -61,13 +59,11 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { } if zrd.Env == nil { - ui.Close() showError("unable to load environment; did you 'zrok enable'?", nil) } zrok, err := zrd.Client() if err != nil { - ui.Close() if !panicInstead { showError("unable to create zrok client", err) } @@ -89,7 +85,6 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { zif, err := zrokdir.ZitiIdentityFile("backend") if err != nil { - ui.Close() if !panicInstead { showError("unable to load ziti identity configuration", err) } @@ -121,7 +116,6 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { httpProxy, err := proxyBackend.NewBackend(cfg) if err != nil { - ui.Close() if !panicInstead { showError("unable to create http backend", err) } diff --git a/endpoints/proxyBackend/http.go b/endpoints/proxyBackend/http.go index 6b177397..bf471302 100644 --- a/endpoints/proxyBackend/http.go +++ b/endpoints/proxyBackend/http.go @@ -2,6 +2,7 @@ package proxyBackend import ( "context" + "fmt" "github.com/openziti-test-kitchen/zrok/util" "github.com/openziti/sdk-golang/ziti" "github.com/openziti/sdk-golang/ziti/config" @@ -80,6 +81,7 @@ func newReverseProxy(target string) (*httputil.ReverseProxy, error) { proxy.Transport = tpt director := proxy.Director proxy.Director = func(req *http.Request) { + fmt.Printf("proxy <= %v %v <= %v\n", req.Method, req.URL.String(), req.Header["X-Real-Ip"]) director(req) logrus.Debugf("-> %v", req.URL.String()) req.Header.Set("X-Proxy", "zrok") diff --git a/endpoints/webBackend/web.go b/endpoints/webBackend/web.go index c7d6a3bf..6023fa16 100644 --- a/endpoints/webBackend/web.go +++ b/endpoints/webBackend/web.go @@ -1,6 +1,7 @@ package webBackend import ( + "fmt" "github.com/openziti/sdk-golang/ziti" "github.com/openziti/sdk-golang/ziti/config" "github.com/openziti/sdk-golang/ziti/edge" @@ -38,7 +39,7 @@ func NewBackend(cfg *Config) (*backend, error) { return &backend{ cfg: cfg, listener: listener, - handler: http.FileServer(http.Dir(cfg.WebRoot)), + handler: &requestLogger{handler: http.FileServer(http.Dir(cfg.WebRoot))}, }, nil } @@ -52,3 +53,12 @@ func (self *backend) Run() error { func (self *backend) Requests() func() int32 { return func() int32 { return 0 } } + +type requestLogger struct { + handler http.Handler +} + +func (rl *requestLogger) ServeHTTP(resp http.ResponseWriter, req *http.Request) { + fmt.Printf("web <= %v %v <= %v\n", req.Method, req.URL.String(), req.Header["X-Real-Ip"]) + rl.handler.ServeHTTP(resp, req) +} diff --git a/go.mod b/go.mod index c6a3959a..9bf2d188 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.18 require ( github.com/charmbracelet/lipgloss v0.6.0 - github.com/gizak/termui/v3 v3.1.0 github.com/go-openapi/errors v0.20.2 github.com/go-openapi/loads v0.21.1 github.com/go-openapi/runtime v0.24.1 @@ -15,13 +14,13 @@ require ( github.com/iancoleman/strcase v0.2.0 github.com/influxdata/influxdb-client-go/v2 v2.11.0 github.com/jaevor/go-nanoid v1.3.0 + github.com/jedib0t/go-pretty/v6 v6.4.3 github.com/jessevdk/go-flags v1.5.0 github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.0 github.com/mattn/go-sqlite3 v1.14.14 github.com/michaelquigley/cf v0.0.13 github.com/michaelquigley/pfxlog v0.6.9 - github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d github.com/opentracing/opentracing-go v1.2.0 github.com/openziti/edge v0.22.39 github.com/openziti/foundation/v2 v2.0.4 @@ -31,9 +30,7 @@ require ( github.com/shirou/gopsutil/v3 v3.22.8 github.com/sirupsen/logrus v1.9.0 github.com/spf13/cobra v1.5.0 - github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.1 - github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569 github.com/wneessen/go-mail v0.2.7 golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 @@ -58,7 +55,6 @@ require ( github.com/google/uuid v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect - github.com/jedib0t/go-pretty/v6 v6.4.3 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect @@ -69,7 +65,6 @@ require ( github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect github.com/miekg/pkcs11 v1.1.1 // indirect github.com/mitchellh/go-ps v1.0.0 // indirect - github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68 // indirect github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0 // indirect @@ -86,6 +81,7 @@ require ( github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/speps/go-hashids v2.0.0+incompatible // indirect + github.com/spf13/pflag v1.0.5 // indirect github.com/tklauser/go-sysconf v0.3.10 // indirect github.com/tklauser/numcpus v0.4.0 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect diff --git a/go.sum b/go.sum index a0feeb01..d6f5b9cd 100644 --- a/go.sum +++ b/go.sum @@ -100,8 +100,6 @@ github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa h1:RDBNVkRviHZtvD github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gizak/termui/v3 v3.1.0 h1:ZZmVDgwHl7gR7elfKf1xc4IudXZ5qqfDh4wExk4Iajc= -github.com/gizak/termui/v3 v3.1.0/go.mod h1:bXQEBkJpzxUAKf0+xq9MSWAvWZlE7c+aidmyFlkYTrY= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -362,7 +360,6 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= @@ -388,8 +385,6 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM= -github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -411,8 +406,6 @@ github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ github.com/netfoundry/secretstream v0.1.2 h1:NgqrYytDnjKbOfWI29TT0SJM+RwB3yf9MIkJVJaU+J0= github.com/netfoundry/secretstream v0.1.2/go.mod h1:uasYkYSp0MmNSlKOWJ2sVzxPms8e58TS4ENq4yro86k= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840= -github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= @@ -520,8 +513,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569 h1:xzABM9let0HLLqFypcxvLmlvEciCHL7+Lv+4vwZqecI= -github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569/go.mod h1:2Ly+NIftZN4de9zRmENdYbvPQeaVIYKWpLFStLFEBgI= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw= From 2ec8a07d4b20824fd1c04b2081b436cdba99c98c Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Mon, 9 Jan 2023 17:31:45 -0500 Subject: [PATCH 06/32] more tolerance in zrokdir metadata checking (#134) --- zrokdir/version.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zrokdir/version.go b/zrokdir/version.go index 0f191cfb..57f43068 100644 --- a/zrokdir/version.go +++ b/zrokdir/version.go @@ -3,6 +3,7 @@ package zrokdir import ( "encoding/json" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "os" ) @@ -19,7 +20,8 @@ func checkMetadata() error { } data, err := os.ReadFile(mf) if err != nil { - return errors.Wrapf(err, "error reading metadata file '%v'", mf) + logrus.Warnf("unable to read zrokdir metadata; ignoring non-existent: %v", err) + return nil } m := &Metadata{} if err := json.Unmarshal(data, m); err != nil { From 03172244cc396a7e1fcb25defd79cc31548041cf Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Mon, 9 Jan 2023 17:37:43 -0500 Subject: [PATCH 07/32] if there is not an identities path, just skip listing identities (#136) --- zrokdir/zrokdir.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/zrokdir/zrokdir.go b/zrokdir/zrokdir.go index a81a433b..9c8d0c71 100644 --- a/zrokdir/zrokdir.go +++ b/zrokdir/zrokdir.go @@ -104,15 +104,23 @@ func Obliterate() error { } func listIdentities() (map[string]struct{}, error) { + ids := make(map[string]struct{}) + idd, err := identitiesDir() if err != nil { return nil, errors.Wrap(err, "error getting zrokdir identities path") } + _, err = os.Stat(idd) + if os.IsNotExist(err) { + return ids, nil + } + if err != nil { + return nil, errors.Wrapf(err, "error stat-ing zrokdir identities root '%v'", idd) + } des, err := os.ReadDir(idd) if err != nil { return nil, errors.Wrapf(err, "error listing zrokdir identities from '%v'", idd) } - ids := make(map[string]struct{}) for _, de := range des { if strings.HasSuffix(de.Name(), ".json") && !de.IsDir() { name := strings.TrimSuffix(de.Name(), ".json") From 38318c68e2e0c31359ebea53acf5ef8282041f2a Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Mon, 9 Jan 2023 17:48:19 -0500 Subject: [PATCH 08/32] tui; warning --- cmd/zrok/accessPrivate.go | 15 ++++++++------- cmd/zrok/accessPublic.go | 7 ++++--- cmd/zrok/disable.go | 11 ++++++----- cmd/zrok/enable.go | 7 ++++--- cmd/zrok/invite.go | 11 ++++++----- cmd/zrok/loop.go | 3 ++- cmd/zrok/release.go | 9 +++++---- cmd/zrok/reserve.go | 13 +++++++------ cmd/zrok/sharePrivate.go | 21 +++++++++++---------- cmd/zrok/sharePublic.go | 21 +++++++++++---------- cmd/zrok/shareReserved.go | 19 ++++++++++--------- cmd/zrok/status.go | 11 ++++++----- cmd/zrok/testEndpoint.go | 5 +++-- cmd/zrok/util.go | 18 ------------------ cmd/zrok/version.go | 3 ++- tui/messages.go | 27 +++++++++++++++++++++++++++ zrokdir/version.go | 4 ++-- 17 files changed, 114 insertions(+), 91 deletions(-) create mode 100644 tui/messages.go diff --git a/cmd/zrok/accessPrivate.go b/cmd/zrok/accessPrivate.go index 798001d2..7346c30e 100644 --- a/cmd/zrok/accessPrivate.go +++ b/cmd/zrok/accessPrivate.go @@ -7,6 +7,7 @@ import ( "github.com/openziti-test-kitchen/zrok/rest_client_zrok" "github.com/openziti-test-kitchen/zrok/rest_client_zrok/share" "github.com/openziti-test-kitchen/zrok/rest_model_zrok" + "github.com/openziti-test-kitchen/zrok/tui" "github.com/openziti-test-kitchen/zrok/zrokdir" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -43,24 +44,24 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) { endpointUrl, err := url.Parse("http://" + cmd.bindAddress) if err != nil { if !panicInstead { - showError("invalid endpoint address", err) + tui.Error("invalid endpoint address", err) } panic(err) } zrd, err := zrokdir.Load() if err != nil { - showError("unable to load zrokdir", err) + tui.Error("unable to load zrokdir", err) } if zrd.Env == nil { - showError("unable to load environment; did you 'zrok enable'?", nil) + tui.Error("unable to load environment; did you 'zrok enable'?", nil) } zrok, err := zrd.Client() if err != nil { if !panicInstead { - showError("unable to create zrok client", err) + tui.Error("unable to create zrok client", err) } panic(err) } @@ -74,7 +75,7 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) { accessResp, err := zrok.Share.Access(req, auth) if err != nil { if !panicInstead { - showError("unable to access", err) + tui.Error("unable to access", err) } panic(err) } @@ -95,7 +96,7 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) { frontend, err := privateFrontend.NewHTTP(cfg) if err != nil { if !panicInstead { - showError("unable to create private frontend", err) + tui.Error("unable to create private frontend", err) } panic(err) } @@ -104,7 +105,7 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) { if err := frontend.Run(); err != nil { if !panicInstead { - showError("unable to run frontend", err) + tui.Error("unable to run frontend", err) } } } diff --git a/cmd/zrok/accessPublic.go b/cmd/zrok/accessPublic.go index 6a7ef637..9e08f471 100644 --- a/cmd/zrok/accessPublic.go +++ b/cmd/zrok/accessPublic.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/michaelquigley/cf" "github.com/openziti-test-kitchen/zrok/endpoints/publicFrontend" + "github.com/openziti-test-kitchen/zrok/tui" "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -33,7 +34,7 @@ func (self *accessPublicCommand) run(_ *cobra.Command, args []string) { if len(args) == 1 { if err := cfg.Load(args[0]); err != nil { if !panicInstead { - showError(fmt.Sprintf("unable to load configuration '%v'", args[0]), err) + tui.Error(fmt.Sprintf("unable to load configuration '%v'", args[0]), err) } panic(err) } @@ -42,13 +43,13 @@ func (self *accessPublicCommand) run(_ *cobra.Command, args []string) { frontend, err := publicFrontend.NewHTTP(cfg) if err != nil { if !panicInstead { - showError("unable to create http frontend", err) + tui.Error("unable to create http frontend", err) } panic(err) } if err := frontend.Run(); err != nil { if !panicInstead { - showError("unable to run http frontend", err) + tui.Error("unable to run http frontend", err) } panic(err) } diff --git a/cmd/zrok/disable.go b/cmd/zrok/disable.go index 7df40a03..f305eac7 100644 --- a/cmd/zrok/disable.go +++ b/cmd/zrok/disable.go @@ -5,6 +5,7 @@ import ( httptransport "github.com/go-openapi/runtime/client" "github.com/openziti-test-kitchen/zrok/rest_client_zrok/environment" "github.com/openziti-test-kitchen/zrok/rest_model_zrok" + "github.com/openziti-test-kitchen/zrok/tui" "github.com/openziti-test-kitchen/zrok/zrokdir" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -33,19 +34,19 @@ func (cmd *disableCommand) run(_ *cobra.Command, _ []string) { zrd, err := zrokdir.Load() if err != nil { if !panicInstead { - showError("unable to load zrokdir", err) + tui.Error("unable to load zrokdir", err) } panic(err) } if zrd.Env == nil { - showError("no environment found; nothing to disable!", nil) + tui.Error("no environment found; nothing to disable!", nil) } zrok, err := zrd.Client() if err != nil { if !panicInstead { - showError("could not create zrok client", err) + tui.Error("could not create zrok client", err) } panic(err) } @@ -60,13 +61,13 @@ func (cmd *disableCommand) run(_ *cobra.Command, _ []string) { } if err := zrokdir.DeleteEnvironment(); err != nil { if !panicInstead { - showError("error removing zrok environment", err) + tui.Error("error removing zrok environment", err) } panic(err) } if err := zrokdir.DeleteZitiIdentity("backend"); err != nil { if !panicInstead { - showError("error removing zrok backend identity", err) + tui.Error("error removing zrok backend identity", err) } } fmt.Printf("zrok environment '%v' disabled for '%v'\n", zrd.Env.ZId, zrd.Env.Token) diff --git a/cmd/zrok/enable.go b/cmd/zrok/enable.go index 9469e60c..e220123d 100644 --- a/cmd/zrok/enable.go +++ b/cmd/zrok/enable.go @@ -5,6 +5,7 @@ import ( httptransport "github.com/go-openapi/runtime/client" "github.com/openziti-test-kitchen/zrok/rest_client_zrok/environment" "github.com/openziti-test-kitchen/zrok/rest_model_zrok" + "github.com/openziti-test-kitchen/zrok/tui" "github.com/openziti-test-kitchen/zrok/zrokdir" "github.com/shirou/gopsutil/v3/host" "github.com/spf13/cobra" @@ -65,7 +66,7 @@ func (cmd *enableCommand) run(_ *cobra.Command, args []string) { resp, err := zrok.Environment.Enable(req, auth) if err != nil { if !panicInstead { - showError("the zrok service returned an error", err) + tui.Error("the zrok service returned an error", err) } panic(err) } @@ -73,13 +74,13 @@ func (cmd *enableCommand) run(_ *cobra.Command, args []string) { zrd.Env = &zrokdir.Environment{Token: token, ZId: resp.Payload.Identity, ApiEndpoint: apiEndpoint} if err := zrd.Save(); err != nil { if !panicInstead { - showError("there was an error saving the new environment", err) + tui.Error("there was an error saving the new environment", err) } panic(err) } if err := zrokdir.SaveZitiIdentity("backend", resp.Payload.Cfg); err != nil { if !panicInstead { - showError("there was an error writing the environment file", err) + tui.Error("there was an error writing the environment file", err) } panic(err) } diff --git a/cmd/zrok/invite.go b/cmd/zrok/invite.go index 9654d363..8a5a91d4 100644 --- a/cmd/zrok/invite.go +++ b/cmd/zrok/invite.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/openziti-test-kitchen/zrok/rest_client_zrok/account" "github.com/openziti-test-kitchen/zrok/rest_model_zrok" + "github.com/openziti-test-kitchen/zrok/tui" "github.com/openziti-test-kitchen/zrok/util" "github.com/openziti-test-kitchen/zrok/zrokdir" "github.com/openziti/foundation/v2/term" @@ -35,25 +36,25 @@ func (cmd *inviteCommand) run(_ *cobra.Command, _ []string) { panic(err) } if !util.IsValidEmail(email) { - showError(fmt.Sprintf("'%v' is not a valid email address", email), nil) + tui.Error(fmt.Sprintf("'%v' is not a valid email address", email), nil) } confirm, err := term.Prompt("Confirm Email: ") if err != nil { panic(err) } if confirm != email { - showError("entered emails do not match... aborting!", nil) + tui.Error("entered emails do not match... aborting!", nil) } zrd, err := zrokdir.Load() if err != nil { - showError("error loading zrokdir", err) + tui.Error("error loading zrokdir", err) } zrok, err := zrd.Client() if err != nil { if !panicInstead { - showError("error creating zrok api client", err) + tui.Error("error creating zrok api client", err) } panic(err) } @@ -64,7 +65,7 @@ func (cmd *inviteCommand) run(_ *cobra.Command, _ []string) { _, err = zrok.Account.Invite(req) if err != nil { if !panicInstead { - showError("error creating invitation", err) + tui.Error("error creating invitation", err) } panic(err) } diff --git a/cmd/zrok/loop.go b/cmd/zrok/loop.go index 74bd3778..71486a99 100644 --- a/cmd/zrok/loop.go +++ b/cmd/zrok/loop.go @@ -10,6 +10,7 @@ import ( "github.com/openziti-test-kitchen/zrok/rest_client_zrok" "github.com/openziti-test-kitchen/zrok/rest_client_zrok/share" "github.com/openziti-test-kitchen/zrok/rest_model_zrok" + "github.com/openziti-test-kitchen/zrok/tui" "github.com/openziti-test-kitchen/zrok/util" "github.com/openziti-test-kitchen/zrok/zrokdir" "github.com/openziti/sdk-golang/ziti" @@ -176,7 +177,7 @@ func (l *looper) startup() { } if zrd.Env == nil { - showError("unable to load environment; did you 'zrok enable'?", nil) + tui.Error("unable to load environment; did you 'zrok enable'?", nil) } l.env = zrd.Env diff --git a/cmd/zrok/release.go b/cmd/zrok/release.go index f16e4b8a..a86ea2a9 100644 --- a/cmd/zrok/release.go +++ b/cmd/zrok/release.go @@ -4,6 +4,7 @@ import ( httptransport "github.com/go-openapi/runtime/client" "github.com/openziti-test-kitchen/zrok/rest_client_zrok/share" "github.com/openziti-test-kitchen/zrok/rest_model_zrok" + "github.com/openziti-test-kitchen/zrok/tui" "github.com/openziti-test-kitchen/zrok/zrokdir" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -33,19 +34,19 @@ func (cmd *releaseCommand) run(_ *cobra.Command, args []string) { zrd, err := zrokdir.Load() if err != nil { if !panicInstead { - showError("unable to load zrokdir", err) + tui.Error("unable to load zrokdir", err) } panic(err) } if zrd.Env == nil { - showError("unable to load environment; did you 'zrok enable'?", nil) + tui.Error("unable to load environment; did you 'zrok enable'?", nil) } zrok, err := zrd.Client() if err != nil { if !panicInstead { - showError("unable to create zrok client", err) + tui.Error("unable to create zrok client", err) } panic(err) } @@ -59,7 +60,7 @@ func (cmd *releaseCommand) run(_ *cobra.Command, args []string) { } if _, err := zrok.Share.Unshare(req, auth); err != nil { if !panicInstead { - showError("error releasing share", err) + tui.Error("error releasing share", err) } panic(err) } diff --git a/cmd/zrok/reserve.go b/cmd/zrok/reserve.go index 50e315b3..501639e5 100644 --- a/cmd/zrok/reserve.go +++ b/cmd/zrok/reserve.go @@ -5,6 +5,7 @@ import ( "github.com/openziti-test-kitchen/zrok/model" "github.com/openziti-test-kitchen/zrok/rest_client_zrok/share" "github.com/openziti-test-kitchen/zrok/rest_model_zrok" + "github.com/openziti-test-kitchen/zrok/tui" "github.com/openziti-test-kitchen/zrok/zrokdir" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -39,13 +40,13 @@ func newReserveCommand() *reserveCommand { func (cmd *reserveCommand) run(_ *cobra.Command, args []string) { shareMode := args[0] if shareMode != "public" && shareMode != "private" { - showError("invalid sharing mode; expecting 'public' or 'private'", nil) + tui.Error("invalid sharing mode; expecting 'public' or 'private'", nil) } targetEndpoint, err := url.Parse(args[1]) if err != nil { if !panicInstead { - showError("invalid target endpoint URL", err) + tui.Error("invalid target endpoint URL", err) } panic(err) } @@ -56,19 +57,19 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) { zrd, err := zrokdir.Load() if err != nil { if !panicInstead { - showError("error loading zrokdir", err) + tui.Error("error loading zrokdir", err) } panic(err) } if zrd.Env == nil { - showError("unable to load environment; did you 'zrok enable'?", nil) + tui.Error("unable to load environment; did you 'zrok enable'?", nil) } zrok, err := zrd.Client() if err != nil { if !panicInstead { - showError("unable to create zrok client", err) + tui.Error("unable to create zrok client", err) } panic(err) } @@ -101,7 +102,7 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) { resp, err := zrok.Share.Share(req, auth) if err != nil { if !panicInstead { - showError("unable to create tunnel", err) + tui.Error("unable to create tunnel", err) } panic(err) } diff --git a/cmd/zrok/sharePrivate.go b/cmd/zrok/sharePrivate.go index 0ee7c686..f13e6c2d 100644 --- a/cmd/zrok/sharePrivate.go +++ b/cmd/zrok/sharePrivate.go @@ -10,6 +10,7 @@ import ( "github.com/openziti-test-kitchen/zrok/rest_client_zrok" "github.com/openziti-test-kitchen/zrok/rest_client_zrok/share" "github.com/openziti-test-kitchen/zrok/rest_model_zrok" + "github.com/openziti-test-kitchen/zrok/tui" "github.com/openziti-test-kitchen/zrok/zrokdir" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -53,7 +54,7 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { targetEndpoint, err := url.Parse(args[0]) if err != nil { if !panicInstead { - showError("invalid target endpoint URL", err) + tui.Error("invalid target endpoint URL", err) } panic(err) } @@ -66,25 +67,25 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { target = args[0] default: - showError(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web}", cmd.backendMode), nil) + tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web}", cmd.backendMode), nil) } zrd, err := zrokdir.Load() if err != nil { if !panicInstead { - showError("unable to load zrokdir", err) + tui.Error("unable to load zrokdir", err) } panic(err) } if zrd.Env == nil { - showError("unable to load environment; did you 'zrok enable'?", nil) + tui.Error("unable to load environment; did you 'zrok enable'?", nil) } zif, err := zrokdir.ZitiIdentityFile("backend") if err != nil { if !panicInstead { - showError("unable to load ziti identity configuration", err) + tui.Error("unable to load ziti identity configuration", err) } panic(err) } @@ -92,7 +93,7 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { zrok, err := zrd.Client() if err != nil { if !panicInstead { - showError("unable to create zrok client", err) + tui.Error("unable to create zrok client", err) } panic(err) } @@ -121,7 +122,7 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { resp, err := zrok.Share.Share(req, auth) if err != nil { if !panicInstead { - showError("unable to create share", err) + tui.Error("unable to create share", err) } panic(err) } @@ -144,7 +145,7 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { _, err = cmd.proxyBackendMode(cfg) if err != nil { if !panicInstead { - showError("unable to create proxy backend handler", err) + tui.Error("unable to create proxy backend handler", err) } panic(err) } @@ -158,13 +159,13 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { _, err = cmd.webBackendMode(cfg) if err != nil { if !panicInstead { - showError("unable to create web backend handler", err) + tui.Error("unable to create web backend handler", err) } panic(err) } default: - showError("invalid backend mode", nil) + tui.Error("invalid backend mode", nil) } logrus.Infof("share with others; they will use this command for access: 'zrok access private %v'", resp.Payload.ShrToken) diff --git a/cmd/zrok/sharePublic.go b/cmd/zrok/sharePublic.go index 0163f94b..894b05c0 100644 --- a/cmd/zrok/sharePublic.go +++ b/cmd/zrok/sharePublic.go @@ -10,6 +10,7 @@ import ( "github.com/openziti-test-kitchen/zrok/rest_client_zrok" "github.com/openziti-test-kitchen/zrok/rest_client_zrok/share" "github.com/openziti-test-kitchen/zrok/rest_model_zrok" + "github.com/openziti-test-kitchen/zrok/tui" "github.com/openziti-test-kitchen/zrok/zrokdir" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -55,7 +56,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { targetEndpoint, err := url.Parse(args[0]) if err != nil { if !panicInstead { - showError("invalid target endpoint URL", err) + tui.Error("invalid target endpoint URL", err) } panic(err) } @@ -68,25 +69,25 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { target = args[0] default: - showError(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web}", cmd.backendMode), nil) + tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web}", cmd.backendMode), nil) } zrd, err := zrokdir.Load() if err != nil { if !panicInstead { - showError("unable to load zrokdir", nil) + tui.Error("unable to load zrokdir", nil) } panic(err) } if zrd.Env == nil { - showError("unable to load environment; did you 'zrok enable'?", nil) + tui.Error("unable to load environment; did you 'zrok enable'?", nil) } zif, err := zrokdir.ZitiIdentityFile("backend") if err != nil { if !panicInstead { - showError("unable to load ziti identity configuration", err) + tui.Error("unable to load ziti identity configuration", err) } panic(err) } @@ -94,7 +95,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { zrok, err := zrd.Client() if err != nil { if !panicInstead { - showError("unable to create zrok client", err) + tui.Error("unable to create zrok client", err) } panic(err) } @@ -123,7 +124,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { resp, err := zrok.Share.Share(req, auth) if err != nil { if !panicInstead { - showError("unable to create tunnel", err) + tui.Error("unable to create tunnel", err) } panic(err) } @@ -147,7 +148,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { bh, err = cmd.proxyBackendMode(cfg) if err != nil { if !panicInstead { - showError("unable to create proxy backend handler", err) + tui.Error("unable to create proxy backend handler", err) } panic(err) } @@ -161,13 +162,13 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { bh, err = cmd.webBackendMode(cfg) if err != nil { if !panicInstead { - showError("unable to create web backend handler", err) + tui.Error("unable to create web backend handler", err) } panic(err) } default: - showError("invalid backend mode", nil) + tui.Error("invalid backend mode", nil) } logrus.Infof("access your zrok share: %v", resp.Payload.FrontendProxyEndpoints[0]) diff --git a/cmd/zrok/shareReserved.go b/cmd/zrok/shareReserved.go index c0ea9f86..2b7e8617 100644 --- a/cmd/zrok/shareReserved.go +++ b/cmd/zrok/shareReserved.go @@ -6,6 +6,7 @@ import ( "github.com/openziti-test-kitchen/zrok/rest_client_zrok/metadata" "github.com/openziti-test-kitchen/zrok/rest_client_zrok/share" "github.com/openziti-test-kitchen/zrok/rest_model_zrok" + "github.com/openziti-test-kitchen/zrok/tui" "github.com/openziti-test-kitchen/zrok/zrokdir" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -40,7 +41,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { e, err := url.Parse(cmd.overrideEndpoint) if err != nil { if !panicInstead { - showError("invalid override endpoint URL", err) + tui.Error("invalid override endpoint URL", err) } panic(err) } @@ -53,19 +54,19 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { zrd, err := zrokdir.Load() if err != nil { if !panicInstead { - showError("error loading zrokdir", err) + tui.Error("error loading zrokdir", err) } panic(err) } if zrd.Env == nil { - showError("unable to load environment; did you 'zrok enable'?", nil) + tui.Error("unable to load environment; did you 'zrok enable'?", nil) } zrok, err := zrd.Client() if err != nil { if !panicInstead { - showError("unable to create zrok client", err) + tui.Error("unable to create zrok client", err) } panic(err) } @@ -75,7 +76,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { resp, err := zrok.Metadata.GetShareDetail(req, auth) if err != nil { if !panicInstead { - showError("unable to retrieve reserved share", err) + tui.Error("unable to retrieve reserved share", err) } panic(err) } @@ -86,7 +87,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { zif, err := zrokdir.ZitiIdentityFile("backend") if err != nil { if !panicInstead { - showError("unable to load ziti identity configuration", err) + tui.Error("unable to load ziti identity configuration", err) } panic(err) } @@ -105,7 +106,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { } if _, err := zrok.Share.UpdateShare(upReq, auth); err != nil { if !panicInstead { - showError("unable to update backend proxy endpoint", err) + tui.Error("unable to update backend proxy endpoint", err) } panic(err) } @@ -117,7 +118,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { httpProxy, err := proxyBackend.NewBackend(cfg) if err != nil { if !panicInstead { - showError("unable to create http backend", err) + tui.Error("unable to create http backend", err) } panic(err) } @@ -125,7 +126,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { go func() { if err := httpProxy.Run(); err != nil { if !panicInstead { - showError("unable to run http proxy", err) + tui.Error("unable to run http proxy", err) } panic(err) } diff --git a/cmd/zrok/status.go b/cmd/zrok/status.go index 3d8620cb..4533a06f 100644 --- a/cmd/zrok/status.go +++ b/cmd/zrok/status.go @@ -3,6 +3,7 @@ package main import ( "fmt" "github.com/jedib0t/go-pretty/v6/table" + "github.com/openziti-test-kitchen/zrok/tui" "github.com/openziti-test-kitchen/zrok/zrokdir" "github.com/spf13/cobra" "os" @@ -33,10 +34,10 @@ func (cmd *statusCommand) run(_ *cobra.Command, _ []string) { zrd, err := zrokdir.Load() if err != nil { - showError("unable to load zrokdir", err) + tui.Error("unable to load zrokdir", err) } - _, _ = fmt.Fprintf(os.Stdout, codeStyle.Render("Config")+":\n\n") + _, _ = fmt.Fprintf(os.Stdout, tui.CodeStyle.Render("Config")+":\n\n") t := table.NewWriter() t.SetOutputMirror(os.Stdout) t.SetStyle(table.StyleColoredDark) @@ -47,10 +48,10 @@ func (cmd *statusCommand) run(_ *cobra.Command, _ []string) { _, _ = fmt.Fprintf(os.Stderr, "\n") if zrd.Env == nil { - _, _ = fmt.Fprintf(os.Stderr, "%v: Unable to load your local environment!\n\n", warningLabel) - _, _ = fmt.Fprintf(os.Stderr, "To create a local environment use the %v command.\n", codeStyle.Render("zrok enable")) + _, _ = fmt.Fprintf(os.Stderr, "%v: Unable to load your local environment!\n\n", tui.WarningLabel) + _, _ = fmt.Fprintf(os.Stderr, "To create a local environment use the %v command.\n", tui.CodeStyle.Render("zrok enable")) } else { - _, _ = fmt.Fprintf(os.Stdout, codeStyle.Render("Environment")+":\n\n") + _, _ = fmt.Fprintf(os.Stdout, tui.CodeStyle.Render("Environment")+":\n\n") t := table.NewWriter() t.SetOutputMirror(os.Stdout) diff --git a/cmd/zrok/testEndpoint.go b/cmd/zrok/testEndpoint.go index 57cf7867..8cf61225 100644 --- a/cmd/zrok/testEndpoint.go +++ b/cmd/zrok/testEndpoint.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/opentracing/opentracing-go/log" "github.com/openziti-test-kitchen/zrok/cmd/zrok/endpointUi" + "github.com/openziti-test-kitchen/zrok/tui" "github.com/sirupsen/logrus" "github.com/spf13/cobra" "html/template" @@ -33,7 +34,7 @@ func newTestEndpointCommand() *testEndpointCommand { var err error if command.t, err = template.ParseFS(endpointUi.FS, "index.gohtml"); err != nil { if !panicInstead { - showError("unable to parse index template", err) + tui.Error("unable to parse index template", err) } panic(err) } @@ -47,7 +48,7 @@ func (cmd *testEndpointCommand) run(_ *cobra.Command, _ []string) { http.HandleFunc("/", cmd.serveIndex) if err := http.ListenAndServe(fmt.Sprintf("%v:%d", cmd.address, cmd.port), nil); err != nil { if !panicInstead { - showError("unable to start http listener", err) + tui.Error("unable to start http listener", err) } panic(err) } diff --git a/cmd/zrok/util.go b/cmd/zrok/util.go index 17cbb9b4..be53c919 100644 --- a/cmd/zrok/util.go +++ b/cmd/zrok/util.go @@ -1,12 +1,9 @@ package main import ( - "fmt" - "github.com/charmbracelet/lipgloss" "github.com/go-openapi/runtime" httptransport "github.com/go-openapi/runtime/client" "os" - "strings" ) type backendHandler interface { @@ -20,18 +17,3 @@ func mustGetAdminAuth() runtime.ClientAuthInfoWriter { } return httptransport.APIKeyAuth("X-TOKEN", "header", adminToken) } - -var errorStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#D90166")) -var errorLabel = errorStyle.Render("ERROR") -var warningStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFA500")) -var warningLabel = warningStyle.Render("WARNING") -var codeStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#00FFFF")) - -func showError(msg string, err error) { - if err != nil { - _, _ = fmt.Fprintf(os.Stderr, "%v: %v (%v)\n", errorLabel, msg, strings.TrimSpace(err.Error())) - } else { - _, _ = fmt.Fprintf(os.Stderr, "%v %v\n", errorLabel, msg) - } - os.Exit(1) -} diff --git a/cmd/zrok/version.go b/cmd/zrok/version.go index 84829686..23079c1a 100644 --- a/cmd/zrok/version.go +++ b/cmd/zrok/version.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/charmbracelet/lipgloss" "github.com/openziti-test-kitchen/zrok/build" + "github.com/openziti-test-kitchen/zrok/tui" "github.com/spf13/cobra" ) @@ -27,5 +28,5 @@ func newVersionCommand() *versionCommand { func (cmd *versionCommand) run(_ *cobra.Command, _ []string) { zrokStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#FF00EE")) - fmt.Println(zrokStyle.Render(" _ \n _____ __ ___ | | __\n|_ / '__/ _ \\| |/ /\n / /| | | (_) | < \n/___|_| \\___/|_|\\_\\") + "\n\n" + codeStyle.Render(build.String()) + "\n") + fmt.Println(zrokStyle.Render(" _ \n _____ __ ___ | | __\n|_ / '__/ _ \\| |/ /\n / /| | | (_) | < \n/___|_| \\___/|_|\\_\\") + "\n\n" + tui.CodeStyle.Render(build.String()) + "\n") } diff --git a/tui/messages.go b/tui/messages.go new file mode 100644 index 00000000..16331812 --- /dev/null +++ b/tui/messages.go @@ -0,0 +1,27 @@ +package tui + +import ( + "fmt" + "github.com/charmbracelet/lipgloss" + "os" + "strings" +) + +var ErrorStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#D90166")) +var ErrorLabel = ErrorStyle.Render("ERROR") +var WarningStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFA500")) +var WarningLabel = WarningStyle.Render("WARNING") +var CodeStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#00FFFF")) + +func Error(msg string, err error) { + if err != nil { + _, _ = fmt.Fprintf(os.Stderr, "%v: %v (%v)\n", ErrorLabel, msg, strings.TrimSpace(err.Error())) + } else { + _, _ = fmt.Fprintf(os.Stderr, "%v %v\n", ErrorLabel, msg) + } + os.Exit(1) +} + +func Warning(msg string, v ...interface{}) { + _, _ = fmt.Fprintf(os.Stderr, "%v: "+msg, v...) +} diff --git a/zrokdir/version.go b/zrokdir/version.go index 57f43068..8a4f5462 100644 --- a/zrokdir/version.go +++ b/zrokdir/version.go @@ -2,8 +2,8 @@ package zrokdir import ( "encoding/json" + "github.com/openziti-test-kitchen/zrok/tui" "github.com/pkg/errors" - "github.com/sirupsen/logrus" "os" ) @@ -20,7 +20,7 @@ func checkMetadata() error { } data, err := os.ReadFile(mf) if err != nil { - logrus.Warnf("unable to read zrokdir metadata; ignoring non-existent: %v", err) + tui.Warning("unable to open zrokdir metadata; ignoring") return nil } m := &Metadata{} From b1de849714fa535035c6ac5f39f2d5732d357f2d Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Mon, 9 Jan 2023 17:51:05 -0500 Subject: [PATCH 09/32] warning --- tui/messages.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tui/messages.go b/tui/messages.go index 16331812..27e49240 100644 --- a/tui/messages.go +++ b/tui/messages.go @@ -23,5 +23,5 @@ func Error(msg string, err error) { } func Warning(msg string, v ...interface{}) { - _, _ = fmt.Fprintf(os.Stderr, "%v: "+msg, v...) + _, _ = fmt.Fprintf(os.Stderr, "%v: "+msg, append([]interface{}{WarningLabel}, v...)) } From 3093bd230dc1e536b9ee263252f49adba7ffb131 Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Mon, 9 Jan 2023 17:51:41 -0500 Subject: [PATCH 10/32] formatting --- tui/messages.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tui/messages.go b/tui/messages.go index 27e49240..d76073cd 100644 --- a/tui/messages.go +++ b/tui/messages.go @@ -23,5 +23,5 @@ func Error(msg string, err error) { } func Warning(msg string, v ...interface{}) { - _, _ = fmt.Fprintf(os.Stderr, "%v: "+msg, append([]interface{}{WarningLabel}, v...)) + _, _ = fmt.Fprintf(os.Stderr, "%v: "+msg+"\n", append([]interface{}{WarningLabel}, v...)) } From 6cec74c2ecd73f529506880454315711544d5a5d Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Mon, 9 Jan 2023 17:56:16 -0500 Subject: [PATCH 11/32] tui --- cmd/zrok/status.go | 2 +- tui/messages.go | 4 ++-- zrokdir/version.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/zrok/status.go b/cmd/zrok/status.go index 4533a06f..2f70e52e 100644 --- a/cmd/zrok/status.go +++ b/cmd/zrok/status.go @@ -48,7 +48,7 @@ func (cmd *statusCommand) run(_ *cobra.Command, _ []string) { _, _ = fmt.Fprintf(os.Stderr, "\n") if zrd.Env == nil { - _, _ = fmt.Fprintf(os.Stderr, "%v: Unable to load your local environment!\n\n", tui.WarningLabel) + tui.Warning("Unable to load your local environment!\n") _, _ = fmt.Fprintf(os.Stderr, "To create a local environment use the %v command.\n", tui.CodeStyle.Render("zrok enable")) } else { _, _ = fmt.Fprintf(os.Stdout, tui.CodeStyle.Render("Environment")+":\n\n") diff --git a/tui/messages.go b/tui/messages.go index d76073cd..5c67251c 100644 --- a/tui/messages.go +++ b/tui/messages.go @@ -15,9 +15,9 @@ var CodeStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#00FFFF")) func Error(msg string, err error) { if err != nil { - _, _ = fmt.Fprintf(os.Stderr, "%v: %v (%v)\n", ErrorLabel, msg, strings.TrimSpace(err.Error())) + _, _ = fmt.Fprintf(os.Stderr, "[%v]: %v (%v)\n", ErrorLabel, msg, strings.TrimSpace(err.Error())) } else { - _, _ = fmt.Fprintf(os.Stderr, "%v %v\n", ErrorLabel, msg) + _, _ = fmt.Fprintf(os.Stderr, "[%v] %v\n", ErrorLabel, msg) } os.Exit(1) } diff --git a/zrokdir/version.go b/zrokdir/version.go index 8a4f5462..792a55a1 100644 --- a/zrokdir/version.go +++ b/zrokdir/version.go @@ -20,7 +20,7 @@ func checkMetadata() error { } data, err := os.ReadFile(mf) if err != nil { - tui.Warning("unable to open zrokdir metadata; ignoring") + tui.Warning("unable to open zrokdir metadata; ignoring\n") return nil } m := &Metadata{} From c4c497b88e770c4af9e3c0bb79602bc3b2f8fcac Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Mon, 9 Jan 2023 17:57:57 -0500 Subject: [PATCH 12/32] mkdirall --- zrokdir/version.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/zrokdir/version.go b/zrokdir/version.go index 792a55a1..b7f3c5b5 100644 --- a/zrokdir/version.go +++ b/zrokdir/version.go @@ -5,6 +5,7 @@ import ( "github.com/openziti-test-kitchen/zrok/tui" "github.com/pkg/errors" "os" + "path/filepath" ) const V = "v0.3" @@ -42,6 +43,9 @@ func writeMetadata() error { if err != nil { return err } + if err := os.MkdirAll(filepath.Dir(mf), os.FileMode(0700)); err != nil { + return err + } if err := os.WriteFile(mf, data, os.FileMode(0400)); err != nil { return err } From 73d124da83d099af86cae2b6137ac8f188ba5eef Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Tue, 10 Jan 2023 13:37:33 -0500 Subject: [PATCH 13/32] tui iteration --- cmd/zrok/shareModel.go | 76 +++++++++++++++++++++++++++++++++++++++++ cmd/zrok/sharePublic.go | 21 +++++++++--- go.mod | 13 +++++-- go.sum | 23 +++++++++++-- 4 files changed, 122 insertions(+), 11 deletions(-) create mode 100644 cmd/zrok/shareModel.go diff --git a/cmd/zrok/shareModel.go b/cmd/zrok/shareModel.go new file mode 100644 index 00000000..7ccfbfc9 --- /dev/null +++ b/cmd/zrok/shareModel.go @@ -0,0 +1,76 @@ +package main + +import ( + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "strings" + "time" +) + +type shareModel struct { + shareToken string + frontendEndpoints []string + shareMode string + backendMode string + requests []*shareRequestModel + logMessages []string + width int + height int +} + +type shareRequestModel struct { + stamp time.Time + remoteAddr string + verb string + path string +} + +func newShareModel(shareToken string, frontendEndpoints []string) *shareModel { + return &shareModel{ + shareToken: shareToken, + frontendEndpoints: frontendEndpoints, + } +} + +func (m *shareModel) Init() tea.Cmd { return nil } + +func (m *shareModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.WindowSizeMsg: + m.width = msg.Width + shareHeaderStyle.Width((m.width - 4) / 2) + m.height = msg.Height + requestsStyle.Width(m.width - 2) + requestsStyle.Height(20) + case tea.KeyMsg: + switch msg.String() { + case "ctrl+c", "q": + return m, tea.Quit + } + } + + return m, nil +} + +func (m *shareModel) View() string { + topRow := lipgloss.JoinHorizontal(lipgloss.Top, + shareHeaderStyle.Render(strings.Join(m.frontendEndpoints, "\n")), + shareHeaderStyle.Render(m.shareToken), + ) + requests := requestsStyle.Render("hello") + all := lipgloss.JoinVertical(lipgloss.Left, topRow, requests) + return all +} + +var shareHeaderStyle = lipgloss.NewStyle(). + Height(3). + PaddingTop(1).PaddingLeft(2).PaddingBottom(1).PaddingRight(2). + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(lipgloss.Color("63")). + Align(lipgloss.Center) + +var requestsStyle = lipgloss.NewStyle(). + Height(3). + PaddingTop(1).PaddingLeft(2).PaddingBottom(1).PaddingRight(2). + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(lipgloss.Color("63")) diff --git a/cmd/zrok/sharePublic.go b/cmd/zrok/sharePublic.go index 894b05c0..b5c36716 100644 --- a/cmd/zrok/sharePublic.go +++ b/cmd/zrok/sharePublic.go @@ -2,6 +2,7 @@ package main import ( "fmt" + tea "github.com/charmbracelet/bubbletea" "github.com/go-openapi/runtime" httptransport "github.com/go-openapi/runtime/client" "github.com/openziti-test-kitchen/zrok/endpoints/proxyBackend" @@ -20,7 +21,6 @@ import ( "os/signal" "strings" "syscall" - "time" ) func init() { @@ -171,11 +171,22 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { tui.Error("invalid backend mode", nil) } - logrus.Infof("access your zrok share: %v", resp.Payload.FrontendProxyEndpoints[0]) - for { - time.Sleep(5 * time.Second) - logrus.Infof("requests: %d", bh.Requests()()) + //logrus.Infof("access your zrok share: %v", resp.Payload.FrontendProxyEndpoints[0]) + //for { + // time.Sleep(5 * time.Second) + // logrus.Infof("requests: %d", bh.Requests()()) + //} + + go func() { + bh.Requests()() + }() + + prg := tea.NewProgram(newShareModel(resp.Payload.ShrToken, resp.Payload.FrontendProxyEndpoints), tea.WithAltScreen()) + if _, err := prg.Run(); err != nil { + tui.Error("An error occurred", err) } + + cmd.destroy(zrd.Env.ZId, resp.Payload.ShrToken, zrok, auth) } func (cmd *sharePublicCommand) proxyBackendMode(cfg *proxyBackend.Config) (backendHandler, error) { diff --git a/go.mod b/go.mod index 9bf2d188..aa5166ee 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/openziti-test-kitchen/zrok go 1.18 require ( + github.com/charmbracelet/bubbletea v0.23.1 github.com/charmbracelet/lipgloss v0.6.0 github.com/go-openapi/errors v0.20.2 github.com/go-openapi/loads v0.21.1 @@ -39,7 +40,9 @@ require ( require ( github.com/Jeffail/gabs v1.4.0 // indirect github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect + github.com/aymanbagabas/go-osc52 v1.0.3 // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect + github.com/containerd/console v1.0.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/deepmap/oapi-codegen v1.8.2 // indirect github.com/docker/go-units v0.4.0 // indirect @@ -61,13 +64,16 @@ require ( github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.16 // indirect - github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect github.com/miekg/pkcs11 v1.1.1 // indirect github.com/mitchellh/go-ps v1.0.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68 // indirect - github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0 // indirect + github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/reflow v0.3.0 // indirect + github.com/muesli/termenv v0.13.0 // indirect github.com/netfoundry/secretstream v0.1.2 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/openziti/channel/v2 v2.0.1 // indirect @@ -90,6 +96,7 @@ require ( golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be // indirect golang.org/x/sys v0.0.0-20220926163933-8cfa568d3c25 // indirect golang.org/x/term v0.0.0-20220919170432-7a66f970e087 // indirect + golang.org/x/text v0.3.7 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index d6f5b9cd..fae55348 100644 --- a/go.sum +++ b/go.sum @@ -53,11 +53,15 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/aymanbagabas/go-osc52 v1.0.3 h1:DTwqENW7X9arYimJrPeGZcV0ln14sGMt3pHZspWD+Mg= +github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/charmbracelet/bubbletea v0.23.1 h1:CYdteX1wCiCzKNUlwm25ZHBIc1GXlYFyUIte8WPvhck= +github.com/charmbracelet/bubbletea v0.23.1/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU= github.com/charmbracelet/lipgloss v0.6.0 h1:1StyZB9vBSOyuZxQUcUwGr17JmojPNm87inij9N3wJY= github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -67,6 +71,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -359,11 +365,15 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= github.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.14 h1:qZgc/Rwetq+MtyE18WhzjokPD93dNqLGNT3QJuLvBGw= @@ -399,10 +409,16 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= -github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68 h1:y1p/ycavWjGT9FnmSjdbWUlLGvcxrY0Rw3ATltrxOhk= +github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34= +github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ= -github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0 h1:STjmj0uFfRryL9fzRA/OupNppeAID6QJYPMavTL7jtY= +github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= +github.com/muesli/termenv v0.13.0 h1:wK20DRpJdDX8b7Ek2QfhvqhRQFZ237RGRO0RQ/Iqdy0= +github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc= github.com/netfoundry/secretstream v0.1.2 h1:NgqrYytDnjKbOfWI29TT0SJM+RwB3yf9MIkJVJaU+J0= github.com/netfoundry/secretstream v0.1.2/go.mod h1:uasYkYSp0MmNSlKOWJ2sVzxPms8e58TS4ENq4yro86k= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= @@ -748,6 +764,7 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= From d984cbf832dfe1b74d095aa55493ea3daee8be4a Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Tue, 10 Jan 2023 14:05:18 -0500 Subject: [PATCH 14/32] tui elaboration (#56) --- cmd/zrok/shareModel.go | 43 +++++++++++++++++++++++++++++++++++++---- cmd/zrok/sharePublic.go | 2 +- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/cmd/zrok/shareModel.go b/cmd/zrok/shareModel.go index 7ccfbfc9..967618c8 100644 --- a/cmd/zrok/shareModel.go +++ b/cmd/zrok/shareModel.go @@ -25,10 +25,12 @@ type shareRequestModel struct { path string } -func newShareModel(shareToken string, frontendEndpoints []string) *shareModel { +func newShareModel(shareToken string, frontendEndpoints []string, shareMode, backendMode string) *shareModel { return &shareModel{ shareToken: shareToken, frontendEndpoints: frontendEndpoints, + shareMode: shareMode, + backendMode: backendMode, } } @@ -38,14 +40,18 @@ func (m *shareModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.WindowSizeMsg: m.width = msg.Width - shareHeaderStyle.Width((m.width - 4) / 2) + shareHeaderStyle.Width(m.width - 30) + configHeaderStyle.Width(26) m.height = msg.Height requestsStyle.Width(m.width - 2) - requestsStyle.Height(20) + requestsStyle.Height(m.height - (len(m.frontendEndpoints) + 6)) + case tea.KeyMsg: switch msg.String() { case "ctrl+c", "q": return m, tea.Quit + case "ctrl+l": + return m, tea.ClearScreen } } @@ -55,13 +61,30 @@ func (m *shareModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { func (m *shareModel) View() string { topRow := lipgloss.JoinHorizontal(lipgloss.Top, shareHeaderStyle.Render(strings.Join(m.frontendEndpoints, "\n")), - shareHeaderStyle.Render(m.shareToken), + configHeaderStyle.Render(m.renderConfig()), ) requests := requestsStyle.Render("hello") all := lipgloss.JoinVertical(lipgloss.Left, topRow, requests) return all } +func (m *shareModel) renderConfig() string { + out := "[" + if m.shareMode == "public" { + out += shareModePublicStyle.Render(strings.ToUpper(m.shareMode)) + } else { + out += shareModePrivateStyle.Render(strings.ToUpper(m.shareMode)) + } + out += "] [" + if m.backendMode == "proxy" { + out += backendModeProxyStyle.Render(strings.ToUpper(m.backendMode)) + } else { + out += backendModeWebStyle.Render(strings.ToUpper(m.backendMode)) + } + out += "]" + return out +} + var shareHeaderStyle = lipgloss.NewStyle(). Height(3). PaddingTop(1).PaddingLeft(2).PaddingBottom(1).PaddingRight(2). @@ -69,8 +92,20 @@ var shareHeaderStyle = lipgloss.NewStyle(). BorderForeground(lipgloss.Color("63")). Align(lipgloss.Center) +var configHeaderStyle = lipgloss.NewStyle(). + Height(3). + PaddingTop(1).PaddingLeft(2).PaddingBottom(1).PaddingRight(2). + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(lipgloss.Color("63")). + Align(lipgloss.Center) + var requestsStyle = lipgloss.NewStyle(). Height(3). PaddingTop(1).PaddingLeft(2).PaddingBottom(1).PaddingRight(2). BorderStyle(lipgloss.RoundedBorder()). BorderForeground(lipgloss.Color("63")) + +var shareModePublicStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#0F0")) +var shareModePrivateStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#F00")) +var backendModeProxyStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFA500")) +var backendModeWebStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#0CC")) diff --git a/cmd/zrok/sharePublic.go b/cmd/zrok/sharePublic.go index b5c36716..fcb443df 100644 --- a/cmd/zrok/sharePublic.go +++ b/cmd/zrok/sharePublic.go @@ -181,7 +181,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { bh.Requests()() }() - prg := tea.NewProgram(newShareModel(resp.Payload.ShrToken, resp.Payload.FrontendProxyEndpoints), tea.WithAltScreen()) + prg := tea.NewProgram(newShareModel(resp.Payload.ShrToken, resp.Payload.FrontendProxyEndpoints, "public", cmd.backendMode), tea.WithAltScreen()) if _, err := prg.Run(); err != nil { tui.Error("An error occurred", err) } From 0119e54d4361893dc0749f7784760dd24efd028b Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Tue, 10 Jan 2023 14:52:28 -0500 Subject: [PATCH 15/32] rough bubbletea tui (#56) --- cmd/zrok/shareModel.go | 55 +++++++++++++++++++++++++++------- cmd/zrok/sharePrivate.go | 5 ++-- cmd/zrok/sharePublic.go | 24 +++++++++++---- cmd/zrok/util.go | 4 --- endpoints/proxyBackend/http.go | 15 ++++++++-- endpoints/util.go | 12 ++++++++ endpoints/webBackend/web.go | 29 +++++++++++++----- 7 files changed, 113 insertions(+), 31 deletions(-) diff --git a/cmd/zrok/shareModel.go b/cmd/zrok/shareModel.go index 967618c8..efba5857 100644 --- a/cmd/zrok/shareModel.go +++ b/cmd/zrok/shareModel.go @@ -1,8 +1,10 @@ package main import ( + "fmt" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" + "github.com/openziti-test-kitchen/zrok/endpoints" "strings" "time" ) @@ -12,19 +14,12 @@ type shareModel struct { frontendEndpoints []string shareMode string backendMode string - requests []*shareRequestModel + requests []*endpoints.BackendRequest logMessages []string width int height int } -type shareRequestModel struct { - stamp time.Time - remoteAddr string - verb string - path string -} - func newShareModel(shareToken string, frontendEndpoints []string, shareMode, backendMode string) *shareModel { return &shareModel{ shareToken: shareToken, @@ -38,6 +33,12 @@ func (m *shareModel) Init() tea.Cmd { return nil } func (m *shareModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { + case *endpoints.BackendRequest: + m.requests = append([]*endpoints.BackendRequest{msg}, m.requests...) + if len(m.requests) > 2048 { + m.requests = m.requests[:2048] + } + case tea.WindowSizeMsg: m.width = msg.Width shareHeaderStyle.Width(m.width - 30) @@ -63,7 +64,7 @@ func (m *shareModel) View() string { shareHeaderStyle.Render(strings.Join(m.frontendEndpoints, "\n")), configHeaderStyle.Render(m.renderConfig()), ) - requests := requestsStyle.Render("hello") + requests := requestsStyle.Render(m.renderBackendRequests()) all := lipgloss.JoinVertical(lipgloss.Left, topRow, requests) return all } @@ -85,6 +86,35 @@ func (m *shareModel) renderConfig() string { return out } +func (m *shareModel) renderBackendRequests() string { + out := "" + maxRows := requestsStyle.GetHeight() + for i := 0; i < maxRows && i < len(m.requests); i++ { + req := m.requests[i] + out += fmt.Sprintf("%v %v -> %v %v", + timeStyle.Render(req.Stamp.Format(time.RFC850)), + addressStyle.Render(req.RemoteAddr), + m.renderMethod(req.Method), + req.Path, + ) + if i != maxRows-1 { + out += "\n" + } + } + return out +} + +func (m *shareModel) renderMethod(method string) string { + switch strings.ToLower(method) { + case "get": + return getStyle.Render(method) + case "post": + return postStyle.Render(method) + default: + return otherMethodStyle.Render(method) + } +} + var shareHeaderStyle = lipgloss.NewStyle(). Height(3). PaddingTop(1).PaddingLeft(2).PaddingBottom(1).PaddingRight(2). @@ -101,7 +131,7 @@ var configHeaderStyle = lipgloss.NewStyle(). var requestsStyle = lipgloss.NewStyle(). Height(3). - PaddingTop(1).PaddingLeft(2).PaddingBottom(1).PaddingRight(2). + PaddingLeft(2).PaddingRight(2). BorderStyle(lipgloss.RoundedBorder()). BorderForeground(lipgloss.Color("63")) @@ -109,3 +139,8 @@ var shareModePublicStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#0F0") var shareModePrivateStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#F00")) var backendModeProxyStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFA500")) var backendModeWebStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#0CC")) +var timeStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#444")) +var addressStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFA500")) +var getStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("98")) +var postStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("101")) +var otherMethodStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("166")) diff --git a/cmd/zrok/sharePrivate.go b/cmd/zrok/sharePrivate.go index f13e6c2d..bd52c06b 100644 --- a/cmd/zrok/sharePrivate.go +++ b/cmd/zrok/sharePrivate.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/go-openapi/runtime" httptransport "github.com/go-openapi/runtime/client" + "github.com/openziti-test-kitchen/zrok/endpoints" "github.com/openziti-test-kitchen/zrok/endpoints/proxyBackend" "github.com/openziti-test-kitchen/zrok/endpoints/webBackend" "github.com/openziti-test-kitchen/zrok/model" @@ -175,7 +176,7 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { } } -func (cmd *sharePrivateCommand) proxyBackendMode(cfg *proxyBackend.Config) (backendHandler, error) { +func (cmd *sharePrivateCommand) proxyBackendMode(cfg *proxyBackend.Config) (endpoints.BackendHandler, error) { be, err := proxyBackend.NewBackend(cfg) if err != nil { return nil, errors.Wrap(err, "error creating http proxy backend") @@ -190,7 +191,7 @@ func (cmd *sharePrivateCommand) proxyBackendMode(cfg *proxyBackend.Config) (back return be, nil } -func (cmd *sharePrivateCommand) webBackendMode(cfg *webBackend.Config) (backendHandler, error) { +func (cmd *sharePrivateCommand) webBackendMode(cfg *webBackend.Config) (endpoints.BackendHandler, error) { be, err := webBackend.NewBackend(cfg) if err != nil { return nil, errors.Wrap(err, "error creating http web backend") diff --git a/cmd/zrok/sharePublic.go b/cmd/zrok/sharePublic.go index fcb443df..995417d8 100644 --- a/cmd/zrok/sharePublic.go +++ b/cmd/zrok/sharePublic.go @@ -5,6 +5,7 @@ import ( tea "github.com/charmbracelet/bubbletea" "github.com/go-openapi/runtime" httptransport "github.com/go-openapi/runtime/client" + "github.com/openziti-test-kitchen/zrok/endpoints" "github.com/openziti-test-kitchen/zrok/endpoints/proxyBackend" "github.com/openziti-test-kitchen/zrok/endpoints/webBackend" "github.com/openziti-test-kitchen/zrok/model" @@ -137,13 +138,15 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { os.Exit(0) }() - var bh backendHandler + var bh endpoints.BackendHandler + requestsChan := make(chan *endpoints.BackendRequest, 1024) switch cmd.backendMode { case "proxy": cfg := &proxyBackend.Config{ IdentityPath: zif, EndpointAddress: target, ShrToken: resp.Payload.ShrToken, + RequestsChan: requestsChan, } bh, err = cmd.proxyBackendMode(cfg) if err != nil { @@ -158,6 +161,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { IdentityPath: zif, WebRoot: target, ShrToken: resp.Payload.ShrToken, + RequestsChan: requestsChan, } bh, err = cmd.webBackendMode(cfg) if err != nil { @@ -171,25 +175,35 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { tui.Error("invalid backend mode", nil) } + _ = bh.Requests()() + //logrus.Infof("access your zrok share: %v", resp.Payload.FrontendProxyEndpoints[0]) //for { // time.Sleep(5 * time.Second) // logrus.Infof("requests: %d", bh.Requests()()) //} + mdl := newShareModel(resp.Payload.ShrToken, resp.Payload.FrontendProxyEndpoints, "public", cmd.backendMode) + prg := tea.NewProgram(mdl, tea.WithAltScreen()) + go func() { - bh.Requests()() + for { + select { + case req := <-requestsChan: + prg.Send(req) + } + } }() - prg := tea.NewProgram(newShareModel(resp.Payload.ShrToken, resp.Payload.FrontendProxyEndpoints, "public", cmd.backendMode), tea.WithAltScreen()) if _, err := prg.Run(); err != nil { tui.Error("An error occurred", err) } + close(requestsChan) cmd.destroy(zrd.Env.ZId, resp.Payload.ShrToken, zrok, auth) } -func (cmd *sharePublicCommand) proxyBackendMode(cfg *proxyBackend.Config) (backendHandler, error) { +func (cmd *sharePublicCommand) proxyBackendMode(cfg *proxyBackend.Config) (endpoints.BackendHandler, error) { be, err := proxyBackend.NewBackend(cfg) if err != nil { return nil, errors.Wrap(err, "error creating http proxy backend") @@ -204,7 +218,7 @@ func (cmd *sharePublicCommand) proxyBackendMode(cfg *proxyBackend.Config) (backe return be, nil } -func (cmd *sharePublicCommand) webBackendMode(cfg *webBackend.Config) (backendHandler, error) { +func (cmd *sharePublicCommand) webBackendMode(cfg *webBackend.Config) (endpoints.BackendHandler, error) { be, err := webBackend.NewBackend(cfg) if err != nil { return nil, errors.Wrap(err, "error creating http web backend") diff --git a/cmd/zrok/util.go b/cmd/zrok/util.go index be53c919..248b43f8 100644 --- a/cmd/zrok/util.go +++ b/cmd/zrok/util.go @@ -6,10 +6,6 @@ import ( "os" ) -type backendHandler interface { - Requests() func() int32 -} - func mustGetAdminAuth() runtime.ClientAuthInfoWriter { adminToken := os.Getenv("ZROK_ADMIN_TOKEN") if adminToken == "" { diff --git a/endpoints/proxyBackend/http.go b/endpoints/proxyBackend/http.go index bf471302..970b1cb3 100644 --- a/endpoints/proxyBackend/http.go +++ b/endpoints/proxyBackend/http.go @@ -3,6 +3,7 @@ package proxyBackend import ( "context" "fmt" + "github.com/openziti-test-kitchen/zrok/endpoints" "github.com/openziti-test-kitchen/zrok/util" "github.com/openziti/sdk-golang/ziti" "github.com/openziti/sdk-golang/ziti/config" @@ -20,6 +21,7 @@ type Config struct { IdentityPath string EndpointAddress string ShrToken string + RequestsChan chan *endpoints.BackendRequest } type backend struct { @@ -43,7 +45,7 @@ func NewBackend(cfg *Config) (*backend, error) { return nil, errors.Wrap(err, "error listening") } - proxy, err := newReverseProxy(cfg.EndpointAddress) + proxy, err := newReverseProxy(cfg.EndpointAddress, cfg.RequestsChan) if err != nil { return nil, err } @@ -68,7 +70,7 @@ func (self *backend) Requests() func() int32 { return self.requests } -func newReverseProxy(target string) (*httputil.ReverseProxy, error) { +func newReverseProxy(target string, requests chan *endpoints.BackendRequest) (*httputil.ReverseProxy, error) { targetURL, err := url.Parse(target) if err != nil { return nil, err @@ -81,9 +83,16 @@ func newReverseProxy(target string) (*httputil.ReverseProxy, error) { proxy.Transport = tpt director := proxy.Director proxy.Director = func(req *http.Request) { + if requests != nil { + requests <- &endpoints.BackendRequest{ + Stamp: time.Now(), + RemoteAddr: fmt.Sprintf("%v", req.Header["X-Real-Ip"]), + Method: req.Method, + Path: req.URL.String(), + } + } fmt.Printf("proxy <= %v %v <= %v\n", req.Method, req.URL.String(), req.Header["X-Real-Ip"]) director(req) - logrus.Debugf("-> %v", req.URL.String()) req.Header.Set("X-Proxy", "zrok") } proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) { diff --git a/endpoints/util.go b/endpoints/util.go index ede4befe..2dd41fc4 100644 --- a/endpoints/util.go +++ b/endpoints/util.go @@ -6,8 +6,20 @@ import ( "github.com/sirupsen/logrus" "net/url" "strings" + "time" ) +type BackendHandler interface { + Requests() func() int32 +} + +type BackendRequest struct { + Stamp time.Time + RemoteAddr string + Method string + Path string +} + func GetRefreshedService(name string, ctx ziti.Context) (*edge.Service, bool) { svc, found := ctx.GetService(name) if !found { diff --git a/endpoints/webBackend/web.go b/endpoints/webBackend/web.go index 6023fa16..caa6f2d8 100644 --- a/endpoints/webBackend/web.go +++ b/endpoints/webBackend/web.go @@ -2,6 +2,7 @@ package webBackend import ( "fmt" + "github.com/openziti-test-kitchen/zrok/endpoints" "github.com/openziti/sdk-golang/ziti" "github.com/openziti/sdk-golang/ziti/config" "github.com/openziti/sdk-golang/ziti/edge" @@ -14,6 +15,7 @@ type Config struct { IdentityPath string WebRoot string ShrToken string + RequestsChan chan *endpoints.BackendRequest } type backend struct { @@ -36,11 +38,16 @@ func NewBackend(cfg *Config) (*backend, error) { return nil, errors.Wrap(err, "error listening") } - return &backend{ + be := &backend{ cfg: cfg, listener: listener, - handler: &requestLogger{handler: http.FileServer(http.Dir(cfg.WebRoot))}, - }, nil + } + if cfg.RequestsChan != nil { + be.handler = &requestGrabber{requests: cfg.RequestsChan, handler: http.FileServer(http.Dir(cfg.WebRoot))} + } else { + be.handler = http.FileServer(http.Dir(cfg.WebRoot)) + } + return be, nil } func (self *backend) Run() error { @@ -54,11 +61,19 @@ func (self *backend) Requests() func() int32 { return func() int32 { return 0 } } -type requestLogger struct { - handler http.Handler +type requestGrabber struct { + requests chan *endpoints.BackendRequest + handler http.Handler } -func (rl *requestLogger) ServeHTTP(resp http.ResponseWriter, req *http.Request) { - fmt.Printf("web <= %v %v <= %v\n", req.Method, req.URL.String(), req.Header["X-Real-Ip"]) +func (rl *requestGrabber) ServeHTTP(resp http.ResponseWriter, req *http.Request) { + if rl.requests != nil { + rl.requests <- &endpoints.BackendRequest{ + Stamp: time.Now(), + RemoteAddr: fmt.Sprintf("%v", req.Header["X-Real-Ip"]), + Method: req.Method, + Path: req.URL.String(), + } + } rl.handler.ServeHTTP(resp, req) } From ad3ecab2acc48330f7686ff23a4679a22b789376 Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Tue, 10 Jan 2023 15:11:39 -0500 Subject: [PATCH 16/32] headless mode for public sharing (#56) --- cmd/zrok/shareModel.go | 28 ++++++++++++++-------------- cmd/zrok/sharePublic.go | 41 ++++++++++++++++++++++++----------------- 2 files changed, 38 insertions(+), 31 deletions(-) diff --git a/cmd/zrok/shareModel.go b/cmd/zrok/shareModel.go index efba5857..a837883d 100644 --- a/cmd/zrok/shareModel.go +++ b/cmd/zrok/shareModel.go @@ -10,22 +10,22 @@ import ( ) type shareModel struct { - shareToken string - frontendEndpoints []string - shareMode string - backendMode string - requests []*endpoints.BackendRequest - logMessages []string - width int - height int + shareToken string + frontendDescriptions []string + shareMode string + backendMode string + requests []*endpoints.BackendRequest + logMessages []string + width int + height int } func newShareModel(shareToken string, frontendEndpoints []string, shareMode, backendMode string) *shareModel { return &shareModel{ - shareToken: shareToken, - frontendEndpoints: frontendEndpoints, - shareMode: shareMode, - backendMode: backendMode, + shareToken: shareToken, + frontendDescriptions: frontendEndpoints, + shareMode: shareMode, + backendMode: backendMode, } } @@ -45,7 +45,7 @@ func (m *shareModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { configHeaderStyle.Width(26) m.height = msg.Height requestsStyle.Width(m.width - 2) - requestsStyle.Height(m.height - (len(m.frontendEndpoints) + 6)) + requestsStyle.Height(m.height - (len(m.frontendDescriptions) + 6)) case tea.KeyMsg: switch msg.String() { @@ -61,7 +61,7 @@ func (m *shareModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { func (m *shareModel) View() string { topRow := lipgloss.JoinHorizontal(lipgloss.Top, - shareHeaderStyle.Render(strings.Join(m.frontendEndpoints, "\n")), + shareHeaderStyle.Render(strings.Join(m.frontendDescriptions, "\n")), configHeaderStyle.Render(m.renderConfig()), ) requests := requestsStyle.Render(m.renderBackendRequests()) diff --git a/cmd/zrok/sharePublic.go b/cmd/zrok/sharePublic.go index 995417d8..41cb939c 100644 --- a/cmd/zrok/sharePublic.go +++ b/cmd/zrok/sharePublic.go @@ -32,6 +32,7 @@ type sharePublicCommand struct { basicAuth []string frontendSelection []string backendMode string + headless bool cmd *cobra.Command } @@ -45,6 +46,7 @@ func newSharePublicCommand() *sharePublicCommand { cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (,...)") cmd.Flags().StringArrayVar(&command.frontendSelection, "frontends", []string{"public"}, "Selected frontends to use for the share") cmd.Flags().StringVar(&command.backendMode, "backend-mode", "proxy", "The backend mode {proxy, web}") + cmd.Flags().BoolVar(&command.headless, "headless", false, "Disable TUI and run headless") cmd.Run = command.run return command } @@ -177,30 +179,35 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { _ = bh.Requests()() - //logrus.Infof("access your zrok share: %v", resp.Payload.FrontendProxyEndpoints[0]) - //for { - // time.Sleep(5 * time.Second) - // logrus.Infof("requests: %d", bh.Requests()()) - //} - - mdl := newShareModel(resp.Payload.ShrToken, resp.Payload.FrontendProxyEndpoints, "public", cmd.backendMode) - prg := tea.NewProgram(mdl, tea.WithAltScreen()) - - go func() { + if cmd.headless { + logrus.Infof("access your zrok share at the following endpoints:\n %v", strings.Join(resp.Payload.FrontendProxyEndpoints, "\n")) for { select { case req := <-requestsChan: - prg.Send(req) + logrus.Infof("%v -> %v %v", req.RemoteAddr, req.Method, req.Path) } } - }() - if _, err := prg.Run(); err != nil { - tui.Error("An error occurred", err) + } else { + mdl := newShareModel(resp.Payload.ShrToken, resp.Payload.FrontendProxyEndpoints, "public", cmd.backendMode) + prg := tea.NewProgram(mdl, tea.WithAltScreen()) + + go func() { + for { + select { + case req := <-requestsChan: + prg.Send(req) + } + } + }() + + if _, err := prg.Run(); err != nil { + tui.Error("An error occurred", err) + } + + close(requestsChan) + cmd.destroy(zrd.Env.ZId, resp.Payload.ShrToken, zrok, auth) } - - close(requestsChan) - cmd.destroy(zrd.Env.ZId, resp.Payload.ShrToken, zrok, auth) } func (cmd *sharePublicCommand) proxyBackendMode(cfg *proxyBackend.Config) (endpoints.BackendHandler, error) { From 2c5ea40b734db29eecc1ede495d64407df2daaf2 Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Tue, 10 Jan 2023 15:39:45 -0500 Subject: [PATCH 17/32] share private tui (#56) --- cmd/zrok/sharePrivate.go | 42 ++++++++++++++++++++++++++++++++++------ cmd/zrok/sharePublic.go | 12 +++++------- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/cmd/zrok/sharePrivate.go b/cmd/zrok/sharePrivate.go index bd52c06b..35ba3bd0 100644 --- a/cmd/zrok/sharePrivate.go +++ b/cmd/zrok/sharePrivate.go @@ -2,6 +2,7 @@ package main import ( "fmt" + tea "github.com/charmbracelet/bubbletea" "github.com/go-openapi/runtime" httptransport "github.com/go-openapi/runtime/client" "github.com/openziti-test-kitchen/zrok/endpoints" @@ -21,7 +22,6 @@ import ( "os/signal" "strings" "syscall" - "time" ) func init() { @@ -31,18 +31,20 @@ func init() { type sharePrivateCommand struct { basicAuth []string backendMode string + headless bool cmd *cobra.Command } func newSharePrivateCommand() *sharePrivateCommand { cmd := &cobra.Command{ - Use: "private ", - Short: "Share a target endpoint privately", + Use: "private ", + Short: "Share a target resource privately", Args: cobra.ExactArgs(1), } command := &sharePrivateCommand{cmd: cmd} cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (,...") cmd.Flags().StringVar(&command.backendMode, "backend-mode", "proxy", "The backend mode {proxy, web}") + cmd.Flags().BoolVar(&command.headless, "headless", false, "Disable TUI and run headless") cmd.Run = command.run return command } @@ -136,12 +138,14 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { os.Exit(0) }() + requestsChan := make(chan *endpoints.BackendRequest, 1024) switch cmd.backendMode { case "proxy": cfg := &proxyBackend.Config{ IdentityPath: zif, EndpointAddress: target, ShrToken: resp.Payload.ShrToken, + RequestsChan: requestsChan, } _, err = cmd.proxyBackendMode(cfg) if err != nil { @@ -156,6 +160,7 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { IdentityPath: zif, WebRoot: target, ShrToken: resp.Payload.ShrToken, + RequestsChan: requestsChan, } _, err = cmd.webBackendMode(cfg) if err != nil { @@ -169,10 +174,35 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { tui.Error("invalid backend mode", nil) } - logrus.Infof("share with others; they will use this command for access: 'zrok access private %v'", resp.Payload.ShrToken) + if cmd.headless { + logrus.Infof("allow other to access your share with the following command:\nzrok access private %v", resp.Payload.ShrToken) + for { + select { + case req := <-requestsChan: + logrus.Infof("%v -> %v %v", req.RemoteAddr, req.Method, req.Path) + } + } - for { - time.Sleep(30 * time.Second) + } else { + shareDescription := fmt.Sprintf("access your share with: %v", tui.CodeStyle.Render(fmt.Sprintf("zrok access private %v", resp.Payload.ShrToken))) + mdl := newShareModel(resp.Payload.ShrToken, []string{shareDescription}, "public", cmd.backendMode) + prg := tea.NewProgram(mdl, tea.WithAltScreen()) + + go func() { + for { + select { + case req := <-requestsChan: + prg.Send(req) + } + } + }() + + if _, err := prg.Run(); err != nil { + tui.Error("An error occurred", err) + } + + close(requestsChan) + cmd.destroy(zrd.Env.ZId, resp.Payload.ShrToken, zrok, auth) } } diff --git a/cmd/zrok/sharePublic.go b/cmd/zrok/sharePublic.go index 41cb939c..b440f009 100644 --- a/cmd/zrok/sharePublic.go +++ b/cmd/zrok/sharePublic.go @@ -78,7 +78,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { zrd, err := zrokdir.Load() if err != nil { if !panicInstead { - tui.Error("unable to load zrokdir", nil) + tui.Error("unable to load zrokdir", err) } panic(err) } @@ -102,6 +102,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { } panic(err) } + auth := httptransport.APIKeyAuth("X-TOKEN", "header", zrd.Env.Token) req := share.NewShareParams() req.Body = &rest_model_zrok.ShareRequest{ @@ -127,7 +128,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { resp, err := zrok.Share.Share(req, auth) if err != nil { if !panicInstead { - tui.Error("unable to create tunnel", err) + tui.Error("unable to create share", err) } panic(err) } @@ -140,7 +141,6 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { os.Exit(0) }() - var bh endpoints.BackendHandler requestsChan := make(chan *endpoints.BackendRequest, 1024) switch cmd.backendMode { case "proxy": @@ -150,7 +150,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { ShrToken: resp.Payload.ShrToken, RequestsChan: requestsChan, } - bh, err = cmd.proxyBackendMode(cfg) + _, err = cmd.proxyBackendMode(cfg) if err != nil { if !panicInstead { tui.Error("unable to create proxy backend handler", err) @@ -165,7 +165,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { ShrToken: resp.Payload.ShrToken, RequestsChan: requestsChan, } - bh, err = cmd.webBackendMode(cfg) + _, err = cmd.webBackendMode(cfg) if err != nil { if !panicInstead { tui.Error("unable to create web backend handler", err) @@ -177,8 +177,6 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { tui.Error("invalid backend mode", nil) } - _ = bh.Requests()() - if cmd.headless { logrus.Infof("access your zrok share at the following endpoints:\n %v", strings.Join(resp.Payload.FrontendProxyEndpoints, "\n")) for { From a63b66ad97c5e1d3b3a53f506f500ec39c073c5b Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Tue, 10 Jan 2023 15:42:24 -0500 Subject: [PATCH 18/32] stray logging (#56) --- endpoints/proxyBackend/http.go | 1 - 1 file changed, 1 deletion(-) diff --git a/endpoints/proxyBackend/http.go b/endpoints/proxyBackend/http.go index 970b1cb3..c6d0a148 100644 --- a/endpoints/proxyBackend/http.go +++ b/endpoints/proxyBackend/http.go @@ -91,7 +91,6 @@ func newReverseProxy(target string, requests chan *endpoints.BackendRequest) (*h Path: req.URL.String(), } } - fmt.Printf("proxy <= %v %v <= %v\n", req.Method, req.URL.String(), req.Header["X-Real-Ip"]) director(req) req.Header.Set("X-Proxy", "zrok") } From 98b8c8c8a1549d0d836a015dc6c8ca700d1352c7 Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Tue, 10 Jan 2023 16:38:53 -0500 Subject: [PATCH 19/32] access tui (#56) --- cmd/zrok/accessModel.go | 111 ++++++++++++++++++++++++++++ cmd/zrok/accessPrivate.go | 36 +++++++-- cmd/zrok/shareModel.go | 23 +++--- cmd/zrok/sharePrivate.go | 2 +- endpoints/privateFrontend/config.go | 3 + endpoints/privateFrontend/http.go | 11 ++- 6 files changed, 168 insertions(+), 18 deletions(-) create mode 100644 cmd/zrok/accessModel.go diff --git a/cmd/zrok/accessModel.go b/cmd/zrok/accessModel.go new file mode 100644 index 00000000..f4d0e02f --- /dev/null +++ b/cmd/zrok/accessModel.go @@ -0,0 +1,111 @@ +package main + +import ( + "fmt" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/openziti-test-kitchen/zrok/endpoints" + "strings" + "time" +) + +type accessModel struct { + shrToken string + localEndpoint string + requests []*endpoints.BackendRequest + width int + height int +} + +func newAccessModel(shrToken, localEndpoint string) *accessModel { + return &accessModel{ + shrToken: shrToken, + localEndpoint: localEndpoint, + } +} + +func (m *accessModel) Init() tea.Cmd { return nil } + +func (m *accessModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case *endpoints.BackendRequest: + m.requests = append([]*endpoints.BackendRequest{msg}, m.requests...) + if len(m.requests) > 2048 { + m.requests = m.requests[:2048] + } + + case tea.WindowSizeMsg: + m.width = msg.Width + accessHeaderStyle.Width(m.width - 2) + accessRequestsStyle.Width(m.width - 2) + + m.height = msg.Height + accessRequestsStyle.Height(m.height - 7) + + case tea.KeyMsg: + switch msg.String() { + case "ctrl+c", "q": + return m, tea.Quit + case "ctrl+l": + return m, tea.ClearScreen + } + } + + return m, nil +} + +func (m *accessModel) View() string { + return lipgloss.JoinVertical( + lipgloss.Left, + accessHeaderStyle.Render(fmt.Sprintf("%v -> %v", m.localEndpoint, m.shrToken)), + accessRequestsStyle.Render(m.renderRequests()), + ) +} + +func (m *accessModel) renderRequests() string { + out := "" + maxRows := accessRequestsStyle.GetHeight() + for i := 0; i < maxRows && i < len(m.requests); i++ { + req := m.requests[i] + out += fmt.Sprintf("%v %v -> %v %v", + timeStyle.Render(req.Stamp.Format(time.RFC850)), + addressStyle.Render(req.RemoteAddr), + m.renderMethod(req.Method), + req.Path, + ) + if i != maxRows-1 { + out += "\n" + } + } + return out +} + +func (m *accessModel) renderMethod(method string) string { + switch strings.ToLower(method) { + case "get": + return getStyle.Render(method) + case "post": + return postStyle.Render(method) + default: + return otherMethodStyle.Render(method) + } +} + +var accessHeaderStyle = lipgloss.NewStyle(). + Height(3). + PaddingTop(1).PaddingLeft(2).PaddingBottom(1).PaddingRight(2). + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(lipgloss.Color("63")). + Align(lipgloss.Center) + +var accessRequestsStyle = lipgloss.NewStyle(). + Height(3). + PaddingLeft(2).PaddingRight(2). + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(lipgloss.Color("63")) + +type accessLogWriter struct{} + +func (w accessLogWriter) Write(p []byte) (n int, err error) { + return len(p), nil +} diff --git a/cmd/zrok/accessPrivate.go b/cmd/zrok/accessPrivate.go index 7346c30e..b94bcc71 100644 --- a/cmd/zrok/accessPrivate.go +++ b/cmd/zrok/accessPrivate.go @@ -1,8 +1,10 @@ package main import ( + tea "github.com/charmbracelet/bubbletea" "github.com/go-openapi/runtime" httptransport "github.com/go-openapi/runtime/client" + "github.com/openziti-test-kitchen/zrok/endpoints" "github.com/openziti-test-kitchen/zrok/endpoints/privateFrontend" "github.com/openziti-test-kitchen/zrok/rest_client_zrok" "github.com/openziti-test-kitchen/zrok/rest_client_zrok/share" @@ -84,6 +86,7 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) { cfg := privateFrontend.DefaultConfig("backend") cfg.ShrToken = shrToken cfg.Address = cmd.bindAddress + cfg.RequestsChan = make(chan *endpoints.BackendRequest, 1024) c := make(chan os.Signal) signal.Notify(c, os.Interrupt, syscall.SIGTERM) @@ -101,13 +104,36 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) { panic(err) } - logrus.Infof("access your share at: %v", endpointUrl.String()) - - if err := frontend.Run(); err != nil { - if !panicInstead { - tui.Error("unable to run frontend", err) + go func() { + if err := frontend.Run(); err != nil { + if !panicInstead { + tui.Error("unable to run frontend", err) + } } + }() + + mdl := newAccessModel(shrToken, endpointUrl.String()) + prg := tea.NewProgram(mdl, tea.WithAltScreen()) + + go func() { + for { + select { + case req := <-cfg.RequestsChan: + if req != nil { + prg.Send(req) + } + } + } + }() + + logrus.SetOutput(&accessLogWriter{}) + + if _, err := prg.Run(); err != nil { + tui.Error("An error occurred", err) } + + close(cfg.RequestsChan) + cmd.destroy(accessResp.Payload.FrontendToken, zrd.Env.ZId, shrToken, zrok, auth) } func (cmd *accessPrivateCommand) destroy(frotendName, envZId, shrToken string, zrok *rest_client_zrok.Zrok, auth runtime.ClientAuthInfoWriter) { diff --git a/cmd/zrok/shareModel.go b/cmd/zrok/shareModel.go index a837883d..d4db6677 100644 --- a/cmd/zrok/shareModel.go +++ b/cmd/zrok/shareModel.go @@ -10,7 +10,7 @@ import ( ) type shareModel struct { - shareToken string + shrToken string frontendDescriptions []string shareMode string backendMode string @@ -20,9 +20,9 @@ type shareModel struct { height int } -func newShareModel(shareToken string, frontendEndpoints []string, shareMode, backendMode string) *shareModel { +func newShareModel(shrToken string, frontendEndpoints []string, shareMode, backendMode string) *shareModel { return &shareModel{ - shareToken: shareToken, + shrToken: shrToken, frontendDescriptions: frontendEndpoints, shareMode: shareMode, backendMode: backendMode, @@ -42,10 +42,11 @@ func (m *shareModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.WindowSizeMsg: m.width = msg.Width shareHeaderStyle.Width(m.width - 30) - configHeaderStyle.Width(26) + shareConfigStyle.Width(26) + shareRequestsStyle.Width(m.width - 2) + m.height = msg.Height - requestsStyle.Width(m.width - 2) - requestsStyle.Height(m.height - (len(m.frontendDescriptions) + 6)) + shareRequestsStyle.Height(m.height - (len(m.frontendDescriptions) + 6)) case tea.KeyMsg: switch msg.String() { @@ -62,9 +63,9 @@ func (m *shareModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { func (m *shareModel) View() string { topRow := lipgloss.JoinHorizontal(lipgloss.Top, shareHeaderStyle.Render(strings.Join(m.frontendDescriptions, "\n")), - configHeaderStyle.Render(m.renderConfig()), + shareConfigStyle.Render(m.renderConfig()), ) - requests := requestsStyle.Render(m.renderBackendRequests()) + requests := shareRequestsStyle.Render(m.renderBackendRequests()) all := lipgloss.JoinVertical(lipgloss.Left, topRow, requests) return all } @@ -88,7 +89,7 @@ func (m *shareModel) renderConfig() string { func (m *shareModel) renderBackendRequests() string { out := "" - maxRows := requestsStyle.GetHeight() + maxRows := shareRequestsStyle.GetHeight() for i := 0; i < maxRows && i < len(m.requests); i++ { req := m.requests[i] out += fmt.Sprintf("%v %v -> %v %v", @@ -122,14 +123,14 @@ var shareHeaderStyle = lipgloss.NewStyle(). BorderForeground(lipgloss.Color("63")). Align(lipgloss.Center) -var configHeaderStyle = lipgloss.NewStyle(). +var shareConfigStyle = lipgloss.NewStyle(). Height(3). PaddingTop(1).PaddingLeft(2).PaddingBottom(1).PaddingRight(2). BorderStyle(lipgloss.RoundedBorder()). BorderForeground(lipgloss.Color("63")). Align(lipgloss.Center) -var requestsStyle = lipgloss.NewStyle(). +var shareRequestsStyle = lipgloss.NewStyle(). Height(3). PaddingLeft(2).PaddingRight(2). BorderStyle(lipgloss.RoundedBorder()). diff --git a/cmd/zrok/sharePrivate.go b/cmd/zrok/sharePrivate.go index 35ba3bd0..0c373d0d 100644 --- a/cmd/zrok/sharePrivate.go +++ b/cmd/zrok/sharePrivate.go @@ -185,7 +185,7 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { } else { shareDescription := fmt.Sprintf("access your share with: %v", tui.CodeStyle.Render(fmt.Sprintf("zrok access private %v", resp.Payload.ShrToken))) - mdl := newShareModel(resp.Payload.ShrToken, []string{shareDescription}, "public", cmd.backendMode) + mdl := newShareModel(resp.Payload.ShrToken, []string{shareDescription}, "private", cmd.backendMode) prg := tea.NewProgram(mdl, tea.WithAltScreen()) go func() { diff --git a/endpoints/privateFrontend/config.go b/endpoints/privateFrontend/config.go index 4a309d83..a704875c 100644 --- a/endpoints/privateFrontend/config.go +++ b/endpoints/privateFrontend/config.go @@ -1,9 +1,12 @@ package privateFrontend +import "github.com/openziti-test-kitchen/zrok/endpoints" + type Config struct { IdentityName string ShrToken string Address string + RequestsChan chan *endpoints.BackendRequest } func DefaultConfig(identityName string) *Config { diff --git a/endpoints/privateFrontend/http.go b/endpoints/privateFrontend/http.go index 48b70e33..e192a834 100644 --- a/endpoints/privateFrontend/http.go +++ b/endpoints/privateFrontend/http.go @@ -16,6 +16,7 @@ import ( "net/http" "net/http/httputil" "net/url" + "time" ) type httpFrontend struct { @@ -75,6 +76,14 @@ func newServiceProxy(cfg *Config, ctx ziti.Context) (*httputil.ReverseProxy, err proxy := serviceTargetProxy(cfg, ctx) director := proxy.Director proxy.Director = func(req *http.Request) { + if cfg.RequestsChan != nil { + cfg.RequestsChan <- &endpoints.BackendRequest{ + Stamp: time.Now(), + RemoteAddr: fmt.Sprintf("%v", req.Header["X-Real-Ip"]), + Method: req.Method, + Path: req.URL.String(), + } + } director(req) req.Header.Set("X-Proxy", "zrok") } @@ -98,7 +107,7 @@ func serviceTargetProxy(cfg *Config, ctx ziti.Context) *httputil.ReverseProxy { logrus.Warn("no config!") } if target, err := url.Parse(fmt.Sprintf("http://%v", targetShrToken)); err == nil { - logrus.Infof("[%v] -> %v", targetShrToken, req.URL) + logrus.Debugf("[%v] -> %v", targetShrToken, req.URL) targetQuery := target.RawQuery req.URL.Scheme = target.Scheme From 100c2214874514c8e2aa81b5f6c301154a97cbb0 Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Tue, 10 Jan 2023 16:39:08 -0500 Subject: [PATCH 20/32] definitely need this to be writable, or problems will ensue --- zrokdir/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zrokdir/version.go b/zrokdir/version.go index b7f3c5b5..177f186d 100644 --- a/zrokdir/version.go +++ b/zrokdir/version.go @@ -46,7 +46,7 @@ func writeMetadata() error { if err := os.MkdirAll(filepath.Dir(mf), os.FileMode(0700)); err != nil { return err } - if err := os.WriteFile(mf, data, os.FileMode(0400)); err != nil { + if err := os.WriteFile(mf, data, os.FileMode(0600)); err != nil { return err } return nil From 4792aa00647116881ab2c529767f897c91e06104 Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Tue, 10 Jan 2023 16:41:45 -0500 Subject: [PATCH 21/32] include the secret token in the identity name to avoid collisions --- controller/enable.go | 2 +- controller/zrokEdgeSdk/identity.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/controller/enable.go b/controller/enable.go index dd6bba26..0e328a9a 100644 --- a/controller/enable.go +++ b/controller/enable.go @@ -31,7 +31,7 @@ func (h *enableHandler) Handle(params environment.EnableParams, principal *rest_ logrus.Errorf("error getting edge client: %v", err) return environment.NewEnableInternalServerError() } - ident, err := zrokEdgeSdk.CreateEnvironmentIdentity(principal.Email, params.Body.Description, client) + ident, err := zrokEdgeSdk.CreateEnvironmentIdentity(principal.Token, principal.Email, params.Body.Description, client) if err != nil { logrus.Error(err) return environment.NewEnableInternalServerError() diff --git a/controller/zrokEdgeSdk/identity.go b/controller/zrokEdgeSdk/identity.go index 35be16c4..9cb955f3 100644 --- a/controller/zrokEdgeSdk/identity.go +++ b/controller/zrokEdgeSdk/identity.go @@ -12,10 +12,10 @@ import ( "time" ) -func CreateEnvironmentIdentity(accountEmail, envDescription string, edge *rest_management_api_client.ZitiEdgeManagement) (*identity.CreateIdentityCreated, error) { +func CreateEnvironmentIdentity(secretToken, accountEmail, envDescription string, edge *rest_management_api_client.ZitiEdgeManagement) (*identity.CreateIdentityCreated, error) { identityType := rest_model_edge.IdentityTypeUser moreTags := map[string]interface{}{"zrokEmail": accountEmail} - return CreateIdentity(accountEmail+"-"+envDescription, identityType, moreTags, edge) + return CreateIdentity(accountEmail+"-"+secretToken+"-"+envDescription, identityType, moreTags, edge) } func CreateIdentity(name string, identityType rest_model_edge.IdentityType, addlTags map[string]interface{}, edge *rest_management_api_client.ZitiEdgeManagement) (*identity.CreateIdentityCreated, error) { From 575a3f703012894430f88d9ced54dc3c17f03719 Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Tue, 10 Jan 2023 16:43:58 -0500 Subject: [PATCH 22/32] a random token will work better --- controller/enable.go | 7 ++++++- controller/zrokEdgeSdk/identity.go | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/controller/enable.go b/controller/enable.go index 0e328a9a..dfbf5f29 100644 --- a/controller/enable.go +++ b/controller/enable.go @@ -31,7 +31,12 @@ func (h *enableHandler) Handle(params environment.EnableParams, principal *rest_ logrus.Errorf("error getting edge client: %v", err) return environment.NewEnableInternalServerError() } - ident, err := zrokEdgeSdk.CreateEnvironmentIdentity(principal.Token, principal.Email, params.Body.Description, client) + uniqueToken, err := createShareToken() + if err != nil { + logrus.Errorf("error creating unique identity token: %v", err) + return environment.NewEnableInternalServerError() + } + ident, err := zrokEdgeSdk.CreateEnvironmentIdentity(uniqueToken, principal.Email, params.Body.Description, client) if err != nil { logrus.Error(err) return environment.NewEnableInternalServerError() diff --git a/controller/zrokEdgeSdk/identity.go b/controller/zrokEdgeSdk/identity.go index 9cb955f3..dbcd7bdd 100644 --- a/controller/zrokEdgeSdk/identity.go +++ b/controller/zrokEdgeSdk/identity.go @@ -12,10 +12,10 @@ import ( "time" ) -func CreateEnvironmentIdentity(secretToken, accountEmail, envDescription string, edge *rest_management_api_client.ZitiEdgeManagement) (*identity.CreateIdentityCreated, error) { +func CreateEnvironmentIdentity(uniqueToken, accountEmail, envDescription string, edge *rest_management_api_client.ZitiEdgeManagement) (*identity.CreateIdentityCreated, error) { identityType := rest_model_edge.IdentityTypeUser moreTags := map[string]interface{}{"zrokEmail": accountEmail} - return CreateIdentity(accountEmail+"-"+secretToken+"-"+envDescription, identityType, moreTags, edge) + return CreateIdentity(accountEmail+"-"+uniqueToken+"-"+envDescription, identityType, moreTags, edge) } func CreateIdentity(name string, identityType rest_model_edge.IdentityType, addlTags map[string]interface{}, edge *rest_management_api_client.ZitiEdgeManagement) (*identity.CreateIdentityCreated, error) { From 0516f28b721e721261efeab7cf37f8ab48bf9975 Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Tue, 10 Jan 2023 17:13:34 -0500 Subject: [PATCH 23/32] zrok reserve; zrok share reserved updated to work with --backend-mode (#151) --- cmd/zrok/reserve.go | 32 ++++++++---- cmd/zrok/shareReserved.go | 107 ++++++++++++++++++++++++-------------- 2 files changed, 90 insertions(+), 49 deletions(-) diff --git a/cmd/zrok/reserve.go b/cmd/zrok/reserve.go index 501639e5..22c7f5f0 100644 --- a/cmd/zrok/reserve.go +++ b/cmd/zrok/reserve.go @@ -21,18 +21,20 @@ func init() { type reserveCommand struct { basicAuth []string frontendSelection []string + backendMode string cmd *cobra.Command } func newReserveCommand() *reserveCommand { cmd := &cobra.Command{ - Use: "reserve ", + Use: "reserve ", Short: "Create a reserved share", Args: cobra.ExactArgs(2), } command := &reserveCommand{cmd: cmd} cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (,...)") cmd.Flags().StringArrayVar(&command.frontendSelection, "frontends", []string{"public"}, "Selected frontends to use for the share") + cmd.Flags().StringVar(&command.backendMode, "backend-mode", "proxy", "The backend mode {proxy, web}") cmd.Run = command.run return command } @@ -43,15 +45,23 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) { tui.Error("invalid sharing mode; expecting 'public' or 'private'", nil) } - targetEndpoint, err := url.Parse(args[1]) - if err != nil { - if !panicInstead { - tui.Error("invalid target endpoint URL", err) + var target string + switch cmd.backendMode { + case "proxy": + targetEndpoint, err := url.Parse(args[1]) + if err != nil { + if !panicInstead { + tui.Error("invalid target endpoint URL", err) + } + panic(err) } - panic(err) - } - if targetEndpoint.Scheme == "" { - targetEndpoint.Scheme = "https" + if targetEndpoint.Scheme == "" { + targetEndpoint.Scheme = "https" + } + target = targetEndpoint.String() + + case "web": + target = args[1] } zrd, err := zrokdir.Load() @@ -78,8 +88,8 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) { req.Body = &rest_model_zrok.ShareRequest{ EnvZID: zrd.Env.ZId, ShareMode: shareMode, - BackendMode: "proxy", - BackendProxyEndpoint: targetEndpoint.String(), + BackendMode: cmd.backendMode, + BackendProxyEndpoint: target, AuthScheme: string(model.None), Reserved: true, } diff --git a/cmd/zrok/shareReserved.go b/cmd/zrok/shareReserved.go index 2b7e8617..d563d673 100644 --- a/cmd/zrok/shareReserved.go +++ b/cmd/zrok/shareReserved.go @@ -2,15 +2,17 @@ package main import ( httptransport "github.com/go-openapi/runtime/client" + "github.com/openziti-test-kitchen/zrok/endpoints" "github.com/openziti-test-kitchen/zrok/endpoints/proxyBackend" + "github.com/openziti-test-kitchen/zrok/endpoints/webBackend" "github.com/openziti-test-kitchen/zrok/rest_client_zrok/metadata" "github.com/openziti-test-kitchen/zrok/rest_client_zrok/share" "github.com/openziti-test-kitchen/zrok/rest_model_zrok" "github.com/openziti-test-kitchen/zrok/tui" "github.com/openziti-test-kitchen/zrok/zrokdir" + "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" - "net/url" "time" ) @@ -36,20 +38,7 @@ func newShareReservedCommand() *shareReservedCommand { func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { shrToken := args[0] - targetEndpoint := "" - if cmd.overrideEndpoint != "" { - e, err := url.Parse(cmd.overrideEndpoint) - if err != nil { - if !panicInstead { - tui.Error("invalid override endpoint URL", err) - } - panic(err) - } - if e.Scheme == "" { - e.Scheme = "https" - } - targetEndpoint = e.String() - } + var target string zrd, err := zrokdir.Load() if err != nil { @@ -80,8 +69,8 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { } panic(err) } - if targetEndpoint == "" { - targetEndpoint = resp.Payload.BackendProxyEndpoint + if target == "" { + target = resp.Payload.BackendProxyEndpoint } zif, err := zrokdir.ZitiIdentityFile("backend") @@ -91,18 +80,14 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { } panic(err) } - cfg := &proxyBackend.Config{ - IdentityPath: zif, - EndpointAddress: targetEndpoint, - ShrToken: shrToken, - } - logrus.Infof("sharing target endpoint: '%v'", cfg.EndpointAddress) - if resp.Payload.BackendProxyEndpoint != targetEndpoint { + logrus.Infof("sharing target: '%v'", target) + + if resp.Payload.BackendProxyEndpoint != target { upReq := share.NewUpdateShareParams() upReq.Body = &rest_model_zrok.UpdateShareRequest{ ShrToken: shrToken, - BackendProxyEndpoint: targetEndpoint, + BackendProxyEndpoint: target, } if _, err := zrok.Share.UpdateShare(upReq, auth); err != nil { if !panicInstead { @@ -110,27 +95,43 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { } panic(err) } - logrus.Infof("updated backend proxy endpoint to: %v", targetEndpoint) + logrus.Infof("updated backend proxy endpoint to: %v", target) } else { - logrus.Infof("using existing backend proxy endpoint: %v", targetEndpoint) + logrus.Infof("using existing backend proxy endpoint: %v", target) } - httpProxy, err := proxyBackend.NewBackend(cfg) - if err != nil { - if !panicInstead { - tui.Error("unable to create http backend", err) + switch resp.Payload.BackendMode { + case "proxy": + cfg := &proxyBackend.Config{ + IdentityPath: zif, + EndpointAddress: target, + ShrToken: shrToken, } - panic(err) - } - - go func() { - if err := httpProxy.Run(); err != nil { + _, err := cmd.proxyBackendMode(cfg) + if err != nil { if !panicInstead { - tui.Error("unable to run http proxy", err) + tui.Error("unable to create proxy backend handler", err) } panic(err) } - }() + + case "web": + cfg := &webBackend.Config{ + IdentityPath: zif, + WebRoot: target, + ShrToken: shrToken, + } + _, err := cmd.webBackendMode(cfg) + if err != nil { + if !panicInstead { + tui.Error("unable to create web backend handler", err) + } + panic(err) + } + + default: + tui.Error("invalid backend mode", nil) + } switch resp.Payload.ShareMode { case "public": @@ -144,3 +145,33 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { time.Sleep(30 * time.Second) } } + +func (cmd *shareReservedCommand) proxyBackendMode(cfg *proxyBackend.Config) (endpoints.BackendHandler, error) { + be, err := proxyBackend.NewBackend(cfg) + if err != nil { + return nil, errors.Wrap(err, "error creating http proxy backend") + } + + go func() { + if err := be.Run(); err != nil { + logrus.Errorf("error running http proxy backend: %v", err) + } + }() + + return be, nil +} + +func (cmd *shareReservedCommand) webBackendMode(cfg *webBackend.Config) (endpoints.BackendHandler, error) { + be, err := webBackend.NewBackend(cfg) + if err != nil { + return nil, errors.Wrap(err, "error creating http web backend") + } + + go func() { + if err := be.Run(); err != nil { + logrus.Errorf("error running http web backend: %v", err) + } + }() + + return be, nil +} From 72cf0b54ad9cab76317a3c1a55b1e385af71f5f1 Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Tue, 10 Jan 2023 17:21:15 -0500 Subject: [PATCH 24/32] implement tui for reserved sharing (#56) --- cmd/zrok/shareReserved.go | 54 ++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/cmd/zrok/shareReserved.go b/cmd/zrok/shareReserved.go index d563d673..7ae275f8 100644 --- a/cmd/zrok/shareReserved.go +++ b/cmd/zrok/shareReserved.go @@ -1,6 +1,8 @@ package main import ( + "fmt" + tea "github.com/charmbracelet/bubbletea" httptransport "github.com/go-openapi/runtime/client" "github.com/openziti-test-kitchen/zrok/endpoints" "github.com/openziti-test-kitchen/zrok/endpoints/proxyBackend" @@ -13,7 +15,6 @@ import ( "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" - "time" ) func init() { @@ -22,6 +23,7 @@ func init() { type shareReservedCommand struct { overrideEndpoint string + headless bool cmd *cobra.Command } @@ -32,6 +34,7 @@ func newShareReservedCommand() *shareReservedCommand { } command := &shareReservedCommand{cmd: cmd} cmd.Flags().StringVar(&command.overrideEndpoint, "override-endpoint", "", "Override the stored target endpoint with a replacement") + cmd.Flags().BoolVar(&command.headless, "headless", false, "Disable TUI and run headless") cmd.Run = command.run return command } @@ -100,12 +103,14 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { logrus.Infof("using existing backend proxy endpoint: %v", target) } + requestsChan := make(chan *endpoints.BackendRequest, 1024) switch resp.Payload.BackendMode { case "proxy": cfg := &proxyBackend.Config{ IdentityPath: zif, EndpointAddress: target, ShrToken: shrToken, + RequestsChan: requestsChan, } _, err := cmd.proxyBackendMode(cfg) if err != nil { @@ -120,6 +125,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { IdentityPath: zif, WebRoot: target, ShrToken: shrToken, + RequestsChan: requestsChan, } _, err := cmd.webBackendMode(cfg) if err != nil { @@ -133,16 +139,46 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { tui.Error("invalid backend mode", nil) } - switch resp.Payload.ShareMode { - case "public": - logrus.Infof("access your zrok share: %v", resp.Payload.FrontendEndpoint) + if cmd.headless { + switch resp.Payload.ShareMode { + case "public": + logrus.Infof("access your zrok share: %v", resp.Payload.FrontendEndpoint) - case "private": - logrus.Infof("use this command to access your zrok share: 'zrok access private %v'", shrToken) - } + case "private": + logrus.Infof("use this command to access your zrok share: 'zrok access private %v'", shrToken) + } + for { + select { + case req := <-requestsChan: + logrus.Infof("%v -> %v %v", req.RemoteAddr, req.Method, req.Path) + } + } + } else { + var shareDescription string + switch resp.Payload.ShareMode { + case "public": + shareDescription = resp.Payload.FrontendEndpoint + case "private": + shareDescription = fmt.Sprintf("access your share with: %v", tui.CodeStyle.Render(fmt.Sprintf("zrok access private %v", shrToken))) + } - for { - time.Sleep(30 * time.Second) + mdl := newShareModel(shrToken, []string{shareDescription}, resp.Payload.ShareMode, resp.Payload.BackendMode) + prg := tea.NewProgram(mdl, tea.WithAltScreen()) + + go func() { + for { + select { + case req := <-requestsChan: + prg.Send(req) + } + } + }() + + if _, err := prg.Run(); err != nil { + tui.Error("An error occurred", err) + } + + close(requestsChan) } } From 163cc9b49c528e2eeecea15852c9daf4418ca2e3 Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Tue, 10 Jan 2023 17:37:15 -0500 Subject: [PATCH 25/32] file naming (#56) --- cmd/zrok/{accessModel.go => accessTui.go} | 0 cmd/zrok/{shareModel.go => shareTui.go} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename cmd/zrok/{accessModel.go => accessTui.go} (100%) rename cmd/zrok/{shareModel.go => shareTui.go} (100%) diff --git a/cmd/zrok/accessModel.go b/cmd/zrok/accessTui.go similarity index 100% rename from cmd/zrok/accessModel.go rename to cmd/zrok/accessTui.go diff --git a/cmd/zrok/shareModel.go b/cmd/zrok/shareTui.go similarity index 100% rename from cmd/zrok/shareModel.go rename to cmd/zrok/shareTui.go From 7868ce85277e9099fb15150e2e2fae662c978ac8 Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Tue, 10 Jan 2023 17:40:20 -0500 Subject: [PATCH 26/32] reorg, streamlining --- cmd/zrok/accessPrivate.go | 2 +- cmd/zrok/accessTui.go | 6 +++--- cmd/zrok/sharePrivate.go | 6 +++--- cmd/zrok/sharePublic.go | 6 +++--- cmd/zrok/shareReserved.go | 6 +++--- cmd/zrok/shareTui.go | 6 +++--- endpoints/privateFrontend/config.go | 2 +- endpoints/privateFrontend/http.go | 2 +- endpoints/proxyBackend/http.go | 6 +++--- endpoints/requests.go | 14 ++++++++++++++ endpoints/util.go | 12 ------------ endpoints/webBackend/web.go | 6 +++--- 12 files changed, 38 insertions(+), 36 deletions(-) create mode 100644 endpoints/requests.go diff --git a/cmd/zrok/accessPrivate.go b/cmd/zrok/accessPrivate.go index b94bcc71..5174d4d2 100644 --- a/cmd/zrok/accessPrivate.go +++ b/cmd/zrok/accessPrivate.go @@ -86,7 +86,7 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) { cfg := privateFrontend.DefaultConfig("backend") cfg.ShrToken = shrToken cfg.Address = cmd.bindAddress - cfg.RequestsChan = make(chan *endpoints.BackendRequest, 1024) + cfg.RequestsChan = make(chan *endpoints.Request, 1024) c := make(chan os.Signal) signal.Notify(c, os.Interrupt, syscall.SIGTERM) diff --git a/cmd/zrok/accessTui.go b/cmd/zrok/accessTui.go index f4d0e02f..52c9f5fe 100644 --- a/cmd/zrok/accessTui.go +++ b/cmd/zrok/accessTui.go @@ -12,7 +12,7 @@ import ( type accessModel struct { shrToken string localEndpoint string - requests []*endpoints.BackendRequest + requests []*endpoints.Request width int height int } @@ -28,8 +28,8 @@ func (m *accessModel) Init() tea.Cmd { return nil } func (m *accessModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { - case *endpoints.BackendRequest: - m.requests = append([]*endpoints.BackendRequest{msg}, m.requests...) + case *endpoints.Request: + m.requests = append([]*endpoints.Request{msg}, m.requests...) if len(m.requests) > 2048 { m.requests = m.requests[:2048] } diff --git a/cmd/zrok/sharePrivate.go b/cmd/zrok/sharePrivate.go index 0c373d0d..2429a624 100644 --- a/cmd/zrok/sharePrivate.go +++ b/cmd/zrok/sharePrivate.go @@ -138,7 +138,7 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { os.Exit(0) }() - requestsChan := make(chan *endpoints.BackendRequest, 1024) + requestsChan := make(chan *endpoints.Request, 1024) switch cmd.backendMode { case "proxy": cfg := &proxyBackend.Config{ @@ -206,7 +206,7 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { } } -func (cmd *sharePrivateCommand) proxyBackendMode(cfg *proxyBackend.Config) (endpoints.BackendHandler, error) { +func (cmd *sharePrivateCommand) proxyBackendMode(cfg *proxyBackend.Config) (endpoints.RequestHandler, error) { be, err := proxyBackend.NewBackend(cfg) if err != nil { return nil, errors.Wrap(err, "error creating http proxy backend") @@ -221,7 +221,7 @@ func (cmd *sharePrivateCommand) proxyBackendMode(cfg *proxyBackend.Config) (endp return be, nil } -func (cmd *sharePrivateCommand) webBackendMode(cfg *webBackend.Config) (endpoints.BackendHandler, error) { +func (cmd *sharePrivateCommand) webBackendMode(cfg *webBackend.Config) (endpoints.RequestHandler, error) { be, err := webBackend.NewBackend(cfg) if err != nil { return nil, errors.Wrap(err, "error creating http web backend") diff --git a/cmd/zrok/sharePublic.go b/cmd/zrok/sharePublic.go index b440f009..1cae1dbd 100644 --- a/cmd/zrok/sharePublic.go +++ b/cmd/zrok/sharePublic.go @@ -141,7 +141,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { os.Exit(0) }() - requestsChan := make(chan *endpoints.BackendRequest, 1024) + requestsChan := make(chan *endpoints.Request, 1024) switch cmd.backendMode { case "proxy": cfg := &proxyBackend.Config{ @@ -208,7 +208,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { } } -func (cmd *sharePublicCommand) proxyBackendMode(cfg *proxyBackend.Config) (endpoints.BackendHandler, error) { +func (cmd *sharePublicCommand) proxyBackendMode(cfg *proxyBackend.Config) (endpoints.RequestHandler, error) { be, err := proxyBackend.NewBackend(cfg) if err != nil { return nil, errors.Wrap(err, "error creating http proxy backend") @@ -223,7 +223,7 @@ func (cmd *sharePublicCommand) proxyBackendMode(cfg *proxyBackend.Config) (endpo return be, nil } -func (cmd *sharePublicCommand) webBackendMode(cfg *webBackend.Config) (endpoints.BackendHandler, error) { +func (cmd *sharePublicCommand) webBackendMode(cfg *webBackend.Config) (endpoints.RequestHandler, error) { be, err := webBackend.NewBackend(cfg) if err != nil { return nil, errors.Wrap(err, "error creating http web backend") diff --git a/cmd/zrok/shareReserved.go b/cmd/zrok/shareReserved.go index 7ae275f8..72a67842 100644 --- a/cmd/zrok/shareReserved.go +++ b/cmd/zrok/shareReserved.go @@ -103,7 +103,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { logrus.Infof("using existing backend proxy endpoint: %v", target) } - requestsChan := make(chan *endpoints.BackendRequest, 1024) + requestsChan := make(chan *endpoints.Request, 1024) switch resp.Payload.BackendMode { case "proxy": cfg := &proxyBackend.Config{ @@ -182,7 +182,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { } } -func (cmd *shareReservedCommand) proxyBackendMode(cfg *proxyBackend.Config) (endpoints.BackendHandler, error) { +func (cmd *shareReservedCommand) proxyBackendMode(cfg *proxyBackend.Config) (endpoints.RequestHandler, error) { be, err := proxyBackend.NewBackend(cfg) if err != nil { return nil, errors.Wrap(err, "error creating http proxy backend") @@ -197,7 +197,7 @@ func (cmd *shareReservedCommand) proxyBackendMode(cfg *proxyBackend.Config) (end return be, nil } -func (cmd *shareReservedCommand) webBackendMode(cfg *webBackend.Config) (endpoints.BackendHandler, error) { +func (cmd *shareReservedCommand) webBackendMode(cfg *webBackend.Config) (endpoints.RequestHandler, error) { be, err := webBackend.NewBackend(cfg) if err != nil { return nil, errors.Wrap(err, "error creating http web backend") diff --git a/cmd/zrok/shareTui.go b/cmd/zrok/shareTui.go index d4db6677..87102481 100644 --- a/cmd/zrok/shareTui.go +++ b/cmd/zrok/shareTui.go @@ -14,7 +14,7 @@ type shareModel struct { frontendDescriptions []string shareMode string backendMode string - requests []*endpoints.BackendRequest + requests []*endpoints.Request logMessages []string width int height int @@ -33,8 +33,8 @@ func (m *shareModel) Init() tea.Cmd { return nil } func (m *shareModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { - case *endpoints.BackendRequest: - m.requests = append([]*endpoints.BackendRequest{msg}, m.requests...) + case *endpoints.Request: + m.requests = append([]*endpoints.Request{msg}, m.requests...) if len(m.requests) > 2048 { m.requests = m.requests[:2048] } diff --git a/endpoints/privateFrontend/config.go b/endpoints/privateFrontend/config.go index a704875c..49c4e1d2 100644 --- a/endpoints/privateFrontend/config.go +++ b/endpoints/privateFrontend/config.go @@ -6,7 +6,7 @@ type Config struct { IdentityName string ShrToken string Address string - RequestsChan chan *endpoints.BackendRequest + RequestsChan chan *endpoints.Request } func DefaultConfig(identityName string) *Config { diff --git a/endpoints/privateFrontend/http.go b/endpoints/privateFrontend/http.go index e192a834..c80c76c2 100644 --- a/endpoints/privateFrontend/http.go +++ b/endpoints/privateFrontend/http.go @@ -77,7 +77,7 @@ func newServiceProxy(cfg *Config, ctx ziti.Context) (*httputil.ReverseProxy, err director := proxy.Director proxy.Director = func(req *http.Request) { if cfg.RequestsChan != nil { - cfg.RequestsChan <- &endpoints.BackendRequest{ + cfg.RequestsChan <- &endpoints.Request{ Stamp: time.Now(), RemoteAddr: fmt.Sprintf("%v", req.Header["X-Real-Ip"]), Method: req.Method, diff --git a/endpoints/proxyBackend/http.go b/endpoints/proxyBackend/http.go index c6d0a148..963e05b2 100644 --- a/endpoints/proxyBackend/http.go +++ b/endpoints/proxyBackend/http.go @@ -21,7 +21,7 @@ type Config struct { IdentityPath string EndpointAddress string ShrToken string - RequestsChan chan *endpoints.BackendRequest + RequestsChan chan *endpoints.Request } type backend struct { @@ -70,7 +70,7 @@ func (self *backend) Requests() func() int32 { return self.requests } -func newReverseProxy(target string, requests chan *endpoints.BackendRequest) (*httputil.ReverseProxy, error) { +func newReverseProxy(target string, requests chan *endpoints.Request) (*httputil.ReverseProxy, error) { targetURL, err := url.Parse(target) if err != nil { return nil, err @@ -84,7 +84,7 @@ func newReverseProxy(target string, requests chan *endpoints.BackendRequest) (*h director := proxy.Director proxy.Director = func(req *http.Request) { if requests != nil { - requests <- &endpoints.BackendRequest{ + requests <- &endpoints.Request{ Stamp: time.Now(), RemoteAddr: fmt.Sprintf("%v", req.Header["X-Real-Ip"]), Method: req.Method, diff --git a/endpoints/requests.go b/endpoints/requests.go new file mode 100644 index 00000000..883a8d58 --- /dev/null +++ b/endpoints/requests.go @@ -0,0 +1,14 @@ +package endpoints + +import "time" + +type RequestHandler interface { + Requests() func() int32 +} + +type Request struct { + Stamp time.Time + RemoteAddr string + Method string + Path string +} diff --git a/endpoints/util.go b/endpoints/util.go index 2dd41fc4..ede4befe 100644 --- a/endpoints/util.go +++ b/endpoints/util.go @@ -6,20 +6,8 @@ import ( "github.com/sirupsen/logrus" "net/url" "strings" - "time" ) -type BackendHandler interface { - Requests() func() int32 -} - -type BackendRequest struct { - Stamp time.Time - RemoteAddr string - Method string - Path string -} - func GetRefreshedService(name string, ctx ziti.Context) (*edge.Service, bool) { svc, found := ctx.GetService(name) if !found { diff --git a/endpoints/webBackend/web.go b/endpoints/webBackend/web.go index caa6f2d8..06f2eff4 100644 --- a/endpoints/webBackend/web.go +++ b/endpoints/webBackend/web.go @@ -15,7 +15,7 @@ type Config struct { IdentityPath string WebRoot string ShrToken string - RequestsChan chan *endpoints.BackendRequest + RequestsChan chan *endpoints.Request } type backend struct { @@ -62,13 +62,13 @@ func (self *backend) Requests() func() int32 { } type requestGrabber struct { - requests chan *endpoints.BackendRequest + requests chan *endpoints.Request handler http.Handler } func (rl *requestGrabber) ServeHTTP(resp http.ResponseWriter, req *http.Request) { if rl.requests != nil { - rl.requests <- &endpoints.BackendRequest{ + rl.requests <- &endpoints.Request{ Stamp: time.Now(), RemoteAddr: fmt.Sprintf("%v", req.Header["X-Real-Ip"]), Method: req.Method, From 48314c013de9edcfe069f357ab19984aede5e95b Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Wed, 11 Jan 2023 12:46:04 -0500 Subject: [PATCH 27/32] improved version of access private tui with captive log (#56) --- cmd/zrok/accessPrivate.go | 4 +- cmd/zrok/accessTui.go | 137 ++++++++++++++++++++++++++++++++------ 2 files changed, 118 insertions(+), 23 deletions(-) diff --git a/cmd/zrok/accessPrivate.go b/cmd/zrok/accessPrivate.go index 5174d4d2..d76e32a4 100644 --- a/cmd/zrok/accessPrivate.go +++ b/cmd/zrok/accessPrivate.go @@ -113,7 +113,9 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) { }() mdl := newAccessModel(shrToken, endpointUrl.String()) + logrus.SetOutput(mdl) prg := tea.NewProgram(mdl, tea.WithAltScreen()) + mdl.prg = prg go func() { for { @@ -126,8 +128,6 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) { } }() - logrus.SetOutput(&accessLogWriter{}) - if _, err := prg.Run(); err != nil { tui.Error("An error occurred", err) } diff --git a/cmd/zrok/accessTui.go b/cmd/zrok/accessTui.go index 52c9f5fe..35ac0ed7 100644 --- a/cmd/zrok/accessTui.go +++ b/cmd/zrok/accessTui.go @@ -4,19 +4,27 @@ import ( "fmt" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" + "github.com/muesli/reflow/wordwrap" "github.com/openziti-test-kitchen/zrok/endpoints" "strings" "time" ) +const accessBacklog = 64 + type accessModel struct { shrToken string localEndpoint string requests []*endpoints.Request + log []string + showLog bool width int height int + prg *tea.Program } +type accessLogLine string + func newAccessModel(shrToken, localEndpoint string) *accessModel { return &accessModel{ shrToken: shrToken, @@ -29,18 +37,36 @@ func (m *accessModel) Init() tea.Cmd { return nil } func (m *accessModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case *endpoints.Request: - m.requests = append([]*endpoints.Request{msg}, m.requests...) - if len(m.requests) > 2048 { - m.requests = m.requests[:2048] + m.requests = append(m.requests, msg) + if len(m.requests) > accessBacklog { + m.requests = m.requests[1:] + } + + case accessLogLine: + m.showLog = true + splitHeight := m.height - 5 + accessRequestsStyle.Height(splitHeight/2 - 1) + accessLogStyle.Height(splitHeight/2 - 1) + + m.log = append(m.log, string(msg)) + if len(m.log) > accessBacklog { + m.log = m.log[1:] } case tea.WindowSizeMsg: m.width = msg.Width accessHeaderStyle.Width(m.width - 2) accessRequestsStyle.Width(m.width - 2) + accessLogStyle.Width(m.width - 2) m.height = msg.Height - accessRequestsStyle.Height(m.height - 7) + if !m.showLog { + accessRequestsStyle.Height(m.height - 5) + } else { + splitHeight := m.height - 5 + accessRequestsStyle.Height(splitHeight/2 - 1) + accessLogStyle.Height(splitHeight/2 - 1) + } case tea.KeyMsg: switch msg.String() { @@ -48,6 +74,15 @@ func (m *accessModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, tea.Quit case "ctrl+l": return m, tea.ClearScreen + case "l": + m.showLog = !m.showLog + if !m.showLog { + accessRequestsStyle.Height(m.height - 5) + } else { + splitHeight := m.height - 5 + accessRequestsStyle.Height(splitHeight/2 - 1) + accessLogStyle.Height(splitHeight/2 - 1) + } } } @@ -55,28 +90,54 @@ func (m *accessModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } func (m *accessModel) View() string { + var panes string + if m.showLog { + panes = lipgloss.JoinVertical(lipgloss.Left, + accessRequestsStyle.Render(m.renderRequests()), + accessLogStyle.Render(m.renderLog()), + ) + } else { + panes = accessRequestsStyle.Render(m.renderRequests()) + } + return lipgloss.JoinVertical( lipgloss.Left, accessHeaderStyle.Render(fmt.Sprintf("%v -> %v", m.localEndpoint, m.shrToken)), - accessRequestsStyle.Render(m.renderRequests()), + panes, ) } func (m *accessModel) renderRequests() string { - out := "" - maxRows := accessRequestsStyle.GetHeight() - for i := 0; i < maxRows && i < len(m.requests); i++ { - req := m.requests[i] - out += fmt.Sprintf("%v %v -> %v %v", + var requestLines []string + for _, req := range m.requests { + reqLine := fmt.Sprintf("%v %v -> %v %v", timeStyle.Render(req.Stamp.Format(time.RFC850)), addressStyle.Render(req.RemoteAddr), m.renderMethod(req.Method), req.Path, ) - if i != maxRows-1 { - out += "\n" + reqLineWrapped := wordwrap.String(reqLine, m.width-2) + splitWrapped := strings.Split(reqLineWrapped, "\n") + for _, splitLine := range splitWrapped { + splitLine := strings.ReplaceAll(splitLine, "\n", "") + if splitLine != "" { + requestLines = append(requestLines, splitLine) + } } } + maxRows := accessRequestsStyle.GetHeight() + startRow := 0 + if len(requestLines) > maxRows { + startRow = len(requestLines) - maxRows + } + out := "" + for i := startRow; i < len(requestLines); i++ { + outLine := requestLines[i] + if i < len(requestLines)-1 { + outLine += "\n" + } + out += outLine + } return out } @@ -91,21 +152,55 @@ func (m *accessModel) renderMethod(method string) string { } } +func (m *accessModel) renderLog() string { + var splitLines []string + for _, line := range m.log { + wrapped := wordwrap.String(line, m.width-2) + wrappedLines := strings.Split(wrapped, "\n") + for _, wrappedLine := range wrappedLines { + splitLine := strings.ReplaceAll(wrappedLine, "\n", "") + if splitLine != "" { + splitLines = append(splitLines, splitLine) + } + } + } + maxRows := accessLogStyle.GetHeight() + startRow := 0 + if len(splitLines) > maxRows { + startRow = len(splitLines) - maxRows + } + out := "" + for i := startRow; i < len(splitLines); i++ { + outLine := splitLines[i] + if i < len(splitLines)-1 { + outLine += "\n" + } + out += outLine + } + return out +} + +func (m *accessModel) Write(p []byte) (n int, err error) { + in := string(p) + lines := strings.Split(in, "\n") + for _, line := range lines { + cleanLine := strings.ReplaceAll(line, "\n", "") + if cleanLine != "" { + m.prg.Send(accessLogLine(cleanLine)) + } + } + return len(p), nil +} + var accessHeaderStyle = lipgloss.NewStyle(). - Height(3). - PaddingTop(1).PaddingLeft(2).PaddingBottom(1).PaddingRight(2). BorderStyle(lipgloss.RoundedBorder()). BorderForeground(lipgloss.Color("63")). Align(lipgloss.Center) var accessRequestsStyle = lipgloss.NewStyle(). - Height(3). - PaddingLeft(2).PaddingRight(2). BorderStyle(lipgloss.RoundedBorder()). BorderForeground(lipgloss.Color("63")) -type accessLogWriter struct{} - -func (w accessLogWriter) Write(p []byte) (n int, err error) { - return len(p), nil -} +var accessLogStyle = lipgloss.NewStyle(). + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(lipgloss.Color("63")) From 3db9f992e45bd7728e3e9acbe154506c1b2b384e Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Wed, 11 Jan 2023 13:36:48 -0500 Subject: [PATCH 28/32] minor access private tui tweaks; share tui aligned with new pattern (#56) --- cmd/zrok/accessTui.go | 36 +++++----- cmd/zrok/sharePrivate.go | 2 + cmd/zrok/sharePublic.go | 2 + cmd/zrok/shareReserved.go | 2 + cmd/zrok/shareTui.go | 137 ++++++++++++++++++++++++++++++++------ 5 files changed, 137 insertions(+), 42 deletions(-) diff --git a/cmd/zrok/accessTui.go b/cmd/zrok/accessTui.go index 35ac0ed7..fee5e292 100644 --- a/cmd/zrok/accessTui.go +++ b/cmd/zrok/accessTui.go @@ -10,7 +10,7 @@ import ( "time" ) -const accessBacklog = 64 +const accessTuiBacklog = 256 type accessModel struct { shrToken string @@ -38,18 +38,16 @@ func (m *accessModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case *endpoints.Request: m.requests = append(m.requests, msg) - if len(m.requests) > accessBacklog { + if len(m.requests) > accessTuiBacklog { m.requests = m.requests[1:] } case accessLogLine: m.showLog = true - splitHeight := m.height - 5 - accessRequestsStyle.Height(splitHeight/2 - 1) - accessLogStyle.Height(splitHeight/2 - 1) + m.adjustPaneHeights() m.log = append(m.log, string(msg)) - if len(m.log) > accessBacklog { + if len(m.log) > accessTuiBacklog { m.log = m.log[1:] } @@ -60,13 +58,7 @@ func (m *accessModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { accessLogStyle.Width(m.width - 2) m.height = msg.Height - if !m.showLog { - accessRequestsStyle.Height(m.height - 5) - } else { - splitHeight := m.height - 5 - accessRequestsStyle.Height(splitHeight/2 - 1) - accessLogStyle.Height(splitHeight/2 - 1) - } + m.adjustPaneHeights() case tea.KeyMsg: switch msg.String() { @@ -76,13 +68,7 @@ func (m *accessModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, tea.ClearScreen case "l": m.showLog = !m.showLog - if !m.showLog { - accessRequestsStyle.Height(m.height - 5) - } else { - splitHeight := m.height - 5 - accessRequestsStyle.Height(splitHeight/2 - 1) - accessLogStyle.Height(splitHeight/2 - 1) - } + m.adjustPaneHeights() } } @@ -107,6 +93,16 @@ func (m *accessModel) View() string { ) } +func (m *accessModel) adjustPaneHeights() { + if !m.showLog { + accessRequestsStyle.Height(m.height - 5) + } else { + splitHeight := m.height - 5 + accessRequestsStyle.Height(splitHeight/2 - 1) + accessLogStyle.Height(splitHeight/2 - 1) + } +} + func (m *accessModel) renderRequests() string { var requestLines []string for _, req := range m.requests { diff --git a/cmd/zrok/sharePrivate.go b/cmd/zrok/sharePrivate.go index 2429a624..851ebc20 100644 --- a/cmd/zrok/sharePrivate.go +++ b/cmd/zrok/sharePrivate.go @@ -186,7 +186,9 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { } else { shareDescription := fmt.Sprintf("access your share with: %v", tui.CodeStyle.Render(fmt.Sprintf("zrok access private %v", resp.Payload.ShrToken))) mdl := newShareModel(resp.Payload.ShrToken, []string{shareDescription}, "private", cmd.backendMode) + logrus.SetOutput(mdl) prg := tea.NewProgram(mdl, tea.WithAltScreen()) + mdl.prg = prg go func() { for { diff --git a/cmd/zrok/sharePublic.go b/cmd/zrok/sharePublic.go index 1cae1dbd..7baf2436 100644 --- a/cmd/zrok/sharePublic.go +++ b/cmd/zrok/sharePublic.go @@ -188,7 +188,9 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { } else { mdl := newShareModel(resp.Payload.ShrToken, resp.Payload.FrontendProxyEndpoints, "public", cmd.backendMode) + logrus.SetOutput(mdl) prg := tea.NewProgram(mdl, tea.WithAltScreen()) + mdl.prg = prg go func() { for { diff --git a/cmd/zrok/shareReserved.go b/cmd/zrok/shareReserved.go index 72a67842..f57f381f 100644 --- a/cmd/zrok/shareReserved.go +++ b/cmd/zrok/shareReserved.go @@ -163,7 +163,9 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { } mdl := newShareModel(shrToken, []string{shareDescription}, resp.Payload.ShareMode, resp.Payload.BackendMode) + logrus.SetOutput(mdl) prg := tea.NewProgram(mdl, tea.WithAltScreen()) + mdl.prg = prg go func() { for { diff --git a/cmd/zrok/shareTui.go b/cmd/zrok/shareTui.go index 87102481..71c39174 100644 --- a/cmd/zrok/shareTui.go +++ b/cmd/zrok/shareTui.go @@ -4,22 +4,30 @@ import ( "fmt" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" + "github.com/muesli/reflow/wordwrap" "github.com/openziti-test-kitchen/zrok/endpoints" "strings" "time" ) +const shareTuiBacklog = 256 + type shareModel struct { shrToken string frontendDescriptions []string shareMode string backendMode string requests []*endpoints.Request - logMessages []string + log []string + showLog bool width int height int + headerHeight int + prg *tea.Program } +type shareLogLine string + func newShareModel(shrToken string, frontendEndpoints []string, shareMode, backendMode string) *shareModel { return &shareModel{ shrToken: shrToken, @@ -34,9 +42,18 @@ func (m *shareModel) Init() tea.Cmd { return nil } func (m *shareModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case *endpoints.Request: - m.requests = append([]*endpoints.Request{msg}, m.requests...) - if len(m.requests) > 2048 { - m.requests = m.requests[:2048] + m.requests = append(m.requests, msg) + if len(m.requests) > shareTuiBacklog { + m.requests = m.requests[1:] + } + + case shareLogLine: + m.showLog = true + m.adjustPaneHeights() + + m.log = append(m.log, string(msg)) + if len(m.log) > shareTuiBacklog { + m.log = m.log[1:] } case tea.WindowSizeMsg: @@ -44,9 +61,11 @@ func (m *shareModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { shareHeaderStyle.Width(m.width - 30) shareConfigStyle.Width(26) shareRequestsStyle.Width(m.width - 2) + shareLogStyle.Width(m.width - 2) m.height = msg.Height - shareRequestsStyle.Height(m.height - (len(m.frontendDescriptions) + 6)) + m.headerHeight = len(m.frontendDescriptions) + 4 + m.adjustPaneHeights() case tea.KeyMsg: switch msg.String() { @@ -54,6 +73,9 @@ func (m *shareModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, tea.Quit case "ctrl+l": return m, tea.ClearScreen + case "l": + m.showLog = !m.showLog + m.adjustPaneHeights() } } @@ -65,9 +87,26 @@ func (m *shareModel) View() string { shareHeaderStyle.Render(strings.Join(m.frontendDescriptions, "\n")), shareConfigStyle.Render(m.renderConfig()), ) - requests := shareRequestsStyle.Render(m.renderBackendRequests()) - all := lipgloss.JoinVertical(lipgloss.Left, topRow, requests) - return all + var panes string + if m.showLog { + panes = lipgloss.JoinVertical(lipgloss.Left, + shareRequestsStyle.Render(m.renderRequests()), + shareLogStyle.Render(m.renderLog()), + ) + } else { + panes = shareRequestsStyle.Render(m.renderRequests()) + } + return lipgloss.JoinVertical(lipgloss.Left, topRow, panes) +} + +func (m *shareModel) adjustPaneHeights() { + if !m.showLog { + shareRequestsStyle.Height(m.height - m.headerHeight) + } else { + splitHeight := m.height - m.headerHeight + shareRequestsStyle.Height(splitHeight/2 - 1) + shareLogStyle.Height(splitHeight/2 - 1) + } } func (m *shareModel) renderConfig() string { @@ -87,21 +126,37 @@ func (m *shareModel) renderConfig() string { return out } -func (m *shareModel) renderBackendRequests() string { - out := "" - maxRows := shareRequestsStyle.GetHeight() - for i := 0; i < maxRows && i < len(m.requests); i++ { - req := m.requests[i] - out += fmt.Sprintf("%v %v -> %v %v", +func (m *shareModel) renderRequests() string { + var requestLines []string + for _, req := range m.requests { + reqLine := fmt.Sprintf("%v %v -> %v %v", timeStyle.Render(req.Stamp.Format(time.RFC850)), addressStyle.Render(req.RemoteAddr), m.renderMethod(req.Method), req.Path, ) - if i != maxRows-1 { - out += "\n" + reqLineWrapped := wordwrap.String(reqLine, m.width-2) + splitWrapped := strings.Split(reqLineWrapped, "\n") + for _, splitLine := range splitWrapped { + splitLine := strings.ReplaceAll(splitLine, "\n", "") + if splitLine != "" { + requestLines = append(requestLines, splitLine) + } } } + maxRows := shareRequestsStyle.GetHeight() + startRow := 0 + if len(requestLines) > maxRows { + startRow = len(requestLines) - maxRows + } + out := "" + for i := startRow; i < len(requestLines); i++ { + outLine := requestLines[i] + if i < len(requestLines)-1 { + outLine += "\n" + } + out += outLine + } return out } @@ -116,23 +171,61 @@ func (m *shareModel) renderMethod(method string) string { } } +func (m *shareModel) renderLog() string { + var splitLines []string + for _, line := range m.log { + wrapped := wordwrap.String(line, m.width-2) + wrappedLines := strings.Split(wrapped, "\n") + for _, wrappedLine := range wrappedLines { + splitLine := strings.ReplaceAll(wrappedLine, "\n", "") + if splitLine != "" { + splitLines = append(splitLines, splitLine) + } + } + } + maxRows := shareLogStyle.GetHeight() + startRow := 0 + if len(splitLines) > maxRows { + startRow = len(splitLines) - maxRows + } + out := "" + for i := startRow; i < len(splitLines); i++ { + outLine := splitLines[i] + if i < len(splitLines)-1 { + outLine += "\n" + } + out += outLine + } + return out +} + +func (m *shareModel) Write(p []byte) (n int, err error) { + in := string(p) + lines := strings.Split(in, "\n") + for _, line := range lines { + cleanLine := strings.ReplaceAll(line, "\n", "") + if cleanLine != "" { + m.prg.Send(shareLogLine(cleanLine)) + } + } + return len(p), nil +} + var shareHeaderStyle = lipgloss.NewStyle(). - Height(3). - PaddingTop(1).PaddingLeft(2).PaddingBottom(1).PaddingRight(2). BorderStyle(lipgloss.RoundedBorder()). BorderForeground(lipgloss.Color("63")). Align(lipgloss.Center) var shareConfigStyle = lipgloss.NewStyle(). - Height(3). - PaddingTop(1).PaddingLeft(2).PaddingBottom(1).PaddingRight(2). BorderStyle(lipgloss.RoundedBorder()). BorderForeground(lipgloss.Color("63")). Align(lipgloss.Center) var shareRequestsStyle = lipgloss.NewStyle(). - Height(3). - PaddingLeft(2).PaddingRight(2). + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(lipgloss.Color("63")) + +var shareLogStyle = lipgloss.NewStyle(). BorderStyle(lipgloss.RoundedBorder()). BorderForeground(lipgloss.Color("63")) From 245e2a7f214fffcc2b6dc1c2c5415e1f6300bb68 Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Wed, 11 Jan 2023 14:26:56 -0500 Subject: [PATCH 29/32] zrok invite tui (#153) --- cmd/zrok/invite.go | 219 ++++++++++++++++++++++++++++++++++-------- cmd/zrok/inviteTui.go | 1 + go.mod | 2 + go.sum | 12 +++ 4 files changed, 196 insertions(+), 38 deletions(-) create mode 100644 cmd/zrok/inviteTui.go diff --git a/cmd/zrok/invite.go b/cmd/zrok/invite.go index 8a5a91d4..ca7579fb 100644 --- a/cmd/zrok/invite.go +++ b/cmd/zrok/invite.go @@ -2,13 +2,17 @@ package main import ( "fmt" + "github.com/charmbracelet/bubbles/textinput" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" "github.com/openziti-test-kitchen/zrok/rest_client_zrok/account" "github.com/openziti-test-kitchen/zrok/rest_model_zrok" "github.com/openziti-test-kitchen/zrok/tui" "github.com/openziti-test-kitchen/zrok/util" "github.com/openziti-test-kitchen/zrok/zrokdir" - "github.com/openziti/foundation/v2/term" "github.com/spf13/cobra" + "os" + "strings" ) func init() { @@ -17,6 +21,7 @@ func init() { type inviteCommand struct { cmd *cobra.Command + tui inviteTui } func newInviteCommand() *inviteCommand { @@ -25,50 +30,188 @@ func newInviteCommand() *inviteCommand { Short: "Invite a new user to zrok", Args: cobra.ExactArgs(0), } - command := &inviteCommand{cmd: cmd} + command := &inviteCommand{ + cmd: cmd, + tui: newInviteTui(), + } cmd.Run = command.run return command } func (cmd *inviteCommand) run(_ *cobra.Command, _ []string) { - email, err := term.Prompt("New Email: ") - if err != nil { - panic(err) - } - if !util.IsValidEmail(email) { - tui.Error(fmt.Sprintf("'%v' is not a valid email address", email), nil) - } - confirm, err := term.Prompt("Confirm Email: ") - if err != nil { - panic(err) - } - if confirm != email { - tui.Error("entered emails do not match... aborting!", nil) + if _, err := tea.NewProgram(&cmd.tui).Run(); err != nil { + tui.Error("unable to run interface", err) + os.Exit(1) } + if cmd.tui.done { + email := cmd.tui.inputs[0].Value() - zrd, err := zrokdir.Load() - if err != nil { - tui.Error("error loading zrokdir", err) - } - - zrok, err := zrd.Client() - if err != nil { - if !panicInstead { - tui.Error("error creating zrok api client", err) + zrd, err := zrokdir.Load() + if err != nil { + tui.Error("error loading zrokdir", err) } - panic(err) - } - req := account.NewInviteParams() - req.Body = &rest_model_zrok.InviteRequest{ - Email: email, - } - _, err = zrok.Account.Invite(req) - if err != nil { - if !panicInstead { - tui.Error("error creating invitation", err) - } - panic(err) - } - fmt.Printf("invitation sent to '%v'!\n", email) + zrok, err := zrd.Client() + if err != nil { + if !panicInstead { + tui.Error("error creating zrok api client", err) + } + panic(err) + } + req := account.NewInviteParams() + req.Body = &rest_model_zrok.InviteRequest{ + Email: email, + } + _, err = zrok.Account.Invite(req) + if err != nil { + if !panicInstead { + tui.Error("error creating invitation", err) + } + panic(err) + } + + fmt.Printf("invitation sent to '%v'!\n", email) + } +} + +type inviteTui struct { + focusIndex int + msg string + inputs []textinput.Model + cursorMode textinput.CursorMode + done bool + + msgOk string + msgMismatch string + focusedStyle lipgloss.Style + blurredStyle lipgloss.Style + errorStyle lipgloss.Style + cursorStyle lipgloss.Style + noStyle lipgloss.Style + helpStyle lipgloss.Style + focusedButton string + blurredButton string +} + +func newInviteTui() inviteTui { + m := inviteTui{ + inputs: make([]textinput.Model, 2), + } + m.focusedStyle = tui.WarningStyle + m.blurredStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#555")) + m.errorStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#F00")) + m.cursorStyle = m.focusedStyle.Copy() + m.noStyle = lipgloss.NewStyle() + m.helpStyle = m.blurredStyle.Copy() + m.focusedButton = m.focusedStyle.Copy().Render("[ Submit ]") + m.blurredButton = fmt.Sprintf("[ %v ]", m.blurredStyle.Render("Submit")) + m.msgOk = m.noStyle.Render("Enter and confirm your email address...") + m.msg = m.msgOk + m.msgMismatch = m.errorStyle.Render("Email is invalid or does not match confirmation...") + + var t textinput.Model + for i := range m.inputs { + t = textinput.New() + t.CursorStyle = m.cursorStyle + t.CharLimit = 96 + + switch i { + case 0: + t.Placeholder = "Email Address" + t.Focus() + t.PromptStyle = m.focusedStyle + t.TextStyle = m.focusedStyle + case 1: + t.Placeholder = "Confirm Email" + } + + m.inputs[i] = t + } + + return m +} + +func (m inviteTui) Init() tea.Cmd { return textinput.Blink } + +func (m *inviteTui) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "ctrl+c", "esc": + return m, tea.Quit + + case "tab", "shift+tab", "enter", "up", "down": + s := msg.String() + + if s == "enter" && m.focusIndex == len(m.inputs) { + if util.IsValidEmail(m.inputs[0].Value()) && m.inputs[0].Value() == m.inputs[1].Value() { + m.done = true + return m, tea.Quit + } + m.msg = m.msgMismatch + return m, nil + } + + if s == "up" || s == "shift+tab" { + m.msg = m.msgOk + m.focusIndex-- + } else { + m.msg = m.msgOk + m.focusIndex++ + } + + if m.focusIndex > len(m.inputs) { + m.focusIndex = 0 + } else if m.focusIndex < 0 { + m.focusIndex = len(m.inputs) + } + + cmds := make([]tea.Cmd, len(m.inputs)) + for i := 0; i <= len(m.inputs)-1; i++ { + if i == m.focusIndex { + cmds[i] = m.inputs[i].Focus() + m.inputs[i].PromptStyle = m.focusedStyle + m.inputs[i].TextStyle = m.focusedStyle + continue + } + m.inputs[i].Blur() + m.inputs[i].PromptStyle = m.noStyle + m.inputs[i].TextStyle = m.noStyle + } + + return m, tea.Batch(cmds...) + } + } + + cmd := m.updateInputs(msg) + + return m, cmd +} + +func (m *inviteTui) updateInputs(msg tea.Msg) tea.Cmd { + cmds := make([]tea.Cmd, len(m.inputs)) + for i := range m.inputs { + m.inputs[i], cmds[i] = m.inputs[i].Update(msg) + } + return tea.Batch(cmds...) +} + +func (m inviteTui) View() string { + var b strings.Builder + b.WriteString(fmt.Sprintf("\n%v\n\n", m.msg)) + + for i := range m.inputs { + b.WriteString(m.inputs[i].View()) + if i < len(m.inputs)-1 { + b.WriteRune('\n') + } + } + + button := &m.blurredButton + if m.focusIndex == len(m.inputs) { + button = &m.focusedButton + } + _, _ = fmt.Fprintf(&b, "\n\n%s\n\n", *button) + + return b.String() } diff --git a/cmd/zrok/inviteTui.go b/cmd/zrok/inviteTui.go new file mode 100644 index 00000000..06ab7d0f --- /dev/null +++ b/cmd/zrok/inviteTui.go @@ -0,0 +1 @@ +package main diff --git a/go.mod b/go.mod index aa5166ee..c98cb934 100644 --- a/go.mod +++ b/go.mod @@ -40,8 +40,10 @@ require ( require ( github.com/Jeffail/gabs v1.4.0 // indirect github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect + github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52 v1.0.3 // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect + github.com/charmbracelet/bubbles v0.14.0 // indirect github.com/containerd/console v1.0.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/deepmap/oapi-codegen v1.8.2 // indirect diff --git a/go.sum b/go.sum index fae55348..163be561 100644 --- a/go.sum +++ b/go.sum @@ -53,6 +53,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aymanbagabas/go-osc52 v1.0.3 h1:DTwqENW7X9arYimJrPeGZcV0ln14sGMt3pHZspWD+Mg= github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -60,8 +62,13 @@ github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqO github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/charmbracelet/bubbles v0.14.0 h1:DJfCwnARfWjZLvMglhSQzo76UZ2gucuHPy9jLWX45Og= +github.com/charmbracelet/bubbles v0.14.0/go.mod h1:bbeTiXwPww4M031aGi8UK2HT9RDWoiNibae+1yCMtcc= +github.com/charmbracelet/bubbletea v0.21.0/go.mod h1:GgmJMec61d08zXsOhqRC/AiOx4K4pmz+VIcRIm1FKr4= github.com/charmbracelet/bubbletea v0.23.1 h1:CYdteX1wCiCzKNUlwm25ZHBIc1GXlYFyUIte8WPvhck= github.com/charmbracelet/bubbletea v0.23.1/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU= +github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= +github.com/charmbracelet/lipgloss v0.5.0/go.mod h1:EZLha/HbzEt7cYqdFPovlqy5FZPj0xFhg5SaqxScmgs= github.com/charmbracelet/lipgloss v0.6.0 h1:1StyZB9vBSOyuZxQUcUwGr17JmojPNm87inij9N3wJY= github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -326,6 +333,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -411,12 +419,14 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34= github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= +github.com/muesli/cancelreader v0.2.0/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= +github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= github.com/muesli/termenv v0.13.0 h1:wK20DRpJdDX8b7Ek2QfhvqhRQFZ237RGRO0RQ/Iqdy0= github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc= github.com/netfoundry/secretstream v0.1.2 h1:NgqrYytDnjKbOfWI29TT0SJM+RwB3yf9MIkJVJaU+J0= @@ -488,6 +498,7 @@ github.com/rubenv/sql-migrate v1.1.2/go.mod h1:/7TZymwxN8VWumcIxw1jjHEcR1djpdkMH github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shirou/gopsutil/v3 v3.22.8 h1:a4s3hXogo5mE2PfdfJIonDbstO/P+9JszdfhAHSzD9Y= github.com/shirou/gopsutil/v3 v3.22.8/go.mod h1:s648gW4IywYzUfE/KjXxUsqrqx/T2xO5VqOXxONeRfI= @@ -765,6 +776,7 @@ golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= From 2767280d2c36511693e937cfbe5b2b471c9080d2 Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Wed, 11 Jan 2023 14:29:14 -0500 Subject: [PATCH 30/32] reuse central tui styles (#153) --- cmd/zrok/invite.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/zrok/invite.go b/cmd/zrok/invite.go index ca7579fb..2081aef5 100644 --- a/cmd/zrok/invite.go +++ b/cmd/zrok/invite.go @@ -98,7 +98,7 @@ func newInviteTui() inviteTui { inputs: make([]textinput.Model, 2), } m.focusedStyle = tui.WarningStyle - m.blurredStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#555")) + m.blurredStyle = tui.CodeStyle m.errorStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#F00")) m.cursorStyle = m.focusedStyle.Copy() m.noStyle = lipgloss.NewStyle() From 630cc274af979dee9c52154888a32ec3f9dc34a9 Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Wed, 11 Jan 2023 15:00:08 -0500 Subject: [PATCH 31/32] progress-enabled zrok enable command (#154) --- cmd/zrok/disable.go | 2 +- cmd/zrok/enable.go | 99 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 86 insertions(+), 15 deletions(-) diff --git a/cmd/zrok/disable.go b/cmd/zrok/disable.go index f305eac7..6e2ea4d0 100644 --- a/cmd/zrok/disable.go +++ b/cmd/zrok/disable.go @@ -70,5 +70,5 @@ func (cmd *disableCommand) run(_ *cobra.Command, _ []string) { tui.Error("error removing zrok backend identity", err) } } - fmt.Printf("zrok environment '%v' disabled for '%v'\n", zrd.Env.ZId, zrd.Env.Token) + fmt.Println("zrok environment disabled...") } diff --git a/cmd/zrok/enable.go b/cmd/zrok/enable.go index e220123d..043895d4 100644 --- a/cmd/zrok/enable.go +++ b/cmd/zrok/enable.go @@ -2,6 +2,8 @@ package main import ( "fmt" + "github.com/charmbracelet/bubbles/spinner" + tea "github.com/charmbracelet/bubbletea" httptransport "github.com/go-openapi/runtime/client" "github.com/openziti-test-kitchen/zrok/rest_client_zrok/environment" "github.com/openziti-test-kitchen/zrok/rest_model_zrok" @@ -9,6 +11,7 @@ import ( "github.com/openziti-test-kitchen/zrok/zrokdir" "github.com/shirou/gopsutil/v3/host" "github.com/spf13/cobra" + "os" user2 "os/user" ) @@ -52,7 +55,6 @@ func (cmd *enableCommand) run(_ *cobra.Command, args []string) { if cmd.description == "@" { cmd.description = fmt.Sprintf("%v@%v", user.Username, hostName) } - zrok, err := zrd.Client() if err != nil { panic(err) @@ -63,29 +65,49 @@ func (cmd *enableCommand) run(_ *cobra.Command, args []string) { Description: cmd.description, Host: hostDetail, } + + var prg *tea.Program + var mdl enableTuiModel + var done = make(chan struct{}) + go func() { + mdl = newEnableTuiModel() + mdl.msg = "contacting the zrok service..." + prg = tea.NewProgram(mdl) + if _, err := prg.Run(); err != nil { + fmt.Println(err) + } + close(done) + if mdl.quitting { + os.Exit(1) + } + }() + resp, err := zrok.Environment.Enable(req, auth) if err != nil { - if !panicInstead { - tui.Error("the zrok service returned an error", err) - } - panic(err) + prg.Send(fmt.Sprintf("the zrok service returned an error: %v", err)) + prg.Quit() + <-done + os.Exit(1) } + prg.Send("writing the environment details...") apiEndpoint, _ := zrd.ApiEndpoint() zrd.Env = &zrokdir.Environment{Token: token, ZId: resp.Payload.Identity, ApiEndpoint: apiEndpoint} if err := zrd.Save(); err != nil { - if !panicInstead { - tui.Error("there was an error saving the new environment", err) - } - panic(err) + prg.Send(fmt.Sprintf("there was an error saving the new environment: %v", err)) + prg.Quit() + <-done + os.Exit(1) } if err := zrokdir.SaveZitiIdentity("backend", resp.Payload.Cfg); err != nil { - if !panicInstead { - tui.Error("there was an error writing the environment file", err) - } - panic(err) + prg.Send(fmt.Sprintf("there was an error writing the environment: %v", err)) + prg.Quit() + <-done + os.Exit(1) } - fmt.Printf("zrok environment '%v' enabled for '%v'\n", resp.Payload.Identity, token) + prg.Send(fmt.Sprintf("the zrok environment was successfully enabled...")) + prg.Quit() + <-done } func getHost() (string, string, error) { @@ -97,3 +119,52 @@ func getHost() (string, string, error) { info.Hostname, info.OS, info.Platform, info.PlatformFamily, info.PlatformVersion, info.KernelVersion, info.KernelArch) return info.Hostname, thisHost, nil } + +type enableTuiModel struct { + spinner spinner.Model + msg string + quitting bool +} + +func newEnableTuiModel() enableTuiModel { + s := spinner.New() + s.Spinner = spinner.Dot + s.Style = tui.WarningStyle + return enableTuiModel{spinner: s} +} + +func (m enableTuiModel) Init() tea.Cmd { return m.spinner.Tick } + +func (m enableTuiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case string: + m.msg = msg + return m, nil + + case tea.KeyMsg: + switch msg.String() { + case "q", "esc", "ctrl+c": + m.quitting = true + return m, tea.Quit + + default: + return m, nil + } + + case struct{}: + return m, tea.Quit + + default: + var cmd tea.Cmd + m.spinner, cmd = m.spinner.Update(msg) + return m, cmd + } +} + +func (m enableTuiModel) View() string { + str := fmt.Sprintf("%s %s\n", m.spinner.View(), m.msg) + if m.quitting { + return str + } + return str +} From 37676a01762390e4456bd4e8b40bb9d06d9623f4 Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Wed, 11 Jan 2023 15:10:26 -0500 Subject: [PATCH 32/32] lint (#56) --- cmd/zrok/invite.go | 4 ++-- cmd/zrok/inviteTui.go | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 cmd/zrok/inviteTui.go diff --git a/cmd/zrok/invite.go b/cmd/zrok/invite.go index 2081aef5..0a7d2cad 100644 --- a/cmd/zrok/invite.go +++ b/cmd/zrok/invite.go @@ -105,9 +105,9 @@ func newInviteTui() inviteTui { m.helpStyle = m.blurredStyle.Copy() m.focusedButton = m.focusedStyle.Copy().Render("[ Submit ]") m.blurredButton = fmt.Sprintf("[ %v ]", m.blurredStyle.Render("Submit")) - m.msgOk = m.noStyle.Render("Enter and confirm your email address...") + m.msgOk = m.noStyle.Render("enter and confirm your email address...") m.msg = m.msgOk - m.msgMismatch = m.errorStyle.Render("Email is invalid or does not match confirmation...") + m.msgMismatch = m.errorStyle.Render("email is invalid or does not match confirmation...") var t textinput.Model for i := range m.inputs { diff --git a/cmd/zrok/inviteTui.go b/cmd/zrok/inviteTui.go deleted file mode 100644 index 06ab7d0f..00000000 --- a/cmd/zrok/inviteTui.go +++ /dev/null @@ -1 +0,0 @@ -package main