mirror of
https://github.com/openziti/zrok.git
synced 2024-11-22 08:03:49 +01:00
access tui (#56)
This commit is contained in:
parent
a63b66ad97
commit
98b8c8c8a1
111
cmd/zrok/accessModel.go
Normal file
111
cmd/zrok/accessModel.go
Normal file
@ -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
|
||||
}
|
@ -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) {
|
||||
|
@ -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()).
|
||||
|
@ -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() {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user