package main import ( "encoding/json" "io" "log" "net/http" ) func runServer() { cfg, err := LoadConfig() if err != nil { log.Fatal(err) } metrics := NewMetrics(nil) proxy := NewProxy(cfg, metrics) mux := http.NewServeMux() mux.HandleFunc("GET /", func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/plain; charset=utf-8") _, _ = w.Write([]byte("Mattermost Push Proxy Router\n")) }) mux.HandleFunc("GET /version", func(w http.ResponseWriter, _ *http.Request) { writeJSON(w, map[string]string{"version": version}) }) mux.HandleFunc("GET /health", handleHealth) mux.Handle("GET /metrics", metrics.Handler()) mux.HandleFunc("POST /api/v1/send_push", func(w http.ResponseWriter, r *http.Request) { handleRoute(w, r, proxy, cfg, "/api/v1/send_push") }) mux.HandleFunc("POST /api/v1/ack", func(w http.ResponseWriter, r *http.Request) { handleRoute(w, r, proxy, cfg, "/api/v1/ack") }) addr := ":" + cfg.Port log.Printf("Push proxy router listening on %s", addr) for _, route := range cfg.Routes { log.Printf("Route %v -> %s", route.Prefixes, route.URL) } if err := http.ListenAndServe(addr, mux); err != nil { log.Fatal(err) } } func handleRoute(w http.ResponseWriter, r *http.Request, proxy *Proxy, cfg Config, path string) { body, err := io.ReadAll(r.Body) if err != nil { proxy.metrics.incRoutingError("read_body") writePushError(w, "failed to read request body") return } platform, err := extractPlatform(body) if err != nil { proxy.metrics.incRoutingError(routingErrorReason(err)) writePushError(w, err.Error()) return } backend, ok := cfg.BackendForPlatform(platform) if !ok { proxy.metrics.incRoutingError("unknown_platform") writePushError(w, "no backend configured for platform="+platform) return } proxy.metrics.incRequest(routePathLabel(path), platform) log.Printf("route platform=%s path=%s backend=%s", platform, path, backend) proxy.Forward(w, r, backend, path, body, platform) } func handleHealth(w http.ResponseWriter, _ *http.Request) { writeJSON(w, map[string]string{"status": "ok"}) } func writeJSON(w http.ResponseWriter, v any) { w.Header().Set("Content-Type", "application/json") enc := json.NewEncoder(w) enc.SetEscapeHTML(false) _ = enc.Encode(v) }