router.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package router
  2. import (
  3. "fmt"
  4. "net/http"
  5. "strings"
  6. "time"
  7. "github.com/CAFxX/httpcompression"
  8. "github.com/go-chi/chi/v5"
  9. chiMW "github.com/go-chi/chi/v5/middleware"
  10. log "github.com/sirupsen/logrus"
  11. "golang.org/x/net/http2"
  12. "golang.org/x/net/http2/h2c"
  13. "github.com/owncast/owncast/activitypub"
  14. aphandlers "github.com/owncast/owncast/activitypub/controllers"
  15. "github.com/owncast/owncast/config"
  16. "github.com/owncast/owncast/core/chat"
  17. "github.com/owncast/owncast/core/data"
  18. "github.com/owncast/owncast/webserver/handlers"
  19. "github.com/owncast/owncast/webserver/router/middleware"
  20. )
  21. // Start starts the router for the http, ws, and rtmp.
  22. func Start(enableVerboseLogging bool) error {
  23. // @behlers New Router
  24. r := chi.NewRouter()
  25. // Middlewares
  26. if enableVerboseLogging {
  27. r.Use(chiMW.RequestLogger(&chiMW.DefaultLogFormatter{Logger: log.StandardLogger(), NoColor: true}))
  28. }
  29. r.Use(chiMW.Recoverer)
  30. addStaticFileEndpoints(r)
  31. // websocket
  32. r.HandleFunc("/ws", chat.HandleClientConnection)
  33. // serve files
  34. fs := http.FileServer(http.Dir(config.PublicFilesPath))
  35. r.Handle("/public/*", http.StripPrefix("/public/", fs))
  36. // Return HLS video
  37. r.HandleFunc("/hls/*", handlers.HandleHLSRequest)
  38. // The admin web app.
  39. r.HandleFunc("/admin/*", middleware.RequireAdminAuth(handlers.IndexHandler))
  40. // Single ActivityPub Actor
  41. r.HandleFunc("/federation/user/*", middleware.RequireActivityPubOrRedirect(aphandlers.ActorHandler))
  42. // Single AP object
  43. r.HandleFunc("/federation/*", middleware.RequireActivityPubOrRedirect(aphandlers.ObjectHandler))
  44. // The primary web app.
  45. r.HandleFunc("/*", handlers.IndexHandler)
  46. // mount the api
  47. r.Mount("/api/", handlers.New().Handler())
  48. // ActivityPub has its own router
  49. activitypub.Start(data.GetDatastore())
  50. // Create a custom mux handler to intercept the /debug/vars endpoint.
  51. // This is a hack because Prometheus enables this endpoint by default
  52. // due to its use of expvar and we do not want this exposed.
  53. h2s := &http2.Server{}
  54. http2Handler := h2c.NewHandler(r, h2s)
  55. m := http.NewServeMux()
  56. m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  57. if r.URL.Path == "/debug/vars" {
  58. w.WriteHeader(http.StatusNotFound)
  59. return
  60. } else if r.URL.Path == "/embed/chat/" || r.URL.Path == "/embed/chat" {
  61. // Redirect /embed/chat
  62. http.Redirect(w, r, "/embed/chat/readonly", http.StatusTemporaryRedirect)
  63. } else {
  64. http2Handler.ServeHTTP(w, r)
  65. }
  66. })
  67. port := config.WebServerPort
  68. ip := config.WebServerIP
  69. compress, _ := httpcompression.DefaultAdapter() // Use the default configuration
  70. server := &http.Server{
  71. Addr: fmt.Sprintf("%s:%d", ip, port),
  72. ReadHeaderTimeout: 4 * time.Second,
  73. Handler: compress(m),
  74. }
  75. if ip != "0.0.0.0" {
  76. log.Infof("Web server is listening at %s:%d.", ip, port)
  77. } else {
  78. log.Infof("Web server is listening on port %d.", port)
  79. }
  80. log.Infoln("Configure this server by visiting /admin.")
  81. return server.ListenAndServe()
  82. }
  83. func addStaticFileEndpoints(r chi.Router) {
  84. // Images
  85. r.HandleFunc("/thumbnail.jpg", handlers.GetThumbnail)
  86. r.HandleFunc("/preview.gif", handlers.GetPreview)
  87. r.HandleFunc("/logo", handlers.GetLogo)
  88. // return a logo that's compatible with external social networks
  89. r.HandleFunc("/logo/external", handlers.GetCompatibleLogo)
  90. // Custom Javascript
  91. r.HandleFunc("/customjavascript", handlers.ServeCustomJavascript)
  92. // robots.txt
  93. r.HandleFunc("/robots.txt", handlers.GetRobotsDotTxt)
  94. // Return a single emoji image.
  95. emojiDir := config.EmojiDir
  96. if !strings.HasSuffix(emojiDir, "*") {
  97. emojiDir += "*"
  98. }
  99. r.HandleFunc(emojiDir, handlers.GetCustomEmojiImage)
  100. // WebFinger
  101. r.HandleFunc("/.well-known/webfinger", aphandlers.WebfingerHandler)
  102. // Host Metadata
  103. r.HandleFunc("/.well-known/host-meta", aphandlers.HostMetaController)
  104. // Nodeinfo v1
  105. r.HandleFunc("/.well-known/nodeinfo", aphandlers.NodeInfoController)
  106. // x-nodeinfo v2
  107. r.HandleFunc("/.well-known/x-nodeinfo2", aphandlers.XNodeInfo2Controller)
  108. // Nodeinfo v2
  109. r.HandleFunc("/nodeinfo/2.0", aphandlers.NodeInfoV2Controller)
  110. // Instance details
  111. r.HandleFunc("/api/v1/instance", aphandlers.InstanceV1Controller)
  112. }