http.go
2.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package term
import (
termbox "github.com/nsf/termbox-go"
"ngrok/client/mvc"
"ngrok/log"
"ngrok/proto"
"ngrok/util"
"unicode/utf8"
)
const (
size = 10
pathMaxLength = 25
)
type HttpView struct {
log.Logger
*area
httpProto *proto.Http
HttpRequests *util.Ring
shutdown chan int
termView *TermView
}
func colorFor(status string) termbox.Attribute {
switch status[0] {
case '3':
return termbox.ColorCyan
case '4':
return termbox.ColorYellow
case '5':
return termbox.ColorRed
default:
}
return termbox.ColorWhite
}
func newTermHttpView(ctl mvc.Controller, termView *TermView, proto *proto.Http, x, y int) *HttpView {
v := &HttpView{
httpProto: proto,
HttpRequests: util.NewRing(size),
area: NewArea(x, y, 70, size+5),
shutdown: make(chan int),
termView: termView,
Logger: log.NewPrefixLogger("view", "term", "http"),
}
ctl.Go(v.Run)
return v
}
func (v *HttpView) Run() {
updates := v.httpProto.Txns.Reg()
for {
select {
case txn := <-updates:
v.Debug("Got HTTP update")
if txn.(*proto.HttpTxn).Resp == nil {
v.HttpRequests.Add(txn)
}
v.Render()
}
}
}
func (v *HttpView) Render() {
v.Clear()
v.Printf(0, 0, "HTTP Requests")
v.Printf(0, 1, "-------------")
for i, obj := range v.HttpRequests.Slice() {
txn := obj.(*proto.HttpTxn)
path := truncatePath(txn.Req.URL.Path)
v.Printf(0, 3+i, "%s %v", txn.Req.Method, path)
if txn.Resp != nil {
v.APrintf(colorFor(txn.Resp.Status), 30, 3+i, "%s", txn.Resp.Status)
}
}
v.termView.Flush()
}
func (v *HttpView) Shutdown() {
close(v.shutdown)
}
func truncatePath(path string) string {
// Truncate all long strings based on rune count
if utf8.RuneCountInString(path) > pathMaxLength {
path = string([]rune(path)[:pathMaxLength])
}
// By this point, len(path) should be < pathMaxLength if we're dealing with single-byte runes.
// Otherwise, we have a multi-byte string and need to calculate the size of each rune and
// truncate manually.
//
// This is a workaround for a bug in termbox-go. Remove it when this issue is fixed:
// https://github.com/nsf/termbox-go/pull/21
if len(path) > pathMaxLength {
out := make([]byte, pathMaxLength, pathMaxLength)
length := 0
for {
r, size := utf8.DecodeRuneInString(path[length:])
if r == utf8.RuneError && size == 1 {
break
}
// utf8.EncodeRune expects there to be enough room to store the full size of the rune
if length+size <= pathMaxLength {
utf8.EncodeRune(out[length:], r)
length += size
} else {
break
}
}
path = string(out[:length])
}
return path
}