Browse Source

Add support for extra.d directory

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 <head> and <body> 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:
```
	<link rel="stylesheet" href="<%.S%>/css/my-plugin.css">
```

Example body.html:
```
	<script data-plugin="<%.S%>/js/my-plugin.js"></script>
```

This makes it possible to extend the web client with additional
components and/or overwrite existing.
pull/304/head
Simon Eisenmann 9 years ago
parent
commit
cfec82384a
  1. 1
      .gitignore
  2. 25
      go/channelling/context.go
  3. 3
      html/head.html
  4. 3
      html/main.html
  5. 8
      server.conf.in
  6. 18
      src/app/spreed-webrtc-server/handler_room.go
  7. 52
      src/app/spreed-webrtc-server/main.go
  8. 23
      src/app/spreed-webrtc-server/utils.go

1
.gitignore vendored

@ -19,6 +19,7 @@ vendor/*
/build/out/ /build/out/
/.sass-cache /.sass-cache
/extra /extra
/extra.d
/src/i18n/*.mo /src/i18n/*.mo
server.key server.key
server.csr server.csr

25
go/channelling/context.go

@ -21,14 +21,21 @@
package channelling package channelling
import (
"html/template"
)
type Context struct { type Context struct {
App string // Main client script App string // Main client script
Cfg *Config Cfg *Config
Host string Host string
Ssl bool Ssl bool
Csp bool Csp bool
Languages []string Languages []string
Room string `json:"-"` Room string `json:"-"`
Scheme string `json:"-"` Scheme string `json:"-"`
Origin string `json:",omitempty"` Origin string `json:",omitempty"`
S string `json:",omitempty"`
ExtraDHead template.HTML `json:"-"`
ExtraDBody template.HTML `json:"-"`
} }

3
html/head.html

@ -11,4 +11,5 @@
<link rel="stylesheet" type="text/css" href="<%.Cfg.S%>/css/font-awesome.min.css"> <link rel="stylesheet" type="text/css" href="<%.Cfg.S%>/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css" href="<%.Cfg.S%>/css/main.min.css"> <link rel="stylesheet" type="text/css" href="<%.Cfg.S%>/css/main.min.css">
<%template "extra-head" .%> <%template "extra-head" .%>
<script id="globalcontext" type="application/json"><%$%></script><%end%> <%.ExtraDHead%>
<script id="globalcontext" type="application/json"><%$%></script><%end%>

3
html/main.html

@ -9,5 +9,6 @@
<ui></ui> <ui></ui>
<script data-main="<%.Cfg.S%>/js/<%.App%>" data-plugin="<%.Cfg.Plugin%>" src="<%.Cfg.S%>/js/libs/require/require.js"></script> <script data-main="<%.Cfg.S%>/js/<%.App%>" data-plugin="<%.Cfg.Plugin%>" src="<%.Cfg.S%>/js/libs/require/require.js"></script>
<%template "extra-body" .%> <%template "extra-body" .%>
<%.ExtraDBody%>
</body> </body>
</html><%end%> </html><%end%>

8
server.conf.in

@ -101,14 +101,20 @@ serverRealm = local
; Full path to an extra templates directory. Templates in this directory ending ; 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 ; 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 ; 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. ; relative to your servers base URL.
;extra = /usr/share/spreed-webrtc-server/extra ;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/<n>/...
; relative to your servers base URL.
; URL relative to the servers base path for a plugin javascript file which is ; 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 ; 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 ; 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 ; a front end webserver. Check the doc folder for more info about plugins and
; examples. ; examples.
;extra.d = /usr/share/spreed-webrtc-server/extra.d
;plugin = extra/static/myplugin.js ;plugin = extra/static/myplugin.js
; Content-Security-Policy HTTP response header value. ; Content-Security-Policy HTTP response header value.
; Spreed WebRTC requires inline styles, WebSocket connection to itself and ; Spreed WebRTC requires inline styles, WebSocket connection to itself and

18
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.. // 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. // Get URL parameters.
r.ParseForm() 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. // See https://developers.google.com/webmasters/ajax-crawling/docs/getting-started for details.
if _, ok := r.Form["_escaped_fragment_"]; ok { if _, ok := r.Form["_escaped_fragment_"]; ok {
// Render crawlerPage template.. // Render crawlerPage template..
err = templates.ExecuteTemplate(w, "crawlerPage", &context) err = templates.ExecuteTemplate(w, "crawlerPage", context)
} else { } else {
// Render mainPage template. // Render mainPage template.
err = templates.ExecuteTemplate(w, "mainPage", &context) err = templates.ExecuteTemplate(w, "mainPage", context)
} }
if err != nil { if err != nil {

52
src/app/spreed-webrtc-server/main.go

@ -22,11 +22,13 @@
package main package main
import ( import (
"bytes"
"crypto/rand" "crypto/rand"
"encoding/hex" "encoding/hex"
"flag" "flag"
"fmt" "fmt"
"html/template" "html/template"
"io/ioutil"
"log" "log"
"net/http" "net/http"
_ "net/http/pprof" _ "net/http/pprof"
@ -53,6 +55,8 @@ var version = "unreleased"
var defaultConfig = "./server.conf" var defaultConfig = "./server.conf"
var templates *template.Template var templates *template.Template
var templatesExtraDHead template.HTML
var templatesExtraDBody template.HTML
var config *channelling.Config var config *channelling.Config
func runner(runtime phoenix.Runtime) error { func runner(runtime phoenix.Runtime) error {
@ -208,6 +212,45 @@ func runner(runtime phoenix.Runtime) error {
log.Printf("Loaded extra templates from: %s", extraFolder) 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. // Define incoming channeling API limit it byte. Larger messages will be discarded.
incomingCodecLimit := 1024 * 1024 // 1MB incomingCodecLimit := 1024 * 1024 // 1MB
@ -326,13 +369,20 @@ func runner(runtime phoenix.Runtime) error {
// Add extra/static support if configured and exists. // Add extra/static support if configured and exists.
if extraFolder != "" { if extraFolder != "" {
extraFolderStatic := path.Join(extraFolder, "static") extraFolderStatic, _ := filepath.Abs(path.Join(extraFolder, "static"))
if _, err = os.Stat(extraFolderStatic); err == nil { if _, err = os.Stat(extraFolderStatic); err == nil {
r.Handle("/extra/static/{path:.*}", http.StripPrefix(fmt.Sprintf("%sextra", config.B), httputils.FileStaticServer(http.Dir(extraFolder)))) 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) 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. // Finally add websocket handler.
r.Handle("/ws", makeWSHandler(statsManager, sessionManager, codec, channellingAPI, users)) r.Handle("/ws", makeWSHandler(statsManager, sessionManager, codec, channellingAPI, users))

23
src/app/spreed-webrtc-server/utils.go

@ -1,8 +1,11 @@
package main package main
import ( import (
"fmt"
"net/http" "net/http"
"github.com/gorilla/mux"
"github.com/strukturag/goacceptlanguageparser" "github.com/strukturag/goacceptlanguageparser"
) )
@ -15,3 +18,23 @@ func getRequestLanguages(r *http.Request, supportedLanguages []string) []string
} }
return langs 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)
})
}

Loading…
Cancel
Save