|
|
|
package bg
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"sync/atomic"
|
|
|
|
|
|
|
|
"github.com/jordanorelli/dws/events"
|
|
|
|
)
|
|
|
|
|
|
|
|
type server struct {
|
|
|
|
port int
|
|
|
|
fs http.Handler
|
|
|
|
out chan events.BackgroundEvent
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *server) listen() {
|
|
|
|
addr := fmt.Sprintf("0.0.0.0:%d", s.port)
|
|
|
|
log.Printf("server listening on addr: %s\n", addr)
|
|
|
|
h := &eventEmittingHandler{
|
|
|
|
wrapped: s,
|
|
|
|
out: s.out,
|
|
|
|
}
|
|
|
|
if err := http.ListenAndServe(addr, h); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *server) setRoot(path string) {
|
|
|
|
log.Printf("server setting root to %s\n", path)
|
|
|
|
s.fs = http.FileServer(http.Dir(path))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if s.fs == nil {
|
|
|
|
writeNotInitializedResponse(w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
s.fs.ServeHTTP(w, r)
|
|
|
|
}
|
|
|
|
|
|
|
|
func writeNotInitializedResponse(w http.ResponseWriter) {
|
|
|
|
w.WriteHeader(500)
|
|
|
|
fmt.Fprintln(w, "no root directory selected")
|
|
|
|
}
|
|
|
|
|
|
|
|
// trackginWriter is an http.ResponseWriter that tracks the number of bytes
|
|
|
|
// sent and the status sent
|
|
|
|
type trackingWriter struct {
|
|
|
|
http.ResponseWriter
|
|
|
|
status int // last http status written
|
|
|
|
wrote int // total number of bytes written
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *trackingWriter) WriteHeader(status int) {
|
|
|
|
t.ResponseWriter.WriteHeader(status)
|
|
|
|
t.status = status
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *trackingWriter) Write(b []byte) (int, error) {
|
|
|
|
n, err := t.ResponseWriter.Write(b)
|
|
|
|
if t.status == 0 {
|
|
|
|
t.status = 200
|
|
|
|
}
|
|
|
|
t.wrote += n
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// eventEmittingHandler is an http.Handler that emits events on an event
|
|
|
|
// channel to report on requests and responses.
|
|
|
|
type eventEmittingHandler struct {
|
|
|
|
wrapped http.Handler
|
|
|
|
out chan events.BackgroundEvent
|
|
|
|
count uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *eventEmittingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
id := int(h.nextCount())
|
|
|
|
h.out <- events.BeginRequestEvent{
|
|
|
|
Seq: id,
|
|
|
|
Path: r.URL.Path,
|
|
|
|
}
|
|
|
|
tw := &trackingWriter{ResponseWriter: w}
|
|
|
|
h.wrapped.ServeHTTP(tw, r)
|
|
|
|
h.out <- events.EndRequestEvent{
|
|
|
|
Seq: id,
|
|
|
|
Status: tw.status,
|
|
|
|
Bytes: tw.wrote,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *eventEmittingHandler) nextCount() uint32 {
|
|
|
|
return atomic.AddUint32(&h.count, 1)
|
|
|
|
}
|