123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- /*
- interactive terminal interface for local clients
- */
- package ui
- import (
- "fmt"
- termbox "github.com/nsf/termbox-go"
- "time"
- )
- const (
- fgColor = termbox.ColorWhite
- bgColor = termbox.ColorDefault
- )
- func clear() {
- w, h := termbox.Size()
- for i := 0; i < w; i++ {
- for j := 0; j < h; j++ {
- termbox.SetCell(i, j, ' ', fgColor, bgColor)
- }
- }
- }
- func printfAttr(x, y int, fg termbox.Attribute, arg0 string, args ...interface{}) {
- s := fmt.Sprintf(arg0, args...)
- for i, ch := range s {
- termbox.SetCell(x+i, y, ch, fg, bgColor)
- }
- }
- func printf(x, y int, arg0 string, args ...interface{}) {
- printfAttr(x, y, fgColor, arg0, args...)
- }
- type Term struct {
- ui *Ui
- statusColorMap map[string]termbox.Attribute
- }
- func NewTerm() *Term {
- return &Term{
- statusColorMap: map[string]termbox.Attribute{
- "connecting": termbox.ColorCyan,
- "reconnecting": termbox.ColorRed,
- "online": termbox.ColorGreen,
- },
- }
- }
- func (t *Term) SetUi(ui *Ui) {
- t.ui = ui
- go t.run()
- }
- func (t *Term) run() {
- // make sure we shut down cleanly
- t.ui.Wait.Add(1)
- defer t.ui.Wait.Done()
- // open channels for incoming application state changes
- // and broadbasts
- updates := t.ui.Updates.Reg()
- // init/close termbox library
- termbox.Init()
- defer termbox.Close()
- go t.input()
- t.draw(updates)
- }
- func (t *Term) draw(updates chan State) {
- for {
- select {
- case state := <-updates:
- // program is shutting down
- if state.IsStopping() {
- return
- }
- clear()
- printfAttr(0, 0, termbox.ColorBlue|termbox.AttrBold, "ngrok")
- msec := float64(time.Millisecond)
- printf(0, 2, "%-30s%s", "Version", state.GetVersion())
- printf(0, 3, "%-30s%s -> %s", "Forwarding", state.GetPublicUrl(), state.GetLocalAddr())
- printf(0, 4, "%-30s%s", "HTTP Dashboard", "http://127.0.0.1:9999")
- printfAttr(0, 5, t.statusColorMap[state.GetStatus()], "%-30s%s", "Tunnel Status", state.GetStatus())
- connMeter, connTimer := state.GetConnectionMetrics()
- printf(0, 6, "%-30s%d", "# Conn", connMeter.Count())
- printf(0, 7, "%-30s%.2fms", "Mean Conn Time", connTimer.Mean()/msec)
- printf(0, 8, "%-30s%.2fms", "Conn Time 95th PCTL", connTimer.Percentile(0.95)/msec)
- bytesInCount, bytesIn := state.GetBytesInMetrics()
- printf(0, 9, "%-30s%d", "Bytes In", bytesInCount.Count())
- printf(0, 10, "%-30s%.2f", "Avg Bytes/req", bytesIn.Mean())
- bytesOutCount, bytesOut := state.GetBytesOutMetrics()
- printf(0, 11, "%-30s%d", "Bytes Out", bytesOutCount.Count())
- printf(0, 12, "%-30s%.2f", "Bytes Out/req", bytesOut.Mean())
- if state.GetProtocol() == "http" {
- printf(0, 13, "HTTP Requests")
- for i, http := range state.GetHistory() {
- req := http.GetRequest()
- resp := http.GetResponse()
- printf(0, 15+i, "%s %v", req.Method, req.URL)
- if resp != nil {
- printf(30, 15+i, "%s", resp.Status)
- }
- }
- }
- termbox.Flush()
- }
- }
- }
- func (t *Term) input() {
- for {
- ev := termbox.PollEvent()
- switch ev.Type {
- case termbox.EventKey:
- switch ev.Key {
- case termbox.KeyCtrlC:
- t.ui.Cmds <- Command{QUIT, ""}
- return
- }
- }
- }
- }
|