Send config via sse

This commit is contained in:
Fabricio 2021-04-06 07:13:58 -03:00
parent 06eb4564f1
commit cad33f7d09
3 changed files with 40 additions and 34 deletions

View File

@ -344,8 +344,8 @@
</div>
<div class="welcome" v-show="items.length == 0">
<p>Waiting for requests on http://localhost:{{{.ProxyPort}}}/<br>
<span>Proxying {{{.TargetURL}}}</span>
<p>Waiting for requests on http://localhost:{{proxyPort}}/<br>
<span>Proxying {{targetURL}}</span>
</p>
</div>
@ -357,13 +357,20 @@
data: {
items: [],
selectedItem: {},
proxyPort: '',
targetURL: '',
},
created() {
this.setupStream();
},
methods: {
setupStream() {
let es = new EventSource(window.location.href + 'conn/');
let es = new EventSource('/conn/');
es.addEventListener('config', event => {
const cfg = JSON.parse(event.data);
this.proxyPort = cfg.ProxyPort;
this.targetURL = cfg.TargetURL;
});
es.addEventListener('captures', event => {
this.items = JSON.parse(event.data).reverse();
});
@ -374,7 +381,7 @@
},
async show(item) {
this.selectedItem = { ...this.selectedItem, id: item.id, status: item.status };
let resp = await fetch(window.location.href + 'info/' + item.id);
let resp = await fetch('/info/' + item.id);
let data = await resp.json();
this.selectedItem = { ...this.selectedItem, ...data };
},
@ -385,7 +392,7 @@
},
async clearDashboard() {
this.selectedItem = {};
await fetch(window.location.href + 'clear/');
await fetch('/clear/');
},
canPrettifyBody(name) {
if (!this.selectedItem[name]) return false;
@ -409,7 +416,7 @@
document.body.removeChild(e);
},
async retry() {
await fetch(window.location.href + 'retry/' + this.selectedItem.id,
await fetch('/retry/' + this.selectedItem.id,
{ headers: { 'Cache-Control': 'no-cache' } });
this.show(this.items[0]);
},

51
main.go
View File

@ -6,7 +6,6 @@ import (
_ "embed"
"encoding/json"
"fmt"
"html/template"
"io"
"io/ioutil"
"net/http"
@ -26,7 +25,7 @@ import (
const StatusInternalProxyError = 999
//go:embed dashboard.html
var dashboardHTML string
var dashboardHTML []byte
func main() {
cfg := ReadConfig()
@ -45,10 +44,10 @@ func main() {
fmt.Println(http.ListenAndServe(":"+cfg.ProxyPort, hdr))
}
func NewDashboardHandler(h http.HandlerFunc, srv *CaptureService, config Config) http.Handler {
func NewDashboardHandler(h http.HandlerFunc, srv *CaptureService, cfg Config) http.Handler {
router := http.NewServeMux()
router.HandleFunc("/", NewDashboardHTMLHandler(config))
router.HandleFunc("/conn/", NewDashboardConnHandler(srv))
router.HandleFunc("/", NewDashboardHTMLHandler())
router.HandleFunc("/conn/", NewDashboardConnHandler(srv, cfg))
router.HandleFunc("/info/", NewDashboardInfoHandler(srv))
router.HandleFunc("/clear/", NewDashboardClearHandler(srv))
router.HandleFunc("/retry/", NewDashboardRetryHandler(srv, h))
@ -57,19 +56,26 @@ func NewDashboardHandler(h http.HandlerFunc, srv *CaptureService, config Config)
// NewDashboardConnHandler opens an event stream connection with the dashboard
// so that it is notified everytime a new capture arrives
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)
http.Error(rw, "streaming not supported", http.StatusInternalServerError)
func NewDashboardConnHandler(srv *CaptureService, cfg Config) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
if _, ok := w.(http.Flusher); !ok {
http.Error(w, "streaming not supported", http.StatusInternalServerError)
return
}
rw.Header().Set("Content-Type", "text/event-stream")
rw.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
// Send the config.
jsn, _ := json.Marshal(cfg)
fmt.Fprintf(w, "event: config\ndata: %s\n\n", jsn)
w.(http.Flusher).Flush()
// Send the captures.
for {
jsn, _ := json.Marshal(srv.DashboardItems())
fmt.Fprintf(rw, "event: captures\ndata: %s\n\n", jsn)
rw.(http.Flusher).Flush()
fmt.Fprintf(w, "event: captures\ndata: %s\n\n", jsn)
w.(http.Flusher).Flush()
select {
case <-srv.Updated():
@ -89,26 +95,19 @@ func NewDashboardClearHandler(srv *CaptureService) http.HandlerFunc {
}
// NewDashboardHTMLHandler returns the dashboard html page
func NewDashboardHTMLHandler(config Config) http.HandlerFunc {
return func(rw http.ResponseWriter, req *http.Request) {
func NewDashboardHTMLHandler() http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
// This redirect prevents accessing the dashboard page from paths other
// than the root path. This is important because the dashboard uses
// relative paths, so "/retry/" would become "/something/retry/".
if req.URL.Path != "/" {
http.Redirect(rw, req, "/", http.StatusTemporaryRedirect)
http.Redirect(w, req, "/", http.StatusTemporaryRedirect)
return
}
rw.Header().Add("Content-Type", "text/html")
t, err := template.New("dashboard template").Delims("{{{", "}}}").Parse(dashboardHTML)
if err != nil {
msg := fmt.Sprintf("could not parse dashboard html template: %v", err)
fmt.Println(msg)
http.Error(rw, msg, http.StatusInternalServerError)
return
}
t.Execute(rw, config)
w.Header().Add("Content-Type", "text/html")
w.Write(dashboardHTML)
}
}

View File

@ -91,7 +91,7 @@ func TestDashboardRedirect(t *testing.T) {
rec := httptest.NewRecorder()
// When.
NewDashboardHTMLHandler(Config{}).ServeHTTP(rec, req)
NewDashboardHTMLHandler().ServeHTTP(rec, req)
// Then.
if rec.Code != http.StatusTemporaryRedirect {
@ -102,7 +102,7 @@ func TestDashboardRedirect(t *testing.T) {
}
}
func ExampleDump() {
func Example_dump() {
c := &Capture{
Req: Req{
Proto: "HTTP/1.1",