capture/capture.go

143 lines
2.9 KiB
Go

package main
import (
"net/http"
"strconv"
"sync"
"time"
)
var captureID int
// CaptureService handles captures.
type CaptureService struct {
items []Capture
mu sync.RWMutex
maxItems int
updated chan struct{} // signals any change in "items".
}
// Capture is our traffic data.
type Capture struct {
ID int
Req Req
Res Res
// Elapsed time of the request, in milliseconds.
Elapsed time.Duration
}
type Req struct {
Proto string `json:"proto"`
Method string `json:"method"`
Url string `json:"url"`
Path string `json:"path"`
Query string `json:"query"`
Header http.Header `json:"header"`
Body []byte `json:"body"`
}
type Res struct {
Proto string
Status string
Code int
Header http.Header
Body []byte
}
// CaptureInfo is the capture info shown in the dashboard.
type CaptureInfo struct {
Request string `json:"request"`
Response string `json:"response"`
Curl string `json:"curl"`
}
// DashboardItem is an item in the dashboard's list.
type DashboardItem struct {
ID int `json:"id"`
Path string `json:"path"`
Query string `json:"query"`
Method string `json:"method"`
Status int `json:"status"`
Elapsed time.Duration `json:"elapsed"`
}
// NewCaptureService creates a new service of captures.
func NewCaptureService(maxItems int) *CaptureService {
return &CaptureService{
maxItems: maxItems,
updated: make(chan struct{}),
}
}
// Insert inserts a new capture.
func (s *CaptureService) Insert(capture Capture) {
s.mu.Lock()
defer s.mu.Unlock()
captureID++
capture.ID = captureID
s.items = append(s.items, capture)
if len(s.items) > s.maxItems {
s.items = s.items[1:]
}
s.signalsUpdate()
}
// Find finds a capture by its ID.
func (s *CaptureService) Find(captureID string) *Capture {
s.mu.RLock()
defer s.mu.RUnlock()
idInt, _ := strconv.Atoi(captureID)
for _, c := range s.items {
if c.ID == idInt {
return &c
}
}
return nil
}
// RemoveAll removes all the captures.
func (s *CaptureService) RemoveAll() {
s.mu.Lock()
defer s.mu.Unlock()
s.items = nil
s.signalsUpdate()
}
// DashboardItems returns the dashboard's list of items.
func (s *CaptureService) DashboardItems() []DashboardItem {
s.mu.RLock()
defer s.mu.RUnlock()
metadatas := make([]DashboardItem, len(s.items))
for i, capture := range s.items {
metadatas[i] = DashboardItem{
ID: capture.ID,
Path: capture.Req.Path,
Query: capture.Req.Query,
Method: capture.Req.Method,
Status: capture.Res.Code,
Elapsed: capture.Elapsed,
}
}
return metadatas
}
// signalsUpdate fires an update signal.
func (s *CaptureService) signalsUpdate() {
close(s.updated)
s.updated = make(chan struct{})
}
// 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
}