give better names to stuff
This commit is contained in:
parent
b94d20865d
commit
0613222b4b
112
capture.go
112
capture.go
|
@ -9,26 +9,25 @@ import (
|
|||
|
||||
var captureID int
|
||||
|
||||
// CaptureList stores all captures
|
||||
type CaptureList struct {
|
||||
// CaptureService handles captures
|
||||
type CaptureService struct {
|
||||
items []Capture
|
||||
mu sync.RWMutex
|
||||
maxItems int
|
||||
updated chan struct{} // signals any change in "items"
|
||||
}
|
||||
|
||||
// Capture saves our traffic data
|
||||
// Capture is our traffic data
|
||||
type Capture struct {
|
||||
ID int
|
||||
Req *http.Request
|
||||
Res *http.Response
|
||||
|
||||
// Elapsed time of the request, in milliseconds
|
||||
Elapsed time.Duration
|
||||
}
|
||||
|
||||
// CaptureMetadata is the data for each list item in the dashboard
|
||||
type CaptureMetadata struct {
|
||||
// DashboardItem is an item in the dashboard's list
|
||||
type DashboardItem struct {
|
||||
ID int `json:"id"`
|
||||
Path string `json:"path"`
|
||||
Method string `json:"method"`
|
||||
|
@ -37,51 +36,42 @@ type CaptureMetadata struct {
|
|||
Elapsed time.Duration `json:"elapsed"`
|
||||
}
|
||||
|
||||
// CaptureDump saves all the dumps shown in the dashboard
|
||||
// CaptureDump is all the dumps shown in the dashboard
|
||||
type CaptureDump struct {
|
||||
Request string `json:"request"`
|
||||
Response string `json:"response"`
|
||||
Curl string `json:"curl"`
|
||||
}
|
||||
|
||||
// Metadata returns the metadada of a capture
|
||||
func (c *Capture) Metadata() CaptureMetadata {
|
||||
return CaptureMetadata{
|
||||
ID: c.ID,
|
||||
Path: c.Req.URL.Path,
|
||||
Method: c.Req.Method,
|
||||
Status: c.Res.StatusCode,
|
||||
Elapsed: c.Elapsed,
|
||||
}
|
||||
}
|
||||
|
||||
// NewCaptureList creates a new list of captures
|
||||
func NewCaptureList(maxItems int) *CaptureList {
|
||||
return &CaptureList{
|
||||
// NewCaptureService creates a new service of captures
|
||||
func NewCaptureService(maxItems int) *CaptureService {
|
||||
return &CaptureService{
|
||||
maxItems: maxItems,
|
||||
updated: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// Insert adds a new capture
|
||||
func (c *CaptureList) Insert(capture Capture) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
// Insert inserts a new capture
|
||||
func (s *CaptureService) Insert(capture Capture) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
captureID++
|
||||
capture.ID = captureID
|
||||
c.items = append(c.items, capture)
|
||||
if len(c.items) > c.maxItems {
|
||||
c.items = c.items[1:]
|
||||
s.items = append(s.items, capture)
|
||||
if len(s.items) > s.maxItems {
|
||||
s.items = s.items[1:]
|
||||
}
|
||||
c.signalsChange()
|
||||
s.signalsUpdate()
|
||||
}
|
||||
|
||||
// Find finds a capture by its id
|
||||
func (c *CaptureList) Find(captureID string) *Capture {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
func (s *CaptureService) Find(captureID string) *Capture {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
idInt, _ := strconv.Atoi(captureID)
|
||||
for _, c := range c.items {
|
||||
for _, c := range s.items {
|
||||
if c.ID == idInt {
|
||||
return &c
|
||||
}
|
||||
|
@ -90,39 +80,43 @@ func (c *CaptureList) Find(captureID string) *Capture {
|
|||
}
|
||||
|
||||
// RemoveAll removes all the captures
|
||||
func (c *CaptureList) RemoveAll() {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
c.items = nil
|
||||
c.signalsChange()
|
||||
func (s *CaptureService) RemoveAll() {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
s.items = nil
|
||||
s.signalsUpdate()
|
||||
}
|
||||
|
||||
// Items returns all the captures
|
||||
func (c *CaptureList) Items() []Capture {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
return c.items
|
||||
}
|
||||
// DashboardItems returns the dashboard's list of items
|
||||
func (s *CaptureService) DashboardItems() []DashboardItem {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
// ItemsAsMetadata returns all the captures as metadata
|
||||
func (c *CaptureList) ItemsAsMetadata() []CaptureMetadata {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
metadatas := make([]CaptureMetadata, len(c.items))
|
||||
for i, capture := range c.items {
|
||||
metadatas[i] = capture.Metadata()
|
||||
metadatas := make([]DashboardItem, len(s.items))
|
||||
for i, capture := range s.items {
|
||||
metadatas[i] = DashboardItem{
|
||||
ID: capture.ID,
|
||||
Path: capture.Req.URL.Path,
|
||||
Method: capture.Req.Method,
|
||||
Status: capture.Res.StatusCode,
|
||||
Elapsed: capture.Elapsed,
|
||||
}
|
||||
}
|
||||
return metadatas
|
||||
}
|
||||
|
||||
func (c *CaptureList) signalsChange() {
|
||||
close(c.updated)
|
||||
c.updated = make(chan struct{})
|
||||
// signalsUpdate fires an update signal
|
||||
func (s *CaptureService) signalsUpdate() {
|
||||
close(s.updated)
|
||||
s.updated = make(chan struct{})
|
||||
}
|
||||
|
||||
// Updated signals any change in the list
|
||||
func (c *CaptureList) Updated() <-chan struct{} {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
return c.updated
|
||||
// Updated signals any change in this service,
|
||||
// like inserting or removing captures
|
||||
func (s *CaptureService) Updated() <-chan struct{} {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
return s.updated
|
||||
}
|
||||
|
|
40
main.go
40
main.go
|
@ -31,15 +31,15 @@ func main() {
|
|||
|
||||
func startCapture(config Config) {
|
||||
|
||||
list := NewCaptureList(config.MaxCaptures)
|
||||
srv := NewCaptureService(config.MaxCaptures)
|
||||
|
||||
handler := NewRecorder(list, NewPlugin(NewProxyHandler(config.TargetURL)))
|
||||
handler := NewRecorderHandler(srv, NewPluginHandler(NewProxyHandler(config.TargetURL)))
|
||||
|
||||
http.HandleFunc(config.DashboardPath, NewDashboardHTMLHandler(config))
|
||||
http.HandleFunc(config.DashboardConnPath, NewDashboardConnHandler(list))
|
||||
http.HandleFunc(config.DashboardInfoPath, NewDashboardInfoHandler(list))
|
||||
http.HandleFunc(config.DashboardClearPath, NewDashboardClearHandler(list))
|
||||
http.HandleFunc(config.DashboardRetryPath, NewDashboardRetryHandler(list, handler))
|
||||
http.HandleFunc(config.DashboardConnPath, NewDashboardConnHandler(srv))
|
||||
http.HandleFunc(config.DashboardInfoPath, NewDashboardInfoHandler(srv))
|
||||
http.HandleFunc(config.DashboardClearPath, NewDashboardClearHandler(srv))
|
||||
http.HandleFunc(config.DashboardRetryPath, NewDashboardRetryHandler(srv, handler))
|
||||
http.HandleFunc("/", handler)
|
||||
|
||||
captureHost := fmt.Sprintf("http://localhost:%s", config.ProxyPort)
|
||||
|
@ -52,7 +52,7 @@ func startCapture(config Config) {
|
|||
|
||||
// NewDashboardConnHandler opens an event stream connection with the dashboard
|
||||
// so that it is notified everytime a new capture arrives
|
||||
func NewDashboardConnHandler(list *CaptureList) http.HandlerFunc {
|
||||
func NewDashboardConnHandler(srv *CaptureService) http.HandlerFunc {
|
||||
return func(rw http.ResponseWriter, req *http.Request) {
|
||||
if _, ok := rw.(http.Flusher); !ok {
|
||||
fmt.Printf("streaming not supported at %s\n", req.URL)
|
||||
|
@ -62,12 +62,12 @@ func NewDashboardConnHandler(list *CaptureList) http.HandlerFunc {
|
|||
rw.Header().Set("Content-Type", "text/event-stream")
|
||||
rw.Header().Set("Cache-Control", "no-cache")
|
||||
for {
|
||||
jsn, _ := json.Marshal(list.ItemsAsMetadata())
|
||||
jsn, _ := json.Marshal(srv.DashboardItems())
|
||||
fmt.Fprintf(rw, "event: captures\ndata: %s\n\n", jsn)
|
||||
rw.(http.Flusher).Flush()
|
||||
|
||||
select {
|
||||
case <-list.Updated():
|
||||
case <-srv.Updated():
|
||||
case <-req.Context().Done():
|
||||
return
|
||||
}
|
||||
|
@ -76,9 +76,9 @@ func NewDashboardConnHandler(list *CaptureList) http.HandlerFunc {
|
|||
}
|
||||
|
||||
// NewDashboardClearHandler clears all the captures
|
||||
func NewDashboardClearHandler(list *CaptureList) http.HandlerFunc {
|
||||
func NewDashboardClearHandler(srv *CaptureService) http.HandlerFunc {
|
||||
return func(rw http.ResponseWriter, req *http.Request) {
|
||||
list.RemoveAll()
|
||||
srv.RemoveAll()
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
@ -99,10 +99,10 @@ func NewDashboardHTMLHandler(config Config) http.HandlerFunc {
|
|||
}
|
||||
|
||||
// NewDashboardRetryHandler retries a request
|
||||
func NewDashboardRetryHandler(list *CaptureList, next http.HandlerFunc) http.HandlerFunc {
|
||||
func NewDashboardRetryHandler(srv *CaptureService, next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(rw http.ResponseWriter, req *http.Request) {
|
||||
id := req.URL.Path[strings.LastIndex(req.URL.Path, "/")+1:]
|
||||
capture := list.Find(id)
|
||||
capture := srv.Find(id)
|
||||
var reqBody []byte
|
||||
capture.Req.Body, reqBody = drain(capture.Req.Body)
|
||||
r, _ := http.NewRequest(capture.Req.Method, capture.Req.URL.String(), bytes.NewReader(reqBody))
|
||||
|
@ -112,17 +112,17 @@ func NewDashboardRetryHandler(list *CaptureList, next http.HandlerFunc) http.Han
|
|||
}
|
||||
|
||||
// NewDashboardInfoHandler returns the full capture info
|
||||
func NewDashboardInfoHandler(list *CaptureList) http.HandlerFunc {
|
||||
func NewDashboardInfoHandler(srv *CaptureService) http.HandlerFunc {
|
||||
return func(rw http.ResponseWriter, req *http.Request) {
|
||||
id := req.URL.Path[strings.LastIndex(req.URL.Path, "/")+1:]
|
||||
capture := list.Find(id)
|
||||
capture := srv.Find(id)
|
||||
rw.Header().Add("Content-Type", "application/json")
|
||||
json.NewEncoder(rw).Encode(dump(capture))
|
||||
}
|
||||
}
|
||||
|
||||
// NewPlugin loads plugin files in the current directory. They are loaded sorted by filename.
|
||||
func NewPlugin(next http.HandlerFunc) http.HandlerFunc {
|
||||
// NewPluginHandler loads plugin files in the current directory. They are loaded sorted by filename.
|
||||
func NewPluginHandler(next http.HandlerFunc) http.HandlerFunc {
|
||||
ex, err := os.Executable()
|
||||
if err != nil {
|
||||
fmt.Println("error: could not get executable:", err)
|
||||
|
@ -161,8 +161,8 @@ func NewPlugin(next http.HandlerFunc) http.HandlerFunc {
|
|||
return next
|
||||
}
|
||||
|
||||
// NewRecorder saves all the traffic data
|
||||
func NewRecorder(list *CaptureList, next http.HandlerFunc) http.HandlerFunc {
|
||||
// NewRecorderHandler saves all the traffic data
|
||||
func NewRecorderHandler(srv *CaptureService, next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(rw http.ResponseWriter, req *http.Request) {
|
||||
|
||||
// save req body for later
|
||||
|
@ -187,7 +187,7 @@ func NewRecorder(list *CaptureList, next http.HandlerFunc) http.HandlerFunc {
|
|||
// record req and res
|
||||
req.Body = ioutil.NopCloser(bytes.NewReader(reqBody))
|
||||
res := rec.Result()
|
||||
list.Insert(Capture{Req: req, Res: res, Elapsed: elapsed})
|
||||
srv.Insert(Capture{Req: req, Res: res, Elapsed: elapsed})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue