chore: reverting the current implementation of http response caching

This commit is contained in:
Gabe Kangas 2023-12-19 18:20:46 -08:00
parent df7eb5e38d
commit bb7de347c5
No known key found for this signature in database
GPG key ID: 4345B2060657F330
8 changed files with 34 additions and 202 deletions

View file

@ -30,8 +30,4 @@ var (
// PublicFilesPath is the optional directory for hosting public files.
PublicFilesPath = filepath.Join(DataDirectory, "public")
// DisableResponseCaching will disable caching of API and resource
// responses. Disable this feature to turn off the optimizations.
DisableResponseCaching = false
)

View file

@ -6,7 +6,6 @@ import (
"path/filepath"
"strconv"
"strings"
"time"
"github.com/owncast/owncast/config"
"github.com/owncast/owncast/core"
@ -14,24 +13,8 @@ import (
"github.com/owncast/owncast/models"
"github.com/owncast/owncast/router/middleware"
"github.com/owncast/owncast/utils"
log "github.com/sirupsen/logrus"
cache "github.com/victorspringer/http-cache"
"github.com/victorspringer/http-cache/adapter/memory"
)
var (
hlsCacheAdapter *cache.Adapter
hlsResponseCache *cache.Client
)
type FileServerHandler struct {
HLSPath string
}
func (fsh *FileServerHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
http.ServeFile(rw, r, fsh.HLSPath)
}
// HandleHLSRequest will manage all requests to HLS content.
func HandleHLSRequest(w http.ResponseWriter, r *http.Request) {
// Sanity check to limit requests to HLS file types.
@ -40,32 +23,6 @@ func HandleHLSRequest(w http.ResponseWriter, r *http.Request) {
return
}
if hlsCacheAdapter == nil {
ca, err := memory.NewAdapter(
memory.AdapterWithAlgorithm(memory.LRU),
memory.AdapterWithCapacity(50),
memory.AdapterWithStorageCapacity(104_857_600),
)
hlsCacheAdapter = &ca
if err != nil {
log.Warn("unable to create web cache", err)
}
}
// Since HLS segments cannot be changed once they're rendered, we can cache
// individual segments for a long time.
if hlsResponseCache == nil {
rc, err := cache.NewClient(
cache.ClientWithAdapter(*hlsCacheAdapter),
cache.ClientWithTTL(30*time.Second),
cache.ClientWithExpiresHeader(),
)
hlsResponseCache = rc
if err != nil {
log.Warn("unable to create web cache client", err)
}
}
requestedPath := r.URL.Path
relativePath := strings.Replace(requestedPath, "/hls/", "", 1)
fullPath := filepath.Join(config.HLSStoragePath, relativePath)
@ -91,10 +48,6 @@ func HandleHLSRequest(w http.ResponseWriter, r *http.Request) {
} else {
cacheTime := utils.GetCacheDurationSecondsForPath(relativePath)
w.Header().Set("Cache-Control", "public, max-age="+strconv.Itoa(cacheTime))
fileServer := &FileServerHandler{HLSPath: fullPath}
hlsResponseCache.Middleware(fileServer).ServeHTTP(w, r)
return
}
middleware.EnableCors(w)

View file

@ -7,7 +7,6 @@ import (
"net/url"
"path/filepath"
"strings"
"time"
"github.com/owncast/owncast/config"
"github.com/owncast/owncast/core"
@ -17,45 +16,12 @@ import (
"github.com/owncast/owncast/static"
"github.com/owncast/owncast/utils"
log "github.com/sirupsen/logrus"
cache "github.com/victorspringer/http-cache"
"github.com/victorspringer/http-cache/adapter/memory"
)
var (
indexCacheAdapter *cache.Adapter
indexBotSearchCache *cache.Client
)
// IndexHandler handles the default index route.
func IndexHandler(w http.ResponseWriter, r *http.Request) {
middleware.EnableCors(w)
if indexCacheAdapter == nil {
ca, err := memory.NewAdapter(
memory.AdapterWithAlgorithm(memory.LFU),
memory.AdapterWithCapacity(50),
memory.AdapterWithStorageCapacity(104_857_600),
)
indexCacheAdapter = &ca
if err != nil {
log.Warn("unable to create web cache", err)
}
}
if indexBotSearchCache == nil {
rc, err := cache.NewClient(
cache.ClientWithAdapter(*indexCacheAdapter),
cache.ClientWithTTL(30*time.Second),
cache.ClientWithExpiresHeader(),
cache.ClientWithRefreshKey("bot-search-page"),
cache.ClientWithExpiresHeader(),
)
indexBotSearchCache = rc
if err != nil {
log.Warn("unable to create web cache client", err)
}
}
isIndexRequest := r.URL.Path == "/" || filepath.Base(r.URL.Path) == "index.html" || filepath.Base(r.URL.Path) == ""
if utils.IsUserAgentAPlayer(r.UserAgent()) && isIndexRequest {
@ -66,7 +32,7 @@ func IndexHandler(w http.ResponseWriter, r *http.Request) {
// For search engine bots and social scrapers return a special
// server-rendered page.
if utils.IsUserAgentABot(r.UserAgent()) && isIndexRequest {
indexBotSearchCache.Middleware(http.HandlerFunc(handleScraperMetadataPage))
handleScraperMetadataPage(w, r)
return
}

5
go.mod
View file

@ -31,9 +31,9 @@ require (
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/crypto v0.15.0 // indirect
golang.org/x/net v0.18.0
golang.org/x/sys v0.15.0 // indirect
golang.org/x/sys v0.14.0 // indirect
)
require github.com/prometheus/client_golang v1.17.0
@ -75,7 +75,6 @@ require (
github.com/CAFxX/httpcompression v0.0.9
github.com/andybalholm/cascadia v1.3.2
github.com/mssola/user_agent v0.6.0
github.com/victorspringer/http-cache v0.0.0-20231006141456-6446fe59efba
github.com/yuin/goldmark-emoji v1.0.2
gopkg.in/evanphx/json-patch.v5 v5.7.0
mvdan.cc/xurls v1.1.0

14
go.sum
View file

@ -134,8 +134,6 @@ github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9f
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/valyala/gozstd v1.20.1 h1:xPnnnvjmaDDitMFfDxmQ4vpx0+3CdTg2o3lALvXTU/g=
github.com/valyala/gozstd v1.20.1/go.mod h1:y5Ew47GLlP37EkTB+B4s7r6A5rdaeB7ftbl9zoYiIPQ=
github.com/victorspringer/http-cache v0.0.0-20231006141456-6446fe59efba h1:+oqDKQIOdkkvro1psUKtI4oH9WBeKkGY2S8h9/lo288=
github.com/victorspringer/http-cache v0.0.0-20231006141456-6446fe59efba/go.mod h1:D1AD6nlXv7HkIfTVd8ZWK1KQEiXYNy/LbLkx8H9tIQw=
github.com/yuin/goldmark v1.3.7/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68=
@ -149,8 +147,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
@ -184,15 +182,15 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=

27
main.go
View file

@ -17,18 +17,17 @@ import (
)
var (
dbFile = flag.String("database", "", "Path to the database file.")
logDirectory = flag.String("logdir", "", "Directory where logs will be written to")
backupDirectory = flag.String("backupdir", "", "Directory where backups will be written to")
enableDebugOptions = flag.Bool("enableDebugFeatures", false, "Enable additional debugging options.")
enableVerboseLogging = flag.Bool("enableVerboseLogging", false, "Enable additional logging.")
restoreDatabaseFile = flag.String("restoreDatabase", "", "Restore an Owncast database backup")
newAdminPassword = flag.String("adminpassword", "", "Set your admin password")
newStreamKey = flag.String("streamkey", "", "Set a temporary stream key for this session")
webServerPortOverride = flag.String("webserverport", "", "Force the web server to listen on a specific port")
webServerIPOverride = flag.String("webserverip", "", "Force web server to listen on this IP address")
rtmpPortOverride = flag.Int("rtmpport", 0, "Set listen port for the RTMP server")
disableResponseCaching = flag.Bool("disableResponseCaching", false, "Do not optimize performance by caching of web responses")
dbFile = flag.String("database", "", "Path to the database file.")
logDirectory = flag.String("logdir", "", "Directory where logs will be written to")
backupDirectory = flag.String("backupdir", "", "Directory where backups will be written to")
enableDebugOptions = flag.Bool("enableDebugFeatures", false, "Enable additional debugging options.")
enableVerboseLogging = flag.Bool("enableVerboseLogging", false, "Enable additional logging.")
restoreDatabaseFile = flag.String("restoreDatabase", "", "Restore an Owncast database backup")
newAdminPassword = flag.String("adminpassword", "", "Set your admin password")
newStreamKey = flag.String("streamkey", "", "Set a temporary stream key for this session")
webServerPortOverride = flag.String("webserverport", "", "Force the web server to listen on a specific port")
webServerIPOverride = flag.String("webserverip", "", "Force web server to listen on this IP address")
rtmpPortOverride = flag.Int("rtmpport", 0, "Set listen port for the RTMP server")
)
// nolint:cyclop
@ -43,10 +42,6 @@ func main() {
config.BackupDirectory = *backupDirectory
}
if *disableResponseCaching {
config.DisableResponseCaching = *disableResponseCaching
}
// Create the data directory if needed
if !utils.DoesFileExists("data") {
if err := os.Mkdir("./data", 0o700); err != nil {

View file

@ -24,45 +24,10 @@ import (
"github.com/owncast/owncast/router/middleware"
"github.com/owncast/owncast/utils"
"github.com/owncast/owncast/yp"
cache "github.com/victorspringer/http-cache"
"github.com/victorspringer/http-cache/adapter/memory"
)
// Start starts the router for the http, ws, and rtmp.
func Start() error {
// Setup a web response cache
enableCache := !config.DisableResponseCaching
responseCache, err := memory.NewAdapter(
memory.AdapterWithAlgorithm(memory.LRU),
memory.AdapterWithCapacity(50),
)
if err != nil {
log.Warn("unable to create web cache", err)
}
superShortCacheClient, err := cache.NewClient(
cache.ClientWithAdapter(responseCache),
cache.ClientWithTTL(3*time.Second),
)
if err != nil {
log.Warn("unable to create web cache client", err)
}
reasonableDurationCacheClient, err := cache.NewClient(
cache.ClientWithAdapter(responseCache),
cache.ClientWithTTL(8*time.Second),
)
if err != nil {
log.Warn("unable to create web cache client", err)
}
longerDurationCacheClient, err := cache.NewClient(
cache.ClientWithAdapter(responseCache),
cache.ClientWithTTL(3*time.Minute),
)
if err != nil {
log.Warn("unable to create web cache client", err)
}
// The primary web app.
http.HandleFunc("/", controllers.IndexHandler)
@ -70,79 +35,41 @@ func Start() error {
http.HandleFunc("/admin/", middleware.RequireAdminAuth(controllers.IndexHandler))
// Images
http.HandleFunc("/thumbnail.jpg", func(rw http.ResponseWriter, r *http.Request) {
superShortCacheClient.Middleware(http.HandlerFunc(controllers.GetThumbnail)).ServeHTTP(rw, r)
})
http.HandleFunc("/preview.gif", func(rw http.ResponseWriter, r *http.Request) {
superShortCacheClient.Middleware(http.HandlerFunc(controllers.GetPreview)).ServeHTTP(rw, r)
})
http.HandleFunc("/logo", func(rw http.ResponseWriter, r *http.Request) {
longerDurationCacheClient.Middleware(http.HandlerFunc(controllers.GetLogo)).ServeHTTP(rw, r)
})
http.HandleFunc("/thumbnail.jpg", controllers.GetThumbnail)
http.HandleFunc("/preview.gif", controllers.GetPreview)
http.HandleFunc("/logo", controllers.GetLogo)
// Custom Javascript
http.HandleFunc("/customjavascript", func(rw http.ResponseWriter, r *http.Request) {
longerDurationCacheClient.Middleware(http.HandlerFunc(controllers.ServeCustomJavascript)).ServeHTTP(rw, r)
})
http.HandleFunc("/customjavascript", controllers.ServeCustomJavascript)
// Return a single emoji image.
http.HandleFunc(config.EmojiDir, func(rw http.ResponseWriter, r *http.Request) {
longerDurationCacheClient.Middleware(http.HandlerFunc(controllers.GetCustomEmojiImage)).ServeHTTP(rw, r)
})
http.HandleFunc(config.EmojiDir, controllers.GetCustomEmojiImage)
// return the logo
// return a logo that's compatible with external social networks
http.HandleFunc("/logo/external", func(rw http.ResponseWriter, r *http.Request) {
longerDurationCacheClient.Middleware(http.HandlerFunc(controllers.GetCompatibleLogo)).ServeHTTP(rw, r)
})
http.HandleFunc("/logo/external", controllers.GetCompatibleLogo)
// robots.txt
http.HandleFunc("/robots.txt", func(rw http.ResponseWriter, r *http.Request) {
longerDurationCacheClient.Middleware(http.HandlerFunc(controllers.GetRobotsDotTxt)).ServeHTTP(rw, r)
})
http.HandleFunc("/robots.txt", controllers.GetRobotsDotTxt)
// status of the system
if enableCache {
http.HandleFunc("/api/status", func(rw http.ResponseWriter, r *http.Request) {
superShortCacheClient.Middleware(http.HandlerFunc(controllers.GetStatus)).ServeHTTP(rw, r)
})
} else {
http.HandleFunc("/api/status", controllers.GetStatus)
}
http.HandleFunc("/api/status", controllers.GetStatus)
// custom emoji supported in the chat
http.HandleFunc("/api/emoji", func(rw http.ResponseWriter, r *http.Request) {
reasonableDurationCacheClient.Middleware(http.HandlerFunc(controllers.GetCustomEmojiList)).ServeHTTP(rw, r)
})
http.HandleFunc("/api/emoji", controllers.GetCustomEmojiList)
// chat rest api
if enableCache {
http.HandleFunc("/api/chat", func(rw http.ResponseWriter, r *http.Request) {
superShortCacheClient.Middleware(middleware.RequireUserAccessToken(controllers.GetChatMessages))
})
} else {
http.HandleFunc("/api/chat", middleware.RequireUserAccessToken(controllers.GetChatMessages))
}
http.HandleFunc("/api/chat", middleware.RequireUserAccessToken(controllers.GetChatMessages))
// web config api
if enableCache {
http.HandleFunc("/api/config", func(rw http.ResponseWriter, r *http.Request) {
superShortCacheClient.Middleware(http.HandlerFunc(controllers.GetWebConfig)).ServeHTTP(rw, r)
})
} else {
http.HandleFunc("/api/config", controllers.GetWebConfig)
}
http.HandleFunc("/api/config", controllers.GetWebConfig)
// return the YP protocol data
http.HandleFunc("/api/yp", yp.GetYPResponse)
// list of all social platforms
http.HandleFunc("/api/socialplatforms", func(rw http.ResponseWriter, r *http.Request) {
reasonableDurationCacheClient.Middleware(http.HandlerFunc(controllers.GetAllSocialPlatforms)).ServeHTTP(rw, r)
})
http.HandleFunc("/api/socialplatforms", controllers.GetAllSocialPlatforms)
// return the list of video variants available
http.HandleFunc("/api/video/variants", controllers.GetVideoStreamOutputVariants)
@ -157,9 +84,7 @@ func Start() error {
http.HandleFunc("/api/remotefollow", controllers.RemoteFollow)
// return followers
http.HandleFunc("/api/followers", func(rw http.ResponseWriter, r *http.Request) {
reasonableDurationCacheClient.Middleware(middleware.HandlePagination(controllers.GetFollowers)).ServeHTTP(rw, r)
})
http.HandleFunc("/api/followers", middleware.HandlePagination(controllers.GetFollowers))
// save client video playback metrics
http.HandleFunc("/api/metrics/playback", controllers.ReportPlaybackMetrics)

View file

@ -43,7 +43,7 @@ function start_owncast() {
go build -o owncast main.go
echo "Running owncast..."
./owncast -disableResponseCaching -database "$TEMP_DB" &
./owncast -database "$TEMP_DB" &
SERVER_PID=$!
popd >/dev/null