feat(api): add server-side caching for requests that could benefit (#3463)
* feat(api): add server-side caching for requests that could benefit for them * fix(tests): do not cache responses while in tests * fix: remove commented out leftover code * chore(deps): update dependency html-webpack-plugin to v5.5.4 * Bundle embedded web app * fix: remove caching for web app assets under test * chore(tests): re-enable temporarily disabled test * chore(deps): update dependency typescript to v5.3.3 * Bundle embedded web app * chore(deps): update dependency npm to v10.2.5 * Bundle embedded web app --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Owncast <owncast@owncast.online>
This commit is contained in:
co-authored by
renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Owncast
parent
b6efe49086
commit
2217f0614a
@@ -30,4 +30,8 @@ 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
|
||||
)
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/core"
|
||||
@@ -13,8 +14,19 @@ 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"
|
||||
)
|
||||
|
||||
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.
|
||||
@@ -23,6 +35,26 @@ func HandleHLSRequest(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
responseCache, err := memory.NewAdapter(
|
||||
memory.AdapterWithAlgorithm(memory.LRU),
|
||||
memory.AdapterWithCapacity(20),
|
||||
memory.AdapterWithStorageCapacity(209_715_200),
|
||||
)
|
||||
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.
|
||||
longTermHLSSegmentCache, err := cache.NewClient(
|
||||
cache.ClientWithAdapter(responseCache),
|
||||
cache.ClientWithTTL(30*time.Second),
|
||||
cache.ClientWithExpiresHeader(),
|
||||
)
|
||||
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)
|
||||
@@ -48,6 +80,10 @@ 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}
|
||||
longTermHLSSegmentCache.Middleware(fileServer).ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.EnableCors(w)
|
||||
|
||||
@@ -69,6 +69,7 @@ require (
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/oschwald/maxminddb-golang v1.11.0 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/victorspringer/http-cache v0.0.0-20231006141456-6446fe59efba // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
@@ -138,6 +138,8 @@ 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=
|
||||
|
||||
@@ -28,6 +28,7 @@ var (
|
||||
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")
|
||||
)
|
||||
|
||||
// nolint:cyclop
|
||||
@@ -42,6 +43,10 @@ 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 {
|
||||
|
||||
+91
-10
@@ -24,52 +24,131 @@ 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.
|
||||
if enableCache {
|
||||
http.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
|
||||
longerDurationCacheClient.Middleware(http.HandlerFunc(controllers.IndexHandler)).ServeHTTP(rw, r)
|
||||
})
|
||||
} else {
|
||||
http.HandleFunc("/", controllers.IndexHandler)
|
||||
}
|
||||
|
||||
// The admin web app.
|
||||
http.HandleFunc("/admin/", middleware.RequireAdminAuth(controllers.IndexHandler))
|
||||
|
||||
// Images
|
||||
http.HandleFunc("/thumbnail.jpg", controllers.GetThumbnail)
|
||||
http.HandleFunc("/preview.gif", controllers.GetPreview)
|
||||
http.HandleFunc("/logo", controllers.GetLogo)
|
||||
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)
|
||||
})
|
||||
|
||||
// Custom Javascript
|
||||
http.HandleFunc("/customjavascript", controllers.ServeCustomJavascript)
|
||||
http.HandleFunc("/customjavascript", func(rw http.ResponseWriter, r *http.Request) {
|
||||
longerDurationCacheClient.Middleware(http.HandlerFunc(controllers.ServeCustomJavascript)).ServeHTTP(rw, r)
|
||||
})
|
||||
|
||||
// Return a single emoji image.
|
||||
http.HandleFunc(config.EmojiDir, controllers.GetCustomEmojiImage)
|
||||
http.HandleFunc(config.EmojiDir, func(rw http.ResponseWriter, r *http.Request) {
|
||||
longerDurationCacheClient.Middleware(http.HandlerFunc(controllers.GetCustomEmojiImage)).ServeHTTP(rw, r)
|
||||
})
|
||||
|
||||
// return the logo
|
||||
|
||||
// return a logo that's compatible with external social networks
|
||||
http.HandleFunc("/logo/external", controllers.GetCompatibleLogo)
|
||||
http.HandleFunc("/logo/external", func(rw http.ResponseWriter, r *http.Request) {
|
||||
longerDurationCacheClient.Middleware(http.HandlerFunc(controllers.GetCompatibleLogo)).ServeHTTP(rw, r)
|
||||
})
|
||||
|
||||
// robots.txt
|
||||
http.HandleFunc("/robots.txt", controllers.GetRobotsDotTxt)
|
||||
http.HandleFunc("/robots.txt", func(rw http.ResponseWriter, r *http.Request) {
|
||||
longerDurationCacheClient.Middleware(http.HandlerFunc(controllers.GetRobotsDotTxt)).ServeHTTP(rw, r)
|
||||
})
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// custom emoji supported in the chat
|
||||
http.HandleFunc("/api/emoji", controllers.GetCustomEmojiList)
|
||||
http.HandleFunc("/api/emoji", func(rw http.ResponseWriter, r *http.Request) {
|
||||
reasonableDurationCacheClient.Middleware(http.HandlerFunc(controllers.GetCustomEmojiList)).ServeHTTP(rw, r)
|
||||
})
|
||||
|
||||
// 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))
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// return the YP protocol data
|
||||
http.HandleFunc("/api/yp", yp.GetYPResponse)
|
||||
|
||||
// list of all social platforms
|
||||
http.HandleFunc("/api/socialplatforms", controllers.GetAllSocialPlatforms)
|
||||
http.HandleFunc("/api/socialplatforms", func(rw http.ResponseWriter, r *http.Request) {
|
||||
reasonableDurationCacheClient.Middleware(http.HandlerFunc(controllers.GetAllSocialPlatforms)).ServeHTTP(rw, r)
|
||||
})
|
||||
|
||||
// return the list of video variants available
|
||||
http.HandleFunc("/api/video/variants", controllers.GetVideoStreamOutputVariants)
|
||||
@@ -84,7 +163,9 @@ func Start() error {
|
||||
http.HandleFunc("/api/remotefollow", controllers.RemoteFollow)
|
||||
|
||||
// return followers
|
||||
http.HandleFunc("/api/followers", middleware.HandlePagination(controllers.GetFollowers))
|
||||
http.HandleFunc("/api/followers", func(rw http.ResponseWriter, r *http.Request) {
|
||||
reasonableDurationCacheClient.Middleware(middleware.HandlePagination(controllers.GetFollowers)).ServeHTTP(rw, r)
|
||||
})
|
||||
|
||||
// save client video playback metrics
|
||||
http.HandleFunc("/api/metrics/playback", controllers.ReportPlaybackMetrics)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
self.__SSG_MANIFEST=new Set,self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB();
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[5584],{15584:function(e,t,n){n.r(t);var r,a,s,o,i,l=n(67294);function _extends(){return(_extends=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e}).apply(this,arguments)}t.default=function(e){return l.createElement("svg",_extends({xmlns:"http://www.w3.org/2000/svg",width:500,height:500,viewBox:"0 0 132.292 132.292"},e),r||(r=l.createElement("linearGradient",{id:"like_svg__a",x1:432.851,x2:464.644,y1:49.977,y2:49.977,gradientUnits:"userSpaceOnUse"},l.createElement("stop",{offset:0,stopColor:"#2087e2"}),l.createElement("stop",{offset:1,stopColor:"#b63fff"}))),a||(a=l.createElement("path",{fill:"url(#like_svg__a)",d:"M438.672 34.08h20.151a5.82 5.82 45 0 1 5.82 5.821v20.151a5.82 5.82 135 0 1-5.82 5.821h-20.15a5.82 5.82 45 0 1-5.822-5.82V39.9a5.82 5.82 135 0 1 5.821-5.82z",transform:"matrix(4.1611 0 0 4.1611 -1801.14 -141.813)"})),s||(s=l.createElement("path",{fill:"#853dd0",d:"M106.243 25.198 110 33.435l5.378 24.12-20.557 29.696-28.676 20.66-35.66-24.468 49.536 48.849h28.048a24.221 24.221 0 0 0 24.222-24.222V44.165z",opacity:.75})),o||(o=l.createElement("path",{fill:"#8392ee",d:"M51.275 39.14s-36.386-7.356-17.999 25.83c13.869 25.032 29.59 23.091 29.59 23.091S47.512 65.822 51.275 39.14"})),i||(i=l.createElement("path",{fill:"none",stroke:"#fff",strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:7.865,d:"M674.216 70.254c-21.056-22.863-45.943 2.215-45.943 2.215s-24.888-25.078-45.943-2.216c-21.056 22.863 16.89 64.133 45.943 78.023 29.053-13.89 66.998-55.16 45.943-78.022",transform:"matrix(.95455 0 0 .95455 -533.57 -33.626)"})))}}}]);
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[7268],{97268:function(e,t,r){r.r(t);var a,n,s,o,l=r(67294);function _extends(){return(_extends=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var a in r)Object.prototype.hasOwnProperty.call(r,a)&&(e[a]=r[a])}return e}).apply(this,arguments)}t.default=function(e){return l.createElement("svg",_extends({xmlns:"http://www.w3.org/2000/svg",width:500,height:500,viewBox:"0 0 132.292 132.292"},e),a||(a=l.createElement("linearGradient",{id:"repost_svg__a",x1:432.851,x2:464.644,y1:49.977,y2:49.977,gradientUnits:"userSpaceOnUse"},l.createElement("stop",{offset:0,stopColor:"#2087e2"}),l.createElement("stop",{offset:1,stopColor:"#b63fff"}))),n||(n=l.createElement("path",{fill:"url(#repost_svg__a)",d:"M438.672 34.08h20.151a5.82 5.82 45 0 1 5.82 5.821v20.151a5.82 5.82 135 0 1-5.82 5.821h-20.15a5.82 5.82 45 0 1-5.822-5.82V39.9a5.82 5.82 135 0 1 5.821-5.82z",transform:"matrix(4.16112 0 0 4.1611 -1801.146 -141.813)"})),s||(s=l.createElement("path",{fill:"#7f40cf",d:"m103.028 50.073-.794 41.033-10.18 12.882-49.412 3.477 26.027 24.827h39.4c13.378 0 24.223-10.845 24.222-24.222V68.265l-9.86-12.31z",opacity:.75})),o||(o=l.createElement("g",{fill:"none",stroke:"#fff",strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:7.865},l.createElement("path",{d:"M741.453 94.965h-41.418a14.744 14.744 0 0 0-14.777 14.777v41.418m14.777 14.777h41.418c8.187 0 14.777-6.59 14.777-14.777v-41.418",transform:"translate(-696.642 -71.915)scale(1.05833)"}),l.createElement("path",{d:"m670.076 143.371 15.182 13.79 15.5-13.6",transform:"translate(-696.642 -71.915)scale(1.05833)"}),l.createElement("path",{d:"m670.076 143.371 15.182 13.79 15.5-13.6",transform:"rotate(180 414.466 105.278)scale(1.05833)"}))))}}}]);
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[9069],{49069:function(e,t,r){r.r(t);var a,n,o,l,s=r(67294);function _extends(){return(_extends=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var a in r)Object.prototype.hasOwnProperty.call(r,a)&&(e[a]=r[a])}return e}).apply(this,arguments)}t.default=function(e){return s.createElement("svg",_extends({xmlns:"http://www.w3.org/2000/svg",width:500,height:500,viewBox:"0 0 132.292 132.292"},e),a||(a=s.createElement("linearGradient",{id:"follow_svg__a",x1:432.851,x2:464.644,y1:49.977,y2:49.977,gradientUnits:"userSpaceOnUse"},s.createElement("stop",{offset:0,stopColor:"#2087e2"}),s.createElement("stop",{offset:1,stopColor:"#b63fff"}))),n||(n=s.createElement("path",{fill:"url(#follow_svg__a)",d:"M438.672 34.08h20.151a5.82 5.82 45 0 1 5.82 5.821v20.151a5.82 5.82 135 0 1-5.82 5.821h-20.15a5.82 5.82 45 0 1-5.822-5.82V39.9a5.82 5.82 135 0 1 5.821-5.82z",transform:"matrix(4.16112 0 0 4.1611 -1801.146 -141.813)"})),o||(o=s.createElement("path",{fill:"#8842da",d:"m99.29 73.002-1.238 22.769-22.423.995 25.259 35.526h7.183c13.377-.001 24.22-10.845 24.22-24.222V89.683z",opacity:.85})),l||(l=s.createElement("g",{stroke:"#fff",strokeLinecap:"round",strokeLinejoin:"round"},s.createElement("circle",{cx:876.218,cy:118.03,r:21.554,fill:"none",strokeWidth:8.788,transform:"matrix(.90817 0 0 .9124 -737.017 -65.428)"}),s.createElement("path",{fill:"none",strokeWidth:6.641,d:"M845.107 163.996c0-16.543 13.41-29.953 29.953-29.953a29.953 29.953 0 0 1 19.632 7.331",transform:"matrix(1.14743 0 0 1.26483 -944.188 -103.004)"}),s.createElement("g",{fill:"#fff",strokeWidth:7.559},s.createElement("path",{d:"m881.641 159.874 34.92.28",transform:"translate(-853.609 -74.031)scale(1.05833)"}),s.createElement("path",{d:"m881.641 159.874 34.92.28",transform:"rotate(90 561.76 -294.47)scale(1.05833)"})))))}}}]);
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[9262],{70918:function(e,t,a){(window.__NEXT_P=window.__NEXT_P||[]).push(["/admin/upgrade",function(){return a(7494)}])},7494:function(e,t,a){"use strict";a.r(t);var n=a(85893),s=a(67294),l=a(59899),r=a(2307),d=a(53740),u=a(92863),i=a(15578);let{Title:o}=d.default,AssetTable=e=>{let t=Object.values(e);return(0,n.jsx)(r.Z,{dataSource:t,columns:[{title:"Name",dataIndex:"name",key:"name",render:(e,t)=>(0,n.jsx)("a",{href:t.browser_download_url,children:e})},{title:"Size",dataIndex:"size",key:"size",render:e=>"".concat((e/1024/1024).toFixed(2)," MB")}],rowKey:e=>e.id,size:"large",pagination:!1})},Logs=()=>{let[e,t]=(0,s.useState)({html_url:"",name:"",created_at:null,body:"",assets:[]}),getRelease=async()=>{try{let e=await (0,u.Kt)();t(e)}catch(e){console.log("==== error",e)}};return((0,s.useEffect)(()=>{getRelease()},[]),e)?(0,n.jsxs)("div",{className:"upgrade-page",children:[(0,n.jsx)(o,{level:2,children:(0,n.jsx)("a",{href:e.html_url,children:e.name})}),(0,n.jsx)(o,{level:5,children:new Date(e.created_at).toDateString()}),(0,n.jsx)(l.U,{children:e.body}),(0,n.jsx)("h3",{children:"Downloads"}),(0,n.jsx)(AssetTable,{...e.assets})]}):null};Logs.getLayout=function(e){return(0,n.jsx)(i.l,{page:e})},t.default=Logs}},function(e){e.O(0,[5596,1130,4104,9403,1024,3942,971,6697,1664,1749,1700,2122,7752,5891,2891,4749,6627,8966,7521,5578,9774,2888,179],function(){return e(e.s=70918)}),_N_E=e.O()}]);
|
||||
File diff suppressed because one or more lines are too long
@@ -9,9 +9,9 @@ request = request('http://127.0.0.1:8080');
|
||||
var ajv = new Ajv();
|
||||
var nodeInfoSchema = jsonfile.readFileSync('schema/nodeinfo_2.0.json');
|
||||
|
||||
const serverName = 'owncast.server.test'
|
||||
const serverURL = 'http://' + serverName
|
||||
const fediUsername = 'streamer'
|
||||
const serverName = 'owncast.server.test';
|
||||
const serverURL = 'http://' + serverName;
|
||||
const fediUsername = 'streamer';
|
||||
|
||||
test('disable federation', async (done) => {
|
||||
const res = await sendAdminRequest('config/federation/enable', false);
|
||||
@@ -59,10 +59,7 @@ test('verify responses of /federation/ when federation is disabled', async (done
|
||||
});
|
||||
|
||||
test('set required parameters and enable federation', async (done) => {
|
||||
const res1 = await sendAdminRequest(
|
||||
'config/serverurl',
|
||||
serverURL
|
||||
);
|
||||
const res1 = await sendAdminRequest('config/serverurl', serverURL);
|
||||
const res2 = await sendAdminRequest(
|
||||
'config/federation/username',
|
||||
fediUsername
|
||||
@@ -73,28 +70,47 @@ test('set required parameters and enable federation', async (done) => {
|
||||
|
||||
test('verify responses of /.well-known/webfinger when federation is enabled', async (done) => {
|
||||
const resNoResource = request.get('/.well-known/webfinger').expect(400);
|
||||
const resBadResource = request.get(
|
||||
'/.well-known/webfinger?resource=' + fediUsername + '@' + serverName
|
||||
).expect(400);
|
||||
const resBadResource2 = request.get(
|
||||
'/.well-known/webfinger?resource=notacct:' + fediUsername + '@' + serverName
|
||||
).expect(400);
|
||||
const resBadServer = request.get(
|
||||
'/.well-known/webfinger?resource=acct:' + fediUsername + '@not' + serverName
|
||||
).expect(404);
|
||||
const resBadUser = request.get(
|
||||
'/.well-known/webfinger?resource=acct:not' + fediUsername + '@' + serverName
|
||||
).expect(404);
|
||||
const resNoAccept = request.get(
|
||||
const resBadResource = request
|
||||
.get('/.well-known/webfinger?resource=' + fediUsername + '@' + serverName)
|
||||
.expect(400);
|
||||
const resBadResource2 = request
|
||||
.get(
|
||||
'/.well-known/webfinger?resource=notacct:' +
|
||||
fediUsername +
|
||||
'@' +
|
||||
serverName
|
||||
)
|
||||
.expect(400);
|
||||
const resBadServer = request
|
||||
.get(
|
||||
'/.well-known/webfinger?resource=acct:' +
|
||||
fediUsername +
|
||||
'@not' +
|
||||
serverName
|
||||
)
|
||||
.expect(404);
|
||||
const resBadUser = request
|
||||
.get(
|
||||
'/.well-known/webfinger?resource=acct:not' +
|
||||
fediUsername +
|
||||
'@' +
|
||||
serverName
|
||||
)
|
||||
.expect(404);
|
||||
const resNoAccept = request
|
||||
.get(
|
||||
'/.well-known/webfinger?resource=acct:' + fediUsername + '@' + serverName
|
||||
).expect(200)
|
||||
)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.then((res) => {
|
||||
parseJson(res.text);
|
||||
});
|
||||
const resWithAccept = request.get(
|
||||
const resWithAccept = request
|
||||
.get(
|
||||
'/.well-known/webfinger?resource=acct:' + fediUsername + '@' + serverName
|
||||
).expect(200)
|
||||
)
|
||||
.expect(200)
|
||||
.set('Accept', 'application/json')
|
||||
.expect('Content-Type', /json/)
|
||||
.then((res) => {
|
||||
@@ -104,14 +120,16 @@ test('verify responses of /.well-known/webfinger when federation is enabled', as
|
||||
});
|
||||
|
||||
test('verify responses of /.well-known/host-meta when federation is enabled', async (done) => {
|
||||
const res = request.get('/.well-known/host-meta')
|
||||
const res = request
|
||||
.get('/.well-known/host-meta')
|
||||
.expect(200)
|
||||
.expect('Content-Type', /xml/);
|
||||
done();
|
||||
});
|
||||
|
||||
test('verify responses of /.well-known/nodeinfo when federation is enabled', async (done) => {
|
||||
const res = request.get('/.well-known/nodeinfo')
|
||||
const res = request
|
||||
.get('/.well-known/nodeinfo')
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.then((res) => {
|
||||
@@ -121,7 +139,8 @@ test('verify responses of /.well-known/nodeinfo when federation is enabled', asy
|
||||
});
|
||||
|
||||
test('verify responses of /.well-known/x-nodeinfo2 when federation is enabled', async (done) => {
|
||||
const res = request.get('/.well-known/x-nodeinfo2')
|
||||
const res = request
|
||||
.get('/.well-known/x-nodeinfo2')
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.then((res) => {
|
||||
@@ -143,7 +162,8 @@ test('verify responses of /nodeinfo/2.0 when federation is enabled', async (done
|
||||
});
|
||||
|
||||
test('verify responses of /api/v1/instance when federation is enabled', async (done) => {
|
||||
const res = request.get('/api/v1/instance')
|
||||
const res = request
|
||||
.get('/api/v1/instance')
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.then((res) => {
|
||||
@@ -153,15 +173,17 @@ test('verify responses of /api/v1/instance when federation is enabled', async (d
|
||||
});
|
||||
|
||||
test('verify responses of /federation/user/ when federation is enabled', async (done) => {
|
||||
const resNoAccept = request.get('/federation/user/')
|
||||
.expect(307);
|
||||
const resWithAccept = request.get('/federation/user/')
|
||||
const resNoAccept = request.get('/federation/user/').expect(307);
|
||||
const resWithAccept = request
|
||||
.get('/federation/user/')
|
||||
.set('Accept', 'application/json')
|
||||
.expect(404);
|
||||
const resWithAcceptWrongUsername = request.get('/federation/user/not' + fediUsername)
|
||||
const resWithAcceptWrongUsername = request
|
||||
.get('/federation/user/not' + fediUsername)
|
||||
.set('Accept', 'application/json')
|
||||
.expect(404);
|
||||
const resWithAcceptUsername = request.get('/federation/user/' + fediUsername)
|
||||
const resWithAcceptUsername = request
|
||||
.get('/federation/user/' + fediUsername)
|
||||
.set('Accept', 'application/json')
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
@@ -172,9 +194,9 @@ test('verify responses of /federation/user/ when federation is enabled', async (
|
||||
});
|
||||
|
||||
test('verify responses of /federation/ when federation is enabled', async (done) => {
|
||||
const resNoAccept = request.get('/federation/')
|
||||
.expect(307);
|
||||
const resWithAccept = request.get('/federation/')
|
||||
const resNoAccept = request.get('/federation/').expect(307);
|
||||
const resWithAccept = request
|
||||
.get('/federation/')
|
||||
.set('Accept', 'application/json')
|
||||
.expect(404);
|
||||
done();
|
||||
|
||||
@@ -43,7 +43,7 @@ function start_owncast() {
|
||||
go build -o owncast main.go
|
||||
|
||||
echo "Running owncast..."
|
||||
./owncast -database "$TEMP_DB" &
|
||||
./owncast -disableResponseCaching -database "$TEMP_DB" &
|
||||
SERVER_PID=$!
|
||||
popd >/dev/null
|
||||
|
||||
|
||||
Reference in New Issue
Block a user