TUN-3255: Update UI to display URL instead of hostname

This commit is contained in:
Rachel Williams 2020-07-24 15:17:17 -07:00 committed by Areg Harutyunyan
parent 094e0c7592
commit fee13dc62f
3 changed files with 49 additions and 29 deletions

View File

@ -533,11 +533,11 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
}() }()
if c.IsSet("launch-ui") { if c.IsSet("launch-ui") {
connEventChan := make(chan ui.ConnEvent) tunnelEventChan := make(chan ui.TunnelEvent)
tunnelConfig.ConnEventChan = connEventChan tunnelConfig.TunnelEventChan = tunnelEventChan
tunnelInfo := ui.NewUIModel(version, hostname, metricsListener.Addr().String(), tunnelConfig.OriginUrl, tunnelConfig.HAConnections) tunnelInfo := ui.NewUIModel(version, hostname, metricsListener.Addr().String(), tunnelConfig.OriginUrl, tunnelConfig.HAConnections)
tunnelInfo.LaunchUI(ctx, logger, connEventChan) tunnelInfo.LaunchUI(ctx, logger, tunnelEventChan)
} }
return waitToShutdown(&wg, errC, shutdownC, graceShutdownC, c.Duration("grace-period"), logger) return waitToShutdown(&wg, errC, shutdownC, graceShutdownC, c.Duration("grace-period"), logger)

View File

@ -19,17 +19,20 @@ const (
Disconnected status = iota Disconnected status = iota
Connected Connected
Reconnecting Reconnecting
SetUrl
RegisteringTunnel
) )
type ConnEvent struct { type TunnelEvent struct {
Index uint8 Index uint8
EventType status EventType status
Location string Location string
Url string
} }
type uiModel struct { type uiModel struct {
version string version string
hostname string edgeURL string
metricsURL string metricsURL string
proxyURL string proxyURL string
connections []connState connections []connState
@ -46,14 +49,14 @@ type palette struct {
func NewUIModel(version, hostname, metricsURL, proxyURL string, haConnections int) *uiModel { func NewUIModel(version, hostname, metricsURL, proxyURL string, haConnections int) *uiModel {
return &uiModel{ return &uiModel{
version: version, version: version,
hostname: hostname, edgeURL: hostname,
metricsURL: metricsURL, metricsURL: metricsURL,
proxyURL: proxyURL, proxyURL: proxyURL,
connections: make([]connState, haConnections), connections: make([]connState, haConnections),
} }
} }
func (data *uiModel) LaunchUI(ctx context.Context, logger logger.Service, connEventChan <-chan ConnEvent) { func (data *uiModel) LaunchUI(ctx context.Context, logger logger.Service, tunnelEventChan <-chan TunnelEvent) {
palette := palette{url: "#4682B4", connected: "#00FF00", defaultText: "white", disconnected: "red", reconnecting: "orange"} palette := palette{url: "#4682B4", connected: "#00FF00", defaultText: "white", disconnected: "red", reconnecting: "orange"}
app := tview.NewApplication() app := tview.NewApplication()
@ -80,7 +83,9 @@ func (data *uiModel) LaunchUI(ctx context.Context, logger logger.Service, connEv
grid.AddItem(tview.NewTextView().SetText("Metrics:"), 3, 0, 1, 1, 0, 0, false) grid.AddItem(tview.NewTextView().SetText("Metrics:"), 3, 0, 1, 1, 0, 0, false)
grid.AddItem(tview.NewTextView().SetText(data.hostname), 0, 1, 1, 1, 0, 0, false) tunnelHostText := tview.NewTextView().SetText(data.edgeURL)
grid.AddItem(tunnelHostText, 0, 1, 1, 1, 0, 0, false)
grid.AddItem(newDynamicColorTextView().SetText(fmt.Sprintf("[%s]\u2022[%s] Proxying to [%s::b]%s", palette.connected, palette.defaultText, palette.url, data.proxyURL)), 1, 1, 1, 1, 0, 0, false) grid.AddItem(newDynamicColorTextView().SetText(fmt.Sprintf("[%s]\u2022[%s] Proxying to [%s::b]%s", palette.connected, palette.defaultText, palette.url, data.proxyURL)), 1, 1, 1, 1, 0, 0, false)
grid.AddItem(connTable, 2, 1, 1, 1, 0, 0, false) grid.AddItem(connTable, 2, 1, 1, 1, 0, 0, false)
@ -94,12 +99,19 @@ func (data *uiModel) LaunchUI(ctx context.Context, logger logger.Service, connEv
case <-ctx.Done(): case <-ctx.Done():
app.Stop() app.Stop()
return return
case conn := <-connEventChan: case event := <-tunnelEventChan:
switch conn.EventType { switch event.EventType {
case Connected: case Connected:
data.setConnTableCell(conn, connTable, palette) data.setConnTableCell(event, connTable, palette)
case Disconnected, Reconnecting: case Disconnected, Reconnecting:
data.changeConnStatus(conn, connTable, logger, palette) data.changeConnStatus(event, connTable, logger, palette)
case SetUrl:
tunnelHostText.SetText(event.Url)
data.edgeURL = event.Url
case RegisteringTunnel:
if data.edgeURL == "" {
tunnelHostText.SetText("Registering tunnel...")
}
} }
} }
app.Draw() app.Draw()
@ -117,8 +129,8 @@ func newDynamicColorTextView() *tview.TextView {
return tview.NewTextView().SetDynamicColors(true) return tview.NewTextView().SetDynamicColors(true)
} }
func (data *uiModel) changeConnStatus(conn ConnEvent, table *tview.Table, logger logger.Service, palette palette) { func (data *uiModel) changeConnStatus(event TunnelEvent, table *tview.Table, logger logger.Service, palette palette) {
index := int(conn.Index) index := int(event.Index)
// Get connection location and state // Get connection location and state
connState := data.getConnState(index) connState := data.getConnState(index)
// Check if connection is already displayed in UI // Check if connection is already displayed in UI
@ -127,11 +139,11 @@ func (data *uiModel) changeConnStatus(conn ConnEvent, table *tview.Table, logger
return return
} }
locationState := conn.Location locationState := event.Location
if conn.EventType == Disconnected { if event.EventType == Disconnected {
connState.state = Disconnected connState.state = Disconnected
} else if conn.EventType == Reconnecting { } else if event.EventType == Reconnecting {
connState.state = Reconnecting connState.state = Reconnecting
locationState = "Reconnecting..." locationState = "Reconnecting..."
} }
@ -140,7 +152,7 @@ func (data *uiModel) changeConnStatus(conn ConnEvent, table *tview.Table, logger
// Get table cell // Get table cell
cell := table.GetCell(index, 0) cell := table.GetCell(index, 0)
// Change dot color in front of text as well as location state // Change dot color in front of text as well as location state
text := newCellText(palette, connectionNum, locationState, conn.EventType) text := newCellText(palette, connectionNum, locationState, event.EventType)
cell.SetText(text) cell.SetText(text)
} }
@ -153,16 +165,16 @@ func (data *uiModel) getConnState(connID int) *connState {
return nil return nil
} }
func (data *uiModel) setConnTableCell(conn ConnEvent, table *tview.Table, palette palette) { func (data *uiModel) setConnTableCell(event TunnelEvent, table *tview.Table, palette palette) {
index := int(conn.Index) index := int(event.Index)
connectionNum := index + 1 connectionNum := index + 1
// Update slice to keep track of connection location and state in UI table // Update slice to keep track of connection location and state in UI table
data.connections[index].state = Connected data.connections[index].state = Connected
data.connections[index].location = conn.Location data.connections[index].location = event.Location
// Update text in table cell to show disconnected state // Update text in table cell to show disconnected state
text := newCellText(palette, connectionNum, conn.Location, conn.EventType) text := newCellText(palette, connectionNum, event.Location, event.EventType)
cell := tview.NewTableCell(text) cell := tview.NewTableCell(text)
table.SetCell(index, 0, cell) table.SetCell(index, 0, cell)
} }

View File

@ -89,7 +89,7 @@ type TunnelConfig struct {
NamedTunnel *NamedTunnelConfig NamedTunnel *NamedTunnelConfig
ReplaceExisting bool ReplaceExisting bool
ConnEventChan chan<- ui.ConnEvent TunnelEventChan chan<- ui.TunnelEvent
} }
type dupConnRegisterTunnelError struct{} type dupConnRegisterTunnelError struct{}
@ -236,8 +236,8 @@ func ServeTunnelLoop(ctx context.Context,
) )
if recoverable { if recoverable {
if duration, ok := backoff.GetBackoffDuration(ctx); ok { if duration, ok := backoff.GetBackoffDuration(ctx); ok {
if config.ConnEventChan != nil { if config.TunnelEventChan != nil {
config.ConnEventChan <- ui.ConnEvent{Index: connectionIndex, EventType: ui.Reconnecting} config.TunnelEventChan <- ui.TunnelEvent{Index: connectionIndex, EventType: ui.Reconnecting}
} }
config.Logger.Infof("Retrying connection %d in %s seconds", connectionIndex, duration) config.Logger.Infof("Retrying connection %d in %s seconds", connectionIndex, duration)
@ -275,9 +275,9 @@ func ServeTunnel(
}() }()
// If launch-ui flag is set, send disconnect msg // If launch-ui flag is set, send disconnect msg
if config.ConnEventChan != nil { if config.TunnelEventChan != nil {
defer func() { defer func() {
config.ConnEventChan <- ui.ConnEvent{Index: connectionIndex, EventType: ui.Disconnected} config.TunnelEventChan <- ui.TunnelEvent{Index: connectionIndex, EventType: ui.Disconnected}
}() }()
} }
@ -440,8 +440,8 @@ func RegisterConnection(
config.Logger.Infof("Connection %d registered with %s using ID %s", connectionIndex, conn.Location, conn.UUID) config.Logger.Infof("Connection %d registered with %s using ID %s", connectionIndex, conn.Location, conn.UUID)
// If launch-ui flag is set, send connect msg // If launch-ui flag is set, send connect msg
if config.ConnEventChan != nil { if config.TunnelEventChan != nil {
config.ConnEventChan <- ui.ConnEvent{Index: connectionIndex, EventType: ui.Connected, Location: conn.Location} config.TunnelEventChan <- ui.TunnelEvent{Index: connectionIndex, EventType: ui.Connected, Location: conn.Location}
} }
return nil return nil
@ -487,6 +487,9 @@ func RegisterTunnel(
uuid uuid.UUID, uuid uuid.UUID,
) error { ) error {
config.TransportLogger.Debug("initiating RPC stream to register") config.TransportLogger.Debug("initiating RPC stream to register")
if config.TunnelEventChan != nil {
config.TunnelEventChan <- ui.TunnelEvent{EventType: ui.RegisteringTunnel}
}
tunnelServer, err := connection.NewRPCClient(ctx, muxer, config.TransportLogger, openStreamTimeout) tunnelServer, err := connection.NewRPCClient(ctx, muxer, config.TransportLogger, openStreamTimeout)
if err != nil { if err != nil {
// RPC stream open error // RPC stream open error
@ -508,6 +511,11 @@ func RegisterTunnel(
// RegisterTunnel RPC failure // RegisterTunnel RPC failure
return processRegisterTunnelError(registrationErr, config.Metrics, register) return processRegisterTunnelError(registrationErr, config.Metrics, register)
} }
// Send free tunnel URL to UI
if config.TunnelEventChan != nil {
config.TunnelEventChan <- ui.TunnelEvent{EventType: ui.SetUrl, Url: registration.Url}
}
credentialManager.SetEventDigest(connectionID, registration.EventDigest) credentialManager.SetEventDigest(connectionID, registration.EventDigest)
return processRegistrationSuccess(config, logger, connectionID, registration, register, credentialManager) return processRegistrationSuccess(config, logger, connectionID, registration, register, credentialManager)
} }