From cfec82384ac99ad13517dde9927e9b6277a3b762 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Wed, 29 Jun 2016 15:22:11 +0200 Subject: [PATCH] Add support for extra.d directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To allow muliple plugins, sorted plugin load and general extensibility of the web client, the server now supports to load an extra.d folder on startup. Sub folders inside extra.d, are loaded in alphabetic order and searched for head.html and body.html, making it possible to append additional html code into the and elements for the web client. Example: ``` extra.d/ └── my-plugin    ├── body.html    ├── head.html    └── static    ├── css │ └── my-plugin.css    └── js    └── my-plugin.js ``` Example head.html: ``` ``` Example body.html: ``` ``` This makes it possible to extend the web client with additional components and/or overwrite existing. --- .gitignore | 1 + go/channelling/context.go | 25 ++++++---- html/head.html | 3 +- html/main.html | 3 +- server.conf.in | 8 ++- src/app/spreed-webrtc-server/handler_room.go | 18 +++++-- src/app/spreed-webrtc-server/main.go | 52 +++++++++++++++++++- src/app/spreed-webrtc-server/utils.go | 23 +++++++++ 8 files changed, 117 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 65082f81..c554cbcc 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ vendor/* /build/out/ /.sass-cache /extra +/extra.d /src/i18n/*.mo server.key server.csr diff --git a/go/channelling/context.go b/go/channelling/context.go index 1315e2f5..c805a370 100644 --- a/go/channelling/context.go +++ b/go/channelling/context.go @@ -21,14 +21,21 @@ package channelling +import ( + "html/template" +) + type Context struct { - App string // Main client script - Cfg *Config - Host string - Ssl bool - Csp bool - Languages []string - Room string `json:"-"` - Scheme string `json:"-"` - Origin string `json:",omitempty"` + App string // Main client script + Cfg *Config + Host string + Ssl bool + Csp bool + Languages []string + Room string `json:"-"` + Scheme string `json:"-"` + Origin string `json:",omitempty"` + S string `json:",omitempty"` + ExtraDHead template.HTML `json:"-"` + ExtraDBody template.HTML `json:"-"` } diff --git a/html/head.html b/html/head.html index 5efedc9e..f9a95ec3 100644 --- a/html/head.html +++ b/html/head.html @@ -11,4 +11,5 @@ <%template "extra-head" .%> -<%end%> \ No newline at end of file +<%.ExtraDHead%> +<%end%> diff --git a/html/main.html b/html/main.html index 9cf277e3..ed9539c3 100644 --- a/html/main.html +++ b/html/main.html @@ -9,5 +9,6 @@ <%template "extra-body" .%> +<%.ExtraDBody%> -<%end%> \ No newline at end of file +<%end%> diff --git a/server.conf.in b/server.conf.in index 54ba2cb1..1c5d5917 100644 --- a/server.conf.in +++ b/server.conf.in @@ -101,14 +101,20 @@ serverRealm = local ; Full path to an extra templates directory. Templates in this directory ending ; with .html will be parsed on startup and can be used to fill the supported ; extra-* template slots. If the extra folder has a sub folder "static", the -; resources in this static folder will be available as /extra/static/filename +; resources in this static folder will be available as /extra/static/... ; relative to your servers base URL. ;extra = /usr/share/spreed-webrtc-server/extra +; Full path to an extra.d directory. Subfolders in this directory will be +; searched for head.html and body.html on startup. If found, those templates +; will be automatically included for the web client. In addition, +; sub-folder/static will be made available by URL at /extra.d/static//... +; relative to your servers base URL. ; URL relative to the servers base path for a plugin javascript file which is ; automatically loaded on web client start for all users. You can put your ; plugin in the extra/static folder (see above) or provide another folder using ; a front end webserver. Check the doc folder for more info about plugins and ; examples. +;extra.d = /usr/share/spreed-webrtc-server/extra.d ;plugin = extra/static/myplugin.js ; Content-Security-Policy HTTP response header value. ; Spreed WebRTC requires inline styles, WebSocket connection to itself and diff --git a/src/app/spreed-webrtc-server/handler_room.go b/src/app/spreed-webrtc-server/handler_room.go index df968384..58753eed 100644 --- a/src/app/spreed-webrtc-server/handler_room.go +++ b/src/app/spreed-webrtc-server/handler_room.go @@ -70,7 +70,19 @@ func handleRoomView(room string, w http.ResponseWriter, r *http.Request) { } // Prepare context to deliver to HTML.. - context := &channelling.Context{Cfg: config, App: "main", Host: r.Host, Scheme: scheme, Ssl: ssl, Csp: csp, Languages: langs, Room: room} + context := &channelling.Context{ + Cfg: config, + App: "main", + Host: r.Host, + Scheme: scheme, + Ssl: ssl, + Csp: csp, + Languages: langs, + Room: room, + S: config.S, + ExtraDHead: templatesExtraDHead, + ExtraDBody: templatesExtraDBody, + } // Get URL parameters. r.ParseForm() @@ -79,10 +91,10 @@ func handleRoomView(room string, w http.ResponseWriter, r *http.Request) { // See https://developers.google.com/webmasters/ajax-crawling/docs/getting-started for details. if _, ok := r.Form["_escaped_fragment_"]; ok { // Render crawlerPage template.. - err = templates.ExecuteTemplate(w, "crawlerPage", &context) + err = templates.ExecuteTemplate(w, "crawlerPage", context) } else { // Render mainPage template. - err = templates.ExecuteTemplate(w, "mainPage", &context) + err = templates.ExecuteTemplate(w, "mainPage", context) } if err != nil { diff --git a/src/app/spreed-webrtc-server/main.go b/src/app/spreed-webrtc-server/main.go index 4051bfba..49fcc2f0 100644 --- a/src/app/spreed-webrtc-server/main.go +++ b/src/app/spreed-webrtc-server/main.go @@ -22,11 +22,13 @@ package main import ( + "bytes" "crypto/rand" "encoding/hex" "flag" "fmt" "html/template" + "io/ioutil" "log" "net/http" _ "net/http/pprof" @@ -53,6 +55,8 @@ var version = "unreleased" var defaultConfig = "./server.conf" var templates *template.Template +var templatesExtraDHead template.HTML +var templatesExtraDBody template.HTML var config *channelling.Config func runner(runtime phoenix.Runtime) error { @@ -208,6 +212,45 @@ func runner(runtime phoenix.Runtime) error { log.Printf("Loaded extra templates from: %s", extraFolder) } + // Load extra.d folder + extraDFolder, err := runtime.GetString("app", "extra.d") + if err == nil { + if !httputils.HasDirPath(extraFolder) { + return fmt.Errorf("Configured extra '%s' is not a directory.", extraFolder) + } + var headBuf bytes.Buffer + var bodyBuf bytes.Buffer + context := &channelling.Context{ + Cfg: config, + } + if extras, err := ioutil.ReadDir(extraDFolder); err == nil { + // ioutil.ReadDir is sorted by name which is what we want here. + for _, extra := range extras { + if !extra.IsDir() { + continue + } + context.S = fmt.Sprintf("extra.d/%s/%s", config.S, extra.Name()) + extraDTemplates := template.New("") + extraDTemplates.Delims("<%", "%>") + extraBase := path.Join(extraDFolder, extra.Name()) + extraDTemplates.ParseFiles(path.Join(extraBase, "head.html"), path.Join(extraBase, "body.html")) + if headTemplate := extraDTemplates.Lookup("head.html"); headTemplate != nil { + if err := headTemplate.Execute(&headBuf, context); err != nil { + log.Println("Failed to parse extra.d template", extraBase, "head.html", err) + } + + } + if bodyTemplate := extraDTemplates.Lookup("body.html"); bodyTemplate != nil { + if err := bodyTemplate.Execute(&bodyBuf, context); err != nil { + log.Println("Failed to parse extra.d template", extraBase, "body.html", err) + } + } + } + } + templatesExtraDHead = template.HTML(headBuf.String()) + templatesExtraDBody = template.HTML(bodyBuf.String()) + } + // Define incoming channeling API limit it byte. Larger messages will be discarded. incomingCodecLimit := 1024 * 1024 // 1MB @@ -326,13 +369,20 @@ func runner(runtime phoenix.Runtime) error { // Add extra/static support if configured and exists. if extraFolder != "" { - extraFolderStatic := path.Join(extraFolder, "static") + extraFolderStatic, _ := filepath.Abs(path.Join(extraFolder, "static")) if _, err = os.Stat(extraFolderStatic); err == nil { r.Handle("/extra/static/{path:.*}", http.StripPrefix(fmt.Sprintf("%sextra", config.B), httputils.FileStaticServer(http.Dir(extraFolder)))) log.Printf("Added URL handler /extra/static/... for static files in %s/...\n", extraFolderStatic) } } + // Add extra.d/static support if configured. + if extraDFolder != "" { + extraDFolderStatic, _ := filepath.Abs(extraDFolder) + r.Handle("/extra.d/static/{ver}/{extra}/{path:.*}", http.StripPrefix(fmt.Sprintf("%sextra.d/static", config.B), rewriteExtraDUrl(httputils.FileStaticServer(http.Dir(extraDFolderStatic))))) + log.Printf("Added URL handler /extra.d/static/... for static files in %s/.../static/... \n", extraDFolderStatic) + } + // Finally add websocket handler. r.Handle("/ws", makeWSHandler(statsManager, sessionManager, codec, channellingAPI, users)) diff --git a/src/app/spreed-webrtc-server/utils.go b/src/app/spreed-webrtc-server/utils.go index b0c6f55b..b8be303e 100644 --- a/src/app/spreed-webrtc-server/utils.go +++ b/src/app/spreed-webrtc-server/utils.go @@ -1,8 +1,11 @@ package main import ( + "fmt" "net/http" + "github.com/gorilla/mux" + "github.com/strukturag/goacceptlanguageparser" ) @@ -15,3 +18,23 @@ func getRequestLanguages(r *http.Request, supportedLanguages []string) []string } return langs } + +func rewriteExtraDUrl(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + + extra, ok := vars["extra"] + if !ok { + http.NotFound(w, r) + return + } + path, ok := vars["path"] + if !ok { + http.NotFound(w, r) + return + } + + r.URL.Path = fmt.Sprintf("%s/static/%s", extra, path) + h.ServeHTTP(w, r) + }) +}