feat: allow homepage customization
arcad/arcast/pipeline/head This commit is unstable
Details
arcad/arcast/pipeline/head This commit is unstable
Details
This commit is contained in:
parent
35585959f5
commit
768393adc8
|
@ -19,7 +19,10 @@ Voici un exemple commenté du fichier de configuration:
|
|||
"http": {
|
||||
// Couple <address>:<port> d'écoute
|
||||
// Par défaut ":" i.e. toutes les adresses avec port aléatoire
|
||||
"address": ":"
|
||||
"address": ":",
|
||||
// Répertoire de personnalisation de la page d'accueil
|
||||
// Voir section "Personnalisation" ci-dessous
|
||||
"customDir": "${CONFIG_DIR}/custom"
|
||||
},
|
||||
// Configuration du serveur HTTPS
|
||||
"https": {
|
||||
|
@ -48,3 +51,9 @@ Voici un exemple commenté du fichier de configuration:
|
|||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Personnalisation
|
||||
|
||||
Il est possible de personnaliser la page d'accueil du player Arcast en créant des fichiers dans le répertoire définit par l'attribut de configuration `http.customDir`.
|
||||
|
||||
Le contenu de ce répertoire doit répliquer l'arborescence embarquée par défaut (voir https://forge.cadoles.com/arcad/arcast/src/branch/develop/pkg/server/embed). Chaque fichier présent remplacera celui embarqué par défaut.
|
||||
|
|
2
go.mod
2
go.mod
|
@ -4,6 +4,7 @@ go 1.21.4
|
|||
|
||||
require (
|
||||
gioui.org v0.4.1
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/gioui-plugins/gio-plugins v0.0.0-20240323070753-3331d8c2df5d
|
||||
github.com/go-chi/cors v1.2.1
|
||||
github.com/gorilla/websocket v1.5.1
|
||||
|
@ -23,6 +24,7 @@ require (
|
|||
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
|
||||
github.com/charmbracelet/lipgloss v0.7.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/dschmidt/go-layerfs v0.1.0 // indirect
|
||||
github.com/go-playground/locales v0.14.0 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||
github.com/go-text/typesetting v0.0.0-20230803102845-24e03d8b5372 // indirect
|
||||
|
|
2
go.sum
2
go.sum
|
@ -32,6 +32,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dschmidt/go-layerfs v0.1.0 h1:jE6aHDfjNzS/31DS48th6EkmELwTa1Uf+aO4jRkBs3U=
|
||||
github.com/dschmidt/go-layerfs v0.1.0/go.mod h1:m62aff0hn23Q/tQBRiNSeLD7EUuimDvsuCvCpzBr3Gw=
|
||||
github.com/gioui-plugins/gio-plugins v0.0.0-20240323070753-3331d8c2df5d h1:8b7owUJ8sNmgqEk+1d7ylr3TCH3vliCvY/6ycfize8o=
|
||||
github.com/gioui-plugins/gio-plugins v0.0.0-20240323070753-3331d8c2df5d/go.mod h1:3XVleuCdPpdajFL+ASh2wmXZNskitXQQ4jhVss0VHZg=
|
||||
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
|
||||
|
|
|
@ -68,6 +68,11 @@ func Run() *cli.Command {
|
|||
EnvVars: []string{"ARCAST_DESKTOP_ALLOWED_ORIGINS"},
|
||||
Value: cli.NewStringSlice(),
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "custom-files-dir",
|
||||
EnvVars: []string{"ARCAST_DESKTOP_CUSTOM_FILES_DIR"},
|
||||
Value: "",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "dummy-browser",
|
||||
EnvVars: []string{"ARCAST_DESKTOP_DUMMY_BROWSER"},
|
||||
|
@ -114,21 +119,11 @@ func Run() *cli.Command {
|
|||
|
||||
conf := config.DefaultConfig()
|
||||
|
||||
logger.Info(ctx.Context, "loading or creating configuration file", logger.F("filename", configFile))
|
||||
if err := config.LoadOrCreate(ctx.Context, configFile, conf, config.DefaultTransforms...); err != nil {
|
||||
logger.Error(ctx.Context, "could not load configuration file", logger.CapturedE(errors.WithStack(err)))
|
||||
}
|
||||
|
||||
instanceID := ctx.String("instance-id")
|
||||
if instanceID != "" {
|
||||
conf.InstanceID = instanceID
|
||||
}
|
||||
|
||||
cert, err := tls.X509KeyPair(conf.HTTPS.Cert, conf.HTTPS.Key)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not parse tls cert/key pair")
|
||||
}
|
||||
|
||||
if ctx.IsSet("apps") {
|
||||
conf.Apps.Enabled = ctx.Bool("apps")
|
||||
}
|
||||
|
@ -145,6 +140,20 @@ func Run() *cli.Command {
|
|||
conf.AllowedOrigins = ctx.StringSlice("allowed-origins")
|
||||
}
|
||||
|
||||
if ctx.IsSet("custom-dir") {
|
||||
conf.HTTP.CustomDir = ctx.String("custom-dir")
|
||||
}
|
||||
|
||||
logger.Info(ctx.Context, "loading or creating configuration file", logger.F("filename", configFile))
|
||||
if err := config.LoadOrCreate(ctx.Context, configFile, conf, config.DefaultTransforms...); err != nil {
|
||||
logger.Error(ctx.Context, "could not load configuration file", logger.CapturedE(errors.WithStack(err)))
|
||||
}
|
||||
|
||||
cert, err := tls.X509KeyPair(conf.HTTPS.Cert, conf.HTTPS.Key)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not parse tls cert/key pair")
|
||||
}
|
||||
|
||||
server := server.New(browser,
|
||||
server.WithInstanceID(conf.InstanceID),
|
||||
server.WithAppsEnabled(conf.Apps.Enabled),
|
||||
|
@ -154,6 +163,7 @@ func Run() *cli.Command {
|
|||
server.WithTLSAddress(conf.HTTPS.Address),
|
||||
server.WithTLSCertificate(&cert),
|
||||
server.WithAllowedOrigins(conf.AllowedOrigins...),
|
||||
server.WithUpperLayerDir(conf.HTTP.CustomDir),
|
||||
)
|
||||
|
||||
if err := server.Start(); err != nil {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
}
|
||||
|
||||
**/*.go
|
||||
pkg/server/templates/**.gotmpl
|
||||
pkg/server/embed/**
|
||||
modd.conf
|
||||
.env {
|
||||
prep: make build-client
|
||||
|
|
|
@ -21,6 +21,7 @@ type Config struct {
|
|||
|
||||
type HTTPConfig struct {
|
||||
Address string `json:"address"`
|
||||
CustomDir string `json:"customDir"`
|
||||
}
|
||||
|
||||
type HTTPSConfig struct {
|
||||
|
@ -40,7 +41,7 @@ type AppsConfig struct {
|
|||
DefaultApp string `json:"defaultApp"`
|
||||
}
|
||||
|
||||
type TransformFunc func(ctx context.Context, conf *Config) error
|
||||
type TransformFunc func(ctx context.Context, filename string, conf *Config) error
|
||||
|
||||
func DefaultConfigFile(ctx context.Context) string {
|
||||
configDir, err := os.UserConfigDir()
|
||||
|
@ -69,7 +70,7 @@ func LoadOrCreate(ctx context.Context, filename string, conf *Config, funcs ...T
|
|||
}
|
||||
|
||||
for _, fn := range funcs {
|
||||
if err := fn(ctx, conf); err != nil {
|
||||
if err := fn(ctx, filename, conf); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
}
|
||||
|
@ -100,6 +101,7 @@ func DefaultConfig() *Config {
|
|||
AllowedOrigins: []string{},
|
||||
HTTP: HTTPConfig{
|
||||
Address: ":45555",
|
||||
CustomDir: "",
|
||||
},
|
||||
HTTPS: HTTPSConfig{
|
||||
Address: ":45556",
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gitlab.com/wpetit/goweb/logger"
|
||||
)
|
||||
|
||||
func CreateCustomDir(ctx context.Context, filename string, conf *Config) error {
|
||||
if conf.HTTP.CustomDir != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
configDir := filepath.Dir(filename)
|
||||
customFilesDir := filepath.Join(configDir, "custom")
|
||||
|
||||
if err := os.MkdirAll(customFilesDir, 0755); err != nil {
|
||||
logger.Error(ctx, "could not create custom files directory", logger.CapturedE(errors.WithStack(err)))
|
||||
return nil
|
||||
}
|
||||
|
||||
conf.HTTP.CustomDir = customFilesDir
|
||||
|
||||
return nil
|
||||
}
|
|
@ -3,4 +3,5 @@ package config
|
|||
var DefaultTransforms = []TransformFunc{
|
||||
GenerateSelfSignedCert,
|
||||
RenewExpiredSelfSignedCert,
|
||||
CreateCustomDir,
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
"gitlab.com/wpetit/goweb/logger"
|
||||
)
|
||||
|
||||
func GenerateSelfSignedCert(ctx context.Context, conf *Config) error {
|
||||
func GenerateSelfSignedCert(ctx context.Context, filename string, conf *Config) error {
|
||||
if !conf.HTTPS.SelfSigned.Enabled {
|
||||
return nil
|
||||
}
|
||||
|
@ -42,13 +42,13 @@ func GenerateSelfSignedCert(ctx context.Context, conf *Config) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func RenewExpiredSelfSignedCert(ctx context.Context, conf *Config) error {
|
||||
func RenewExpiredSelfSignedCert(ctx context.Context, filename string, conf *Config) error {
|
||||
if !conf.HTTPS.SelfSigned.Enabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
if conf.HTTPS.Cert == nil || conf.HTTPS.Key == nil {
|
||||
if err := GenerateSelfSignedCert(ctx, conf); err != nil {
|
||||
if err := GenerateSelfSignedCert(ctx, filename, conf); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ func RenewExpiredSelfSignedCert(ctx context.Context, conf *Config) error {
|
|||
if err != nil {
|
||||
logger.Error(ctx, "could not parse x509 certificate, regenerating one", logger.CapturedE(errors.WithStack(err)))
|
||||
|
||||
if err := GenerateSelfSignedCert(ctx, conf); err != nil {
|
||||
if err := GenerateSelfSignedCert(ctx, filename, conf); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ func RenewExpiredSelfSignedCert(ctx context.Context, conf *Config) error {
|
|||
|
||||
logger.Warn(ctx, "self-signed certificate has expired, regenerating one", logger.CapturedE(errors.WithStack(err)))
|
||||
|
||||
if err := GenerateSelfSignedCert(ctx, conf); err != nil {
|
||||
if err := GenerateSelfSignedCert(ctx, filename, conf); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
{{ define "base" }}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" type="image/x-icon" href="/logo.png" />
|
||||
<title>Ready to cast !</title>
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
{{ block "head" .
|
||||
}}{{
|
||||
end
|
||||
}}
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="panel">
|
||||
<div id="icon"></div>
|
||||
{{ block "message" . }}
|
||||
<h2 id="title" class="text-centered">Ready to cast !</h2>
|
||||
{{ end }}
|
||||
{{ block "info" . }}
|
||||
<p><b>Instance ID</b></p>
|
||||
<p class="text-small text-centered">
|
||||
<code>{{ .ID }}</code>
|
||||
</p>
|
||||
<p><b>Addresses</b></p>
|
||||
<ul class="text-italic text-small text-centered">
|
||||
{{ $port := .Port }}
|
||||
{{
|
||||
range.IPs
|
||||
}}
|
||||
<li>
|
||||
<code>{{ . }}:{{ $port }}</code>
|
||||
</li>
|
||||
{{
|
||||
end
|
||||
}}
|
||||
</ul>
|
||||
{{ end }}
|
||||
{{if .Apps }}
|
||||
{{ block "apps" . }}
|
||||
<p><b>Apps</b></p>
|
||||
<ul class="text-italic text-small text-centered">
|
||||
{{ $tlsPort := .TLSPort }}
|
||||
{{
|
||||
range.IPs
|
||||
}}
|
||||
<li>
|
||||
<a href="https://{{ . }}:{{ $tlsPort }}/apps">
|
||||
https://{{ . }}:{{ $tlsPort }}/apps
|
||||
</a>
|
||||
</li>
|
||||
{{
|
||||
end
|
||||
}}
|
||||
</ul>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
{{ end }}
|
|
@ -0,0 +1,3 @@
|
|||
{{ define "index" }}
|
||||
{{ template "base" . }}
|
||||
{{ end }}
|
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
|
@ -0,0 +1,121 @@
|
|||
html {
|
||||
box-sizing: border-box;
|
||||
font-size: 16px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
||||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgb(76, 96, 188);
|
||||
background: linear-gradient(
|
||||
415deg,
|
||||
rgba(4, 168, 243, 1),
|
||||
rgb(76, 136, 188, 1),
|
||||
rgba(76, 96, 188, 1),
|
||||
rgb(115, 76, 188, 1),
|
||||
rgb(87, 76, 188, 1)
|
||||
);
|
||||
background-size: 400% 400%;
|
||||
animation: gradient 15s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes gradient {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
body,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
p,
|
||||
ol,
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.panel {
|
||||
display: block;
|
||||
background-color: #fff;
|
||||
border-radius: 15px;
|
||||
box-shadow: 10px 10px 10px #33333361;
|
||||
position: relative;
|
||||
padding: 50px 30px 30px 30px;
|
||||
min-width: 50%;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
#title {
|
||||
margin: 10px 0px 20px 0px;
|
||||
}
|
||||
|
||||
#icon {
|
||||
width: 100px;
|
||||
aspect-ratio: 1/1;
|
||||
background-size: contain;
|
||||
background-position: center center;
|
||||
background-image: url("logo.png");
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-left: -50px;
|
||||
margin-top: -100px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.panel p,
|
||||
.panel ul {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.text-centered {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.text-small {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.mt {
|
||||
margin-top: 1em;
|
||||
display: block;
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"html/template"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"forge.cadoles.com/arcad/arcast/pkg/network"
|
||||
"github.com/dschmidt/go-layerfs"
|
||||
"github.com/pkg/errors"
|
||||
"gitlab.com/wpetit/goweb/logger"
|
||||
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed embed/**
|
||||
embedFS embed.FS
|
||||
)
|
||||
|
||||
func (s *Server) initLayeredFS() error {
|
||||
layers := make([]fs.FS, 0)
|
||||
|
||||
if s.upperLayerDir != "" {
|
||||
upperLayer := os.DirFS(s.upperLayerDir)
|
||||
layers = append(layers, upperLayer)
|
||||
}
|
||||
|
||||
baseLayer, err := fs.Sub(embedFS, "embed")
|
||||
if err != nil {
|
||||
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
layers = append(layers, baseLayer)
|
||||
|
||||
s.layeredFS = layerfs.New(layers...)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) handleStatic(w http.ResponseWriter, r *http.Request) {
|
||||
path := r.URL.Path
|
||||
|
||||
if strings.HasPrefix(path, "/_templates") {
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
http.ServeFileFS(w, r, s.layeredFS, path)
|
||||
}
|
||||
|
||||
func (s *Server) handleIndex(w http.ResponseWriter, r *http.Request) {
|
||||
type templateData struct {
|
||||
IPs []string
|
||||
Port int
|
||||
TLSPort int
|
||||
ID string
|
||||
Apps bool
|
||||
}
|
||||
|
||||
ips, err := network.GetLANIPv4Addrs()
|
||||
if err != nil {
|
||||
logger.Error(r.Context(), "could not retrieve lan ip addresses", logger.CapturedE(errors.WithStack(err)))
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
d := templateData{
|
||||
ID: s.instanceID,
|
||||
IPs: ips,
|
||||
Port: s.port,
|
||||
TLSPort: s.tlsPort,
|
||||
Apps: s.appsEnabled,
|
||||
}
|
||||
|
||||
templates, err := template.New("").ParseFS(s.layeredFS, "_partials/*.gohtml", "_templates/*.gohtml")
|
||||
if err != nil {
|
||||
logger.Error(r.Context(), "could not parse template", logger.CapturedE(errors.WithStack(err)))
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if err := templates.ExecuteTemplate(w, "index", d); err != nil {
|
||||
logger.Error(r.Context(), "could not render index page", logger.CapturedE(errors.WithStack(err)))
|
||||
}
|
||||
}
|
|
@ -4,7 +4,6 @@ import (
|
|||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
@ -14,25 +13,8 @@ import (
|
|||
"github.com/go-chi/cors"
|
||||
"github.com/pkg/errors"
|
||||
"gitlab.com/wpetit/goweb/logger"
|
||||
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed templates/idle.html.gotmpl
|
||||
rawIdleTemplate []byte
|
||||
idleTemplate *template.Template
|
||||
)
|
||||
|
||||
func init() {
|
||||
tmpl, err := template.New("").Parse(string(rawIdleTemplate))
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "could not parse idle template"))
|
||||
}
|
||||
|
||||
idleTemplate = tmpl
|
||||
}
|
||||
|
||||
func (s *Server) startWebServers(ctx context.Context) error {
|
||||
router := chi.NewRouter()
|
||||
|
||||
|
@ -50,7 +32,6 @@ func (s *Server) startWebServers(ctx context.Context) error {
|
|||
}))
|
||||
}
|
||||
|
||||
router.Get("/", s.handleHome)
|
||||
router.Get("/api/v1/info", s.handleInfo)
|
||||
router.Post("/api/v1/cast", s.handleCast)
|
||||
router.Delete("/api/v1/cast", s.handleReset)
|
||||
|
@ -63,6 +44,9 @@ func (s *Server) startWebServers(ctx context.Context) error {
|
|||
router.Handle("/api/v1/broadcast/{channelID}", http.HandlerFunc(s.handleBroadcast))
|
||||
}
|
||||
|
||||
router.Get("/", s.handleIndex)
|
||||
router.Get("/*", s.handleStatic)
|
||||
|
||||
if err := s.startHTTPServer(ctx, router); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
@ -193,32 +177,3 @@ func (s *Server) getAllowedOrigins() ([]string, error) {
|
|||
|
||||
return allowedOrigins, nil
|
||||
}
|
||||
|
||||
func (s *Server) handleHome(w http.ResponseWriter, r *http.Request) {
|
||||
type templateData struct {
|
||||
IPs []string
|
||||
Port int
|
||||
TLSPort int
|
||||
ID string
|
||||
Apps bool
|
||||
}
|
||||
|
||||
ips, err := network.GetLANIPv4Addrs()
|
||||
if err != nil {
|
||||
logger.Error(r.Context(), "could not retrieve lan ip addresses", logger.CapturedE(errors.WithStack(err)))
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
d := templateData{
|
||||
ID: s.instanceID,
|
||||
IPs: ips,
|
||||
Port: s.port,
|
||||
TLSPort: s.tlsPort,
|
||||
Apps: s.appsEnabled,
|
||||
}
|
||||
|
||||
if err := idleTemplate.Execute(w, d); err != nil {
|
||||
logger.Error(r.Context(), "could not render idle page", logger.CapturedE(errors.WithStack(err)))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ type Options struct {
|
|||
DefaultApp string
|
||||
AllowedOrigins []string
|
||||
Apps []App
|
||||
UpperLayerDir string
|
||||
}
|
||||
|
||||
type OptionFunc func(opts *Options)
|
||||
|
@ -42,6 +43,7 @@ func NewOptions(funcs ...OptionFunc) *Options {
|
|||
DefaultApp: "",
|
||||
AllowedOrigins: make([]string, 0),
|
||||
Apps: make([]App, 0),
|
||||
UpperLayerDir: "",
|
||||
}
|
||||
|
||||
for _, fn := range funcs {
|
||||
|
@ -105,6 +107,12 @@ func WithServiceDiscoveryEnabled(enabled bool) OptionFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func WithUpperLayerDir(dir string) OptionFunc {
|
||||
return func(opts *Options) {
|
||||
opts.UpperLayerDir = dir
|
||||
}
|
||||
}
|
||||
|
||||
func NewRandomInstanceID() string {
|
||||
return newRandomInstanceID()
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package server
|
|||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"io/fs"
|
||||
|
||||
"forge.cadoles.com/arcad/arcast/pkg/browser"
|
||||
"github.com/gorilla/websocket"
|
||||
|
@ -32,10 +33,19 @@ type Server struct {
|
|||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
upgrader websocket.Upgrader
|
||||
|
||||
layeredFS fs.FS
|
||||
upperLayerDir string
|
||||
}
|
||||
|
||||
func (s *Server) Start() error {
|
||||
serverCtx, cancelServer := context.WithCancel(context.Background())
|
||||
ctx := context.Background()
|
||||
|
||||
if err := s.initLayeredFS(); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
serverCtx, cancelServer := context.WithCancel(ctx)
|
||||
|
||||
s.cancel = cancelServer
|
||||
s.ctx = serverCtx
|
||||
|
@ -92,6 +102,7 @@ func New(browser browser.Browser, funcs ...OptionFunc) *Server {
|
|||
defaultApp: opts.DefaultApp,
|
||||
apps: opts.Apps,
|
||||
serviceDiscoveryEnabled: opts.EnableServiceDiscovery,
|
||||
upperLayerDir: opts.UpperLayerDir,
|
||||
}
|
||||
|
||||
server.upgrader = websocket.Upgrader{
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue