diff --git a/static/stats.js b/static/stats.js index 6ff432c..271decb 100644 --- a/static/stats.js +++ b/static/stats.js @@ -25,7 +25,7 @@ async function listStats() { let l; try { - let r = await fetch('/stats.json'); + let r = await fetch('/galene-api/.stats'); if(!r.ok) throw new Error(`${r.status} ${r.statusText}`); l = await r.json(); diff --git a/webserver/api.go b/webserver/api.go new file mode 100644 index 0000000..482a281 --- /dev/null +++ b/webserver/api.go @@ -0,0 +1,57 @@ +package webserver + +import ( + "encoding/json" + "log" + "net/http" + "strings" + + "github.com/jech/galene/stats" +) + +func apiHandler(w http.ResponseWriter, r *http.Request) { + username, password, ok := r.BasicAuth() + if !ok { + failAuthentication(w, "galene-api") + return + } + + if ok, err := adminMatch(username, password); !ok { + if err != nil { + log.Printf("Administrator password: %v", err) + } + failAuthentication(w, "galene-api") + return + } + + if !strings.HasPrefix(r.URL.Path, "/galene-api/") { + http.NotFound(w, r) + return + } + + first, kind, rest := splitPath(r.URL.Path[len("/galene/api"):]) + if first != "" { + http.NotFound(w, r) + return + } + + if kind == ".stats" && rest == "" { + if r.Method != "HEAD" && r.Method != "GET" { + http.Error(w, "method not allowed", + http.StatusMethodNotAllowed) + } + w.Header().Set("content-type", "application/json") + w.Header().Set("cache-control", "no-cache") + if r.Method == "HEAD" { + return + } + + ss := stats.GetGroups() + e := json.NewEncoder(w) + e.Encode(ss) + return + } + + http.NotFound(w, r) + return +} diff --git a/webserver/webserver.go b/webserver/webserver.go index 672b782..38f5539 100644 --- a/webserver/webserver.go +++ b/webserver/webserver.go @@ -26,7 +26,6 @@ import ( "github.com/jech/galene/diskwriter" "github.com/jech/galene/group" "github.com/jech/galene/rtpconn" - "github.com/jech/galene/stats" ) var server atomic.Value @@ -46,10 +45,7 @@ func Serve(address string, dataDir string) error { http.HandleFunc("/recordings/", recordingsHandler) http.HandleFunc("/ws", wsHandler) http.HandleFunc("/public-groups.json", publicHandler) - http.HandleFunc("/stats.json", - func(w http.ResponseWriter, r *http.Request) { - statsHandler(w, r, dataDir) - }) + http.HandleFunc("/galene-api/", apiHandler) s := &http.Server{ Addr: address, @@ -493,35 +489,6 @@ func failAuthentication(w http.ResponseWriter, realm string) { http.Error(w, "Haha!", http.StatusUnauthorized) } -func statsHandler(w http.ResponseWriter, r *http.Request, dataDir string) { - username, password, ok := r.BasicAuth() - if !ok { - failAuthentication(w, "stats") - return - } - - if ok, err := adminMatch(username, password); !ok { - if err != nil { - log.Printf("Administrator password: %v", err) - } - failAuthentication(w, "stats") - return - } - - w.Header().Set("content-type", "application/json") - w.Header().Set("cache-control", "no-cache") - if r.Method == "HEAD" { - return - } - - ss := stats.GetGroups() - e := json.NewEncoder(w) - err := e.Encode(ss) - if err != nil { - log.Printf("stats.json: %v", err) - } -} - var wsUpgrader = websocket.Upgrader{ HandshakeTimeout: 30 * time.Second, }