Compare commits

..

4 Commits

29 changed files with 226 additions and 140 deletions

View File

@ -1,3 +1,3 @@
ARCAST_DESKTOP_ADDITIONAL_CHROME_ARGS= ARCAST_DESKTOP_ADDITIONAL_CHROME_ARGS=
ARCAST_DESKTOP_INSTANCE_ID= ARCAST_DESKTOP_INSTANCE_ID=
ARCAST_DESKTOP_WEB_APPS=true ARCAST_DESKTOP_APPS=true

View File

@ -4,6 +4,7 @@ GORELEASER_ARGS ?= release --snapshot --rm-dist
GITCHLOG_ARGS ?= GITCHLOG_ARGS ?=
SHELL := /bin/bash SHELL := /bin/bash
JDK_PATH ?= /usr/lib/jvm/java-11-openjdk JDK_PATH ?= /usr/lib/jvm/java-11-openjdk
GOARCH ?= amd64
MKT_GITEA_RELEASE_PROJECT := arcast MKT_GITEA_RELEASE_PROJECT := arcast
MKT_GITEA_RELEASE_ORG := arcad MKT_GITEA_RELEASE_ORG := arcad
@ -22,9 +23,9 @@ test-go: deps
build: build-desktop build-android build-client ## Build artefacts build: build-desktop build-android build-client ## Build artefacts
build-desktop: deps ## Build executable build-desktop: deps ## Build executable
CGO_ENABLED=0 go build \ CGO_ENABLED=0 GOARCH=$(GOARCH) go build \
-v \ -v \
-o ./bin/desktop \ -o ./bin/desktop_$(GOARCH) \
./cmd/desktop ./cmd/desktop
build-client: deps ## Build executable build-client: deps ## Build executable
@ -35,9 +36,14 @@ build-client: deps ## Build executable
build-android: tools/gogio/bin/gogio deps ## Build executable build-android: tools/gogio/bin/gogio deps ## Build executable
mkdir -p dist mkdir -p dist
GOOS=android CGO_CFLAGS="-I${JDK_PATH}/include -I${JDK_PATH}/include/linux -w" tools/gogio/bin/gogio -target android -buildmode archive -o android/app/libs/mobile.aar -x ./cmd/mobile CGO_ENABLED=1 GOOS=android CGO_CFLAGS="-I${JDK_PATH}/include -I${JDK_PATH}/include/linux -w" tools/gogio/bin/gogio -target android -buildmode archive -o android/app/libs/mobile.aar -x ./cmd/mobile
( cd android && ./gradlew assembleDebug ) ( cd android && ./gradlew assembleDebug )
release-android: tools/gogio/bin/gogio deps ## Build executable
mkdir -p dist
CGO_ENABLED=1 GOOS=android CGO_CFLAGS="-I${JDK_PATH}/include -I${JDK_PATH}/include/linux -w" tools/gogio/bin/gogio -target android -buildmode archive -o android/app/libs/mobile.aar -x ./cmd/mobile
( cd android && ./gradlew assemble )
install-android: build-android install-android: build-android
adb install android/app/build/outputs/apk/debug/app-debug.apk adb install android/app/build/outputs/apk/debug/app-debug.apk
adb shell monkey -p com.cadoles.arcast_player -c android.intent.category.LAUNCHER 1 adb shell monkey -p com.cadoles.arcast_player -c android.intent.category.LAUNCHER 1
@ -66,7 +72,14 @@ gitea-release: .mktools build
rm -rf .gitea-release rm -rf .gitea-release
mkdir -p .gitea-release mkdir -p .gitea-release
cp ./bin/desktop .gitea-release/arcad_player_linux_amd64 cp ./bin/desktop_amd64 .gitea-release/arcad_player_linux_amd64
$(MAKE) GOARCH=arm build-desktop
cp ./bin/desktop_arm .gitea-release/arcad_player_linux_arm
$(MAKE) GOARCH=arm64 build-desktop
cp ./bin/desktop_arm64 .gitea-release/arcad_player_linux_arm64
cp ./bin/client .gitea-release/arcad_client_linux_amd64 cp ./bin/client .gitea-release/arcad_client_linux_amd64
cp ./android/app/build/outputs/apk/debug/app-debug.apk .gitea-release/arcast_player_debug.apk cp ./android/app/build/outputs/apk/debug/app-debug.apk .gitea-release/arcast_player_debug.apk

View File

@ -32,4 +32,4 @@ Avoir [Chromium](https://www.chromium.org/chromium-projects/) (ou `Google Chrome
#### Dernière version #### Dernière version
- Linux: [`amd64`](https://forge.cadoles.com/arcad/arcast/releases/download/latest/arcad_player_linux_amd64) - Linux: [`amd64`](https://forge.cadoles.com/arcad/arcast/releases/download/latest/arcad_player_linux_amd64), [`arm`](https://forge.cadoles.com/arcad/arcast/releases/download/latest/arcad_player_linux_arm), [`arm64`](https://forge.cadoles.com/arcad/arcast/releases/download/latest/arcad_player_linux_arm64)

19
apps/home/app.js Normal file
View File

@ -0,0 +1,19 @@
fetch("/api/v1/apps")
.then((res) => res.json())
.then((res) => {
const defaultApp = res.data.defaultApp;
const apps = res.data.apps;
const container = document.createElement("div");
container.className = "container";
apps.forEach((app) => {
if (app.id === defaultApp || app.hidden) return;
const appLink = document.createElement("a");
appLink.className = "app-link";
appLink.href = `/apps/${app.id}/`;
appLink.innerText = app.title["fr"];
container.appendChild(appLink);
});
document.getElementById("main").replaceWith(container);
});

3
apps/lib/manifest.json Normal file
View File

@ -0,0 +1,3 @@
{
"hidden": true
}

View File

@ -8,6 +8,7 @@ import (
"os" "os"
"sync" "sync"
"forge.cadoles.com/arcad/arcast"
"forge.cadoles.com/arcad/arcast/pkg/browser/gioui" "forge.cadoles.com/arcad/arcast/pkg/browser/gioui"
"forge.cadoles.com/arcad/arcast/pkg/server" "forge.cadoles.com/arcad/arcast/pkg/server"
"gioui.org/app" "gioui.org/app"
@ -80,7 +81,9 @@ func main() {
server := server.New( server := server.New(
browser, browser,
server.WithInstanceID(instanceID), server.WithInstanceID(instanceID),
server.WithWebApps(true), server.WithAppsEnabled(true),
server.WithDefautApp("home"),
server.WithApps(arcast.DefaultApps...),
) )
if err := server.Start(); err != nil { if err := server.Start(); err != nil {

70
default_apps.go Normal file
View File

@ -0,0 +1,70 @@
package arcast
import (
"embed"
"encoding/json"
"io/fs"
"path/filepath"
"forge.cadoles.com/arcad/arcast/pkg/server"
"github.com/pkg/errors"
)
var (
DefaultApps []server.App
//go:embed apps/**
appsFS embed.FS
)
func init() {
defaultApps, err := loadApps("apps/*")
if err != nil {
panic(errors.WithStack(err))
}
DefaultApps = defaultApps
}
func loadApps(dirPattern string) ([]server.App, error) {
apps := make([]server.App, 0)
files, err := fs.Glob(appsFS, dirPattern)
if err != nil {
return nil, errors.WithStack(err)
}
for _, f := range files {
stat, err := fs.Stat(appsFS, f)
if err != nil {
return nil, errors.WithStack(err)
}
if !stat.IsDir() {
continue
}
rawManifest, err := fs.ReadFile(appsFS, filepath.Join(f, "manifest.json"))
if err != nil {
return nil, errors.WithStack(err)
}
var app server.App
if err := json.Unmarshal(rawManifest, &app); err != nil {
return nil, errors.WithStack(err)
}
app.ID = filepath.Base(f)
fs, err := fs.Sub(appsFS, "apps/"+app.ID)
if err != nil {
return nil, errors.WithStack(err)
}
app.FS = fs
apps = append(apps, app)
}
return apps, nil
}

2
go.mod
View File

@ -60,3 +60,5 @@ require (
golang.org/x/net v0.19.0 // indirect golang.org/x/net v0.19.0 // indirect
golang.org/x/sys v0.15.0 // indirect golang.org/x/sys v0.15.0 // indirect
) )
replace github.com/zserge/lorca => github.com/Bornholm/lorca v0.0.0-20240121134933-d5e83569cb4c

4
go.sum
View File

@ -19,6 +19,8 @@ gioui.org/shader v1.0.8 h1:6ks0o/A+b0ne7RzEqRZK5f4Gboz2CfG+mVliciy6+qA=
gioui.org/shader v1.0.8/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM= gioui.org/shader v1.0.8/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0 h1:bGG/g4ypjrCJoSvFrP5hafr9PPB5aw8SjcOWWila7ZI= git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0 h1:bGG/g4ypjrCJoSvFrP5hafr9PPB5aw8SjcOWWila7ZI=
git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0/go.mod h1:+axXBRUTIDlCeE73IKeD/os7LoEnTKdkp8/gQOFjqyo= git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0/go.mod h1:+axXBRUTIDlCeE73IKeD/os7LoEnTKdkp8/gQOFjqyo=
github.com/Bornholm/lorca v0.0.0-20240121134933-d5e83569cb4c h1:xG9xSpEqZYOvd1Bvx/36i3RBTA17d7XnuvoMIG+/ry8=
github.com/Bornholm/lorca v0.0.0-20240121134933-d5e83569cb4c/go.mod h1:TUOtEogaMwy0b+p9e4NxZC1jbPRUaNaEw5DnjQF//F8=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
@ -104,8 +106,6 @@ github.com/wlynxg/anet v0.0.1/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguH
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zserge/lorca v0.1.10 h1:f/xBJ3D3ipcVRCcvN8XqZnpoKcOXV8I4vwqlFyw7ruc=
github.com/zserge/lorca v0.1.10/go.mod h1:bVmnIbIRlOcoV285KIRSe4bUABKi7R7384Ycuum6e4A=
gitlab.com/wpetit/goweb v0.0.0-20231215190137-4a8add1d3d07 h1:0V95X1cBpdj5zyOe6oGtn/BQHlRpV8WlL3eTs3jaxiA= gitlab.com/wpetit/goweb v0.0.0-20231215190137-4a8add1d3d07 h1:0V95X1cBpdj5zyOe6oGtn/BQHlRpV8WlL3eTs3jaxiA=
gitlab.com/wpetit/goweb v0.0.0-20231215190137-4a8add1d3d07/go.mod h1:Nfr7aZPiSN6biFumhiHbh9k8A3rKQRzR+o0bVtv78UY= gitlab.com/wpetit/goweb v0.0.0-20231215190137-4a8add1d3d07/go.mod h1:Nfr7aZPiSN6biFumhiHbh9k8A3rKQRzR+o0bVtv78UY=
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"os" "os"
"forge.cadoles.com/arcad/arcast"
"forge.cadoles.com/arcad/arcast/pkg/browser/lorca" "forge.cadoles.com/arcad/arcast/pkg/browser/lorca"
"forge.cadoles.com/arcad/arcast/pkg/server" "forge.cadoles.com/arcad/arcast/pkg/server"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -37,8 +38,8 @@ func Run() *cli.Command {
Value: defaults.Height, Value: defaults.Height,
}, },
&cli.BoolFlag{ &cli.BoolFlag{
Name: "web-apps", Name: "apps",
EnvVars: []string{"ARCAST_DESKTOP_WEB_APPS"}, EnvVars: []string{"ARCAST_DESKTOP_APPS"},
Value: false, Value: false,
}, },
&cli.IntFlag{ &cli.IntFlag{
@ -51,7 +52,7 @@ func Run() *cli.Command {
windowHeight := ctx.Int("window-height") windowHeight := ctx.Int("window-height")
windowWidth := ctx.Int("window-width") windowWidth := ctx.Int("window-width")
chromeArgs := addFlagsPrefix(ctx.StringSlice("additional-chrome-arg")...) chromeArgs := addFlagsPrefix(ctx.StringSlice("additional-chrome-arg")...)
webApps := ctx.Bool("web-apps") enableApps := ctx.Bool("apps")
serverAddress := ctx.String("address") serverAddress := ctx.String("address")
browser := lorca.NewBrowser( browser := lorca.NewBrowser(
@ -83,7 +84,9 @@ func Run() *cli.Command {
server := server.New(browser, server := server.New(browser,
server.WithInstanceID(instanceID), server.WithInstanceID(instanceID),
server.WithWebApps(webApps), server.WithAppsEnabled(enableApps),
server.WithDefaultApp("home"),
server.WithApps(arcast.DefaultApps...),
server.WithAddress(serverAddress), server.WithAddress(serverAddress),
) )

View File

@ -1,9 +1,9 @@
**/*.go **/*.go
pkg/server/templates/**.gotmpl pkg/server/templates/**.gotmpl
pkg/server/apps/** apps/**
modd.conf modd.conf
.env { .env {
prep: make build-client prep: make build-client
prep: make build-desktop prep: make build-desktop
daemon: make run RUN_CMD="bin/desktop --debug --log-level debug run" daemon: make run RUN_CMD="bin/desktop_amd64 --debug --log-level debug run"
} }

View File

@ -18,7 +18,10 @@ type Browser struct {
func (b *Browser) Start() error { func (b *Browser) Start() error {
logger.Debug(context.Background(), "starting browser", logger.F("opts", b.opts)) logger.Debug(context.Background(), "starting browser", logger.F("opts", b.opts))
ui, err := lorca.New("", "", b.opts.Width, b.opts.Height, b.opts.ChromeArgs...) ui, err := lorca.New(
lorca.WithWindowSize(b.opts.Width, b.opts.Height),
lorca.WithAdditionalCustomArgs(b.opts.ChromeArgs...),
)
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }

View File

@ -14,8 +14,8 @@ var DefaultChromeArgs = []string{
func NewOptions(funcs ...OptionsFunc) *Options { func NewOptions(funcs ...OptionsFunc) *Options {
opts := &Options{ opts := &Options{
Width: 800, Width: 0,
Height: 600, Height: 0,
ChromeArgs: DefaultChromeArgs, ChromeArgs: DefaultChromeArgs,
} }

View File

@ -1,83 +1,28 @@
package server package server
import ( import (
"embed"
"encoding/json"
"io/fs" "io/fs"
"net/http" "net/http"
"os" "strings"
"path/filepath" "sync"
"github.com/pkg/errors" "github.com/go-chi/chi/v5"
"gitlab.com/wpetit/goweb/api" "gitlab.com/wpetit/goweb/api"
_ "embed" _ "embed"
) )
var (
apps []App
//go:embed apps/**
appsFS embed.FS
)
func init() {
if err := initializeAppsList(); err != nil {
panic(errors.WithStack(err))
}
}
func initializeAppsList() error {
files, err := fs.Glob(appsFS, "apps/*")
if err != nil {
return errors.WithStack(err)
}
for _, f := range files {
stat, err := fs.Stat(appsFS, f)
if err != nil {
return errors.WithStack(err)
}
if !stat.IsDir() {
continue
}
rawManifest, err := fs.ReadFile(appsFS, filepath.Join(f, "manifest.json"))
if err != nil {
if errors.Is(err, os.ErrNotExist) {
continue
}
return errors.WithStack(err)
}
var app App
if err := json.Unmarshal(rawManifest, &app); err != nil {
return errors.WithStack(err)
}
app.ID = filepath.Base(f)
apps = append(apps, app)
}
return nil
}
func (s *Server) handleDefaultApp(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/apps/"+s.defaultWebApp, http.StatusTemporaryRedirect)
}
type AppsResponse struct {
Apps []App
}
type App struct { type App struct {
ID string `json:"id"` ID string `json:"id"`
Title map[string]string `json:"title"` Title map[string]string `json:"title"`
Description map[string]string `json:"description"` Description map[string]string `json:"description"`
Icon string `json:"icon"` Icon string `json:"icon"`
FS fs.FS `json:"-"`
Hidden bool `json:"hidden"`
}
func (s *Server) handleDefaultApp(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/apps/"+s.defaultApp+"/", http.StatusTemporaryRedirect)
} }
func (s *Server) handleApps(w http.ResponseWriter, r *http.Request) { func (s *Server) handleApps(w http.ResponseWriter, r *http.Request) {
@ -85,7 +30,34 @@ func (s *Server) handleApps(w http.ResponseWriter, r *http.Request) {
DefaultApp string `json:"defaultApp"` DefaultApp string `json:"defaultApp"`
Apps []App `json:"apps"` Apps []App `json:"apps"`
}{ }{
DefaultApp: s.defaultWebApp, DefaultApp: s.defaultApp,
Apps: apps, Apps: s.apps,
}) })
} }
var (
indexedAppFilesystems map[string]fs.FS
indexAppsOnce sync.Once
)
func (s *Server) handleAppFilesystem(w http.ResponseWriter, r *http.Request) {
indexAppsOnce.Do(func() {
indexedAppFilesystems = make(map[string]fs.FS, len(s.apps))
for _, app := range s.apps {
indexedAppFilesystems[app.ID] = app.FS
}
})
appID := chi.URLParam(r, "appID")
fs, exists := indexedAppFilesystems[appID]
if !exists {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return
}
name := strings.TrimPrefix(r.URL.Path, "/apps/"+appID)
http.ServeFileFS(w, r, fs, name)
}

View File

@ -1,19 +0,0 @@
fetch('/api/v1/apps')
.then(res => res.json())
.then(res => {
const defaultApp = res.data.defaultApp
const apps = res.data.apps
const container = document.createElement("div")
container.className = "container"
apps.forEach(app => {
if (app.id === defaultApp) return
const appLink = document.createElement("a")
appLink.className = "app-link"
appLink.href = "/apps/" + app.id
appLink.innerText = app.title['fr']
container.appendChild(appLink)
})
document.getElementById("main").replaceWith(container);
})

View File

@ -35,7 +35,7 @@ func init() {
func (s *Server) startHTTPServer(ctx context.Context) error { func (s *Server) startHTTPServer(ctx context.Context) error {
router := chi.NewRouter() router := chi.NewRouter()
if s.webApps { if s.appsEnabled {
ips, err := getLANIPv4Addrs() ips, err := getLANIPv4Addrs()
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
@ -59,10 +59,10 @@ func (s *Server) startHTTPServer(ctx context.Context) error {
router.Delete("/api/v1/cast", s.handleReset) router.Delete("/api/v1/cast", s.handleReset)
router.Get("/api/v1/status", s.handleStatus) router.Get("/api/v1/status", s.handleStatus)
if s.webApps { if s.appsEnabled {
router.Get("/apps", s.handleDefaultApp) router.Get("/apps", s.handleDefaultApp)
router.Get("/api/v1/apps", s.handleApps) router.Get("/api/v1/apps", s.handleApps)
router.Handle("/apps/*", http.FileServer(http.FS(appsFS))) router.Handle("/apps/{appID}/*", http.HandlerFunc(s.handleAppFilesystem))
} }
server := http.Server{ server := http.Server{
@ -193,10 +193,10 @@ func (s *Server) handleStatus(w http.ResponseWriter, r *http.Request) {
func (s *Server) handleHome(w http.ResponseWriter, r *http.Request) { func (s *Server) handleHome(w http.ResponseWriter, r *http.Request) {
type templateData struct { type templateData struct {
IPs []string IPs []string
Port int Port int
ID string ID string
WebApps bool Apps bool
} }
ips, err := getLANIPv4Addrs() ips, err := getLANIPv4Addrs()
@ -207,10 +207,10 @@ func (s *Server) handleHome(w http.ResponseWriter, r *http.Request) {
} }
d := templateData{ d := templateData{
ID: s.instanceID, ID: s.instanceID,
IPs: ips, IPs: ips,
Port: s.port, Port: s.port,
WebApps: s.webApps, Apps: s.appsEnabled,
} }
if err := idleTemplate.Execute(w, d); err != nil { if err := idleTemplate.Execute(w, d); err != nil {

View File

@ -17,22 +17,24 @@ func init() {
} }
type Options struct { type Options struct {
InstanceID string InstanceID string
Address string Address string
DisableServiceDiscovery bool EnableServiceDiscovery bool
WebApps bool EnableApps bool
DefaultWebApp string DefaultApp string
Apps []App
} }
type OptionFunc func(opts *Options) type OptionFunc func(opts *Options)
func NewOptions(funcs ...OptionFunc) *Options { func NewOptions(funcs ...OptionFunc) *Options {
opts := &Options{ opts := &Options{
InstanceID: NewRandomInstanceID(), InstanceID: NewRandomInstanceID(),
Address: ":", Address: ":",
DisableServiceDiscovery: false, EnableServiceDiscovery: true,
WebApps: false, EnableApps: false,
DefaultWebApp: "home", DefaultApp: "",
Apps: make([]App, 0),
} }
for _, fn := range funcs { for _, fn := range funcs {
@ -42,9 +44,21 @@ func NewOptions(funcs ...OptionFunc) *Options {
return opts return opts
} }
func WithWebApps(enabled bool) OptionFunc { func WithAppsEnabled(enabled bool) OptionFunc {
return func(opts *Options) { return func(opts *Options) {
opts.WebApps = enabled opts.EnableApps = enabled
}
}
func WithDefaultApp(defaultApp string) OptionFunc {
return func(opts *Options) {
opts.DefaultApp = defaultApp
}
}
func WithApps(apps ...App) OptionFunc {
return func(opts *Options) {
opts.Apps = apps
} }
} }
@ -60,9 +74,9 @@ func WithInstanceID(id string) OptionFunc {
} }
} }
func WithServiceDiscoveryDisabled(disabled bool) OptionFunc { func WithServiceDiscoveryEnabled(enabled bool) OptionFunc {
return func(opts *Options) { return func(opts *Options) {
opts.DisableServiceDiscovery = disabled opts.EnableServiceDiscovery = enabled
} }
} }

View File

@ -11,13 +11,15 @@ import (
type Server struct { type Server struct {
browser browser.Browser browser browser.Browser
instanceID string instanceID string
address string address string
port int port int
disableServiceDiscovery bool
webApps bool serviceDiscoveryEnabled bool
defaultWebApp string
appsEnabled bool
defaultApp string
apps []App
ctx context.Context ctx context.Context
cancel context.CancelFunc cancel context.CancelFunc
@ -35,7 +37,7 @@ func (s *Server) Start() error {
return errors.WithStack(err) return errors.WithStack(err)
} }
if !s.disableServiceDiscovery { if s.serviceDiscoveryEnabled {
mdnsServerCtx, cancelMDNSServer := context.WithCancel(serverCtx) mdnsServerCtx, cancelMDNSServer := context.WithCancel(serverCtx)
if err := s.startMDNServer(mdnsServerCtx); err != nil { if err := s.startMDNServer(mdnsServerCtx); err != nil {
cancelHTTPServer() cancelHTTPServer()
@ -74,8 +76,9 @@ func New(browser browser.Browser, funcs ...OptionFunc) *Server {
browser: browser, browser: browser,
instanceID: opts.InstanceID, instanceID: opts.InstanceID,
address: opts.Address, address: opts.Address,
webApps: opts.WebApps, appsEnabled: opts.EnableApps,
defaultWebApp: opts.DefaultWebApp, defaultApp: opts.DefaultApp,
disableServiceDiscovery: opts.DisableServiceDiscovery, apps: opts.Apps,
serviceDiscoveryEnabled: opts.EnableServiceDiscovery,
} }
} }

View File

@ -99,12 +99,12 @@
<li><code>{{ . }}:{{ $port }}</code></li> <li><code>{{ . }}:{{ $port }}</code></li>
{{end}} {{end}}
</ul> </ul>
{{if .WebApps }} {{if .Apps }}
<p>Apps:</p> <p>Apps:</p>
<ul class="text-italic text-small"> <ul class="text-italic text-small">
{{ $port := .Port }} {{ $port := .Port }}
{{range .IPs}} {{range .IPs}}
<li><a href="http://{{ . }}:{{ $port }}/apps">http://{{ . }}:{{ $port }}/apps</a></li> <li><a target="_blank" href="http://{{ . }}:{{ $port }}/apps">http://{{ . }}:{{ $port }}/apps</a></li>
{{end}} {{end}}
</ul> </ul>
{{end}} {{end}}