mirror of
https://github.com/m1k1o/neko-rooms.git
synced 2026-11-02 22:51:34 -06:00
replace lobby with proxy.
This commit is contained in:
@@ -1,35 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/m1k1o/neko-rooms/internal/proxy"
|
||||
)
|
||||
|
||||
func (manager *ApiManagerCtx) RoomLobby(w http.ResponseWriter, r *http.Request) {
|
||||
if !manager.conf.Lobby {
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
|
||||
roomName := chi.URLParam(r, "roomName")
|
||||
response, err := manager.rooms.FindByName(roomName)
|
||||
|
||||
if err != nil || response.Name != roomName {
|
||||
proxy.RoomNotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
if !response.Running {
|
||||
proxy.RoomNotRunning(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
if strings.Contains(response.Status, "starting") {
|
||||
proxy.RoomNotReady(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
proxy.RoomReady(w, r)
|
||||
}
|
||||
+92
-23
@@ -6,6 +6,8 @@ import (
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
dockerTypes "github.com/docker/docker/api/types"
|
||||
@@ -15,6 +17,11 @@ import (
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type entry struct {
|
||||
running bool
|
||||
handler *httputil.ReverseProxy
|
||||
}
|
||||
|
||||
type ProxyManagerCtx struct {
|
||||
logger zerolog.Logger
|
||||
mu sync.RWMutex
|
||||
@@ -23,7 +30,7 @@ type ProxyManagerCtx struct {
|
||||
|
||||
client *dockerClient.Client
|
||||
instanceName string
|
||||
handlers *prefixHandler[*httputil.ReverseProxy]
|
||||
handlers *prefixHandler[*entry]
|
||||
}
|
||||
|
||||
func New(client *dockerClient.Client, instanceName string) *ProxyManagerCtx {
|
||||
@@ -32,7 +39,7 @@ func New(client *dockerClient.Client, instanceName string) *ProxyManagerCtx {
|
||||
|
||||
client: client,
|
||||
instanceName: instanceName,
|
||||
handlers: &prefixHandler[*httputil.ReverseProxy]{},
|
||||
handlers: &prefixHandler[*entry]{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +56,6 @@ func (p *ProxyManagerCtx) Start() {
|
||||
Filters: filters.NewArgs(
|
||||
filters.Arg("type", "container"),
|
||||
filters.Arg("label", fmt.Sprintf("m1k1o.neko_rooms.instance=%s", p.instanceName)),
|
||||
filters.Arg("label", "m1k1o.neko_rooms.proxy=true"),
|
||||
filters.Arg("event", "create"),
|
||||
filters.Arg("event", "start"),
|
||||
//filters.Arg("event", "health_status"),
|
||||
@@ -63,7 +69,7 @@ func (p *ProxyManagerCtx) Start() {
|
||||
case err := <-errs:
|
||||
p.logger.Info().Interface("err", err).Msg("eee")
|
||||
case msg := <-msgs:
|
||||
path, port, ok := p.parseLabels(msg.Actor.Attributes)
|
||||
enabled, path, port, ok := p.parseLabels(msg.Actor.Attributes)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
@@ -79,16 +85,27 @@ func (p *ProxyManagerCtx) Start() {
|
||||
p.mu.Lock()
|
||||
switch msg.Action {
|
||||
case "create":
|
||||
p.handlers.Set(path, nil)
|
||||
case "start":
|
||||
proxy := httputil.NewSingleHostReverseProxy(&url.URL{
|
||||
Scheme: "http",
|
||||
Host: host,
|
||||
p.handlers.Set(path, &entry{
|
||||
running: false,
|
||||
})
|
||||
case "start":
|
||||
e := &entry{
|
||||
running: true,
|
||||
}
|
||||
|
||||
p.handlers.Set(path, proxy)
|
||||
// if proxying is disabled
|
||||
if enabled {
|
||||
e.handler = httputil.NewSingleHostReverseProxy(&url.URL{
|
||||
Scheme: "http",
|
||||
Host: host,
|
||||
})
|
||||
}
|
||||
|
||||
p.handlers.Set(path, e)
|
||||
case "stop":
|
||||
p.handlers.Set(path, nil)
|
||||
p.handlers.Set(path, &entry{
|
||||
running: false,
|
||||
})
|
||||
case "destroy":
|
||||
p.handlers.Remove(path)
|
||||
}
|
||||
@@ -118,31 +135,77 @@ func (p *ProxyManagerCtx) Refresh() error {
|
||||
return err
|
||||
}
|
||||
|
||||
p.handlers = &prefixHandler[*httputil.ReverseProxy]{}
|
||||
p.handlers = &prefixHandler[*entry]{}
|
||||
|
||||
for _, cont := range containers {
|
||||
path, port, ok := p.parseLabels(cont.Labels)
|
||||
enabled, path, port, ok := p.parseLabels(cont.Labels)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
host := cont.ID[:12] + ":" + port
|
||||
|
||||
var proxy *httputil.ReverseProxy
|
||||
entry := &entry{}
|
||||
if cont.State == "running" {
|
||||
proxy = httputil.NewSingleHostReverseProxy(&url.URL{
|
||||
Scheme: "http",
|
||||
Host: host,
|
||||
})
|
||||
entry.running = true
|
||||
|
||||
// if proxying is disabled
|
||||
if enabled {
|
||||
entry.handler = httputil.NewSingleHostReverseProxy(&url.URL{
|
||||
Scheme: "http",
|
||||
Host: host,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
p.handlers.Set(path, proxy)
|
||||
p.handlers.Set(path, entry)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ProxyManagerCtx) parseLabels(labels map[string]string) (path string, port string, ok bool) {
|
||||
func (p *ProxyManagerCtx) parseLabels(labels map[string]string) (enabled bool, path string, port string, ok bool) {
|
||||
enabledStr, found := labels["m1k1o.neko_rooms.proxy.enabled"]
|
||||
if !found {
|
||||
//
|
||||
// workaround for legacy traefik labels
|
||||
//
|
||||
|
||||
// get room name
|
||||
var roomName string
|
||||
roomName, ok = labels["m1k1o.neko_rooms.name"]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// get container name
|
||||
containerName := p.instanceName + "-" + roomName
|
||||
|
||||
// get path
|
||||
path, ok = labels["traefik.http.middlewares."+containerName+"-prf.stripprefix.prefixes"]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// remove last /
|
||||
path = strings.TrimSuffix(path, "/")
|
||||
|
||||
// get port
|
||||
port, ok = labels["traefik.http.services."+containerName+"-frontend.loadbalancer.server.port"]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
// workaround for legacy traefik labels
|
||||
//
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
enabledBool, err := strconv.ParseBool(enabledStr)
|
||||
enabled = enabledBool && err == nil
|
||||
|
||||
path, ok = labels["m1k1o.neko_rooms.proxy.path"]
|
||||
if !ok {
|
||||
return
|
||||
@@ -172,13 +235,19 @@ func (p *ProxyManagerCtx) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// if room not running
|
||||
if proxy == nil {
|
||||
if !proxy.running {
|
||||
RoomNotRunning(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// if not proxying
|
||||
if proxy.handler == nil {
|
||||
RoomReady(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// handle not ready room
|
||||
proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
|
||||
proxy.handler.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
|
||||
if r.URL.Path == "/" {
|
||||
RoomNotReady(w, r)
|
||||
}
|
||||
@@ -187,7 +256,7 @@ func (p *ProxyManagerCtx) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// strip prefix from proxy
|
||||
handler := http.StripPrefix(prefix, proxy)
|
||||
handler := http.StripPrefix(prefix, proxy.handler)
|
||||
|
||||
// handle by proxy
|
||||
handler.ServeHTTP(w, r)
|
||||
|
||||
@@ -41,6 +41,37 @@ func (p *prefixHandler[T]) Set(prefix string, value T) {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *prefixHandler[T]) Get(prefix string) (value T, ok bool) {
|
||||
arr := strings.Split(prefix, "/")
|
||||
len := len(arr)
|
||||
|
||||
for i, a := range arr {
|
||||
if a == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if p.Children == nil {
|
||||
p.Children = map[string]*prefixHandler[T]{}
|
||||
}
|
||||
|
||||
dat, found := p.Children[a]
|
||||
if !found {
|
||||
dat = &prefixHandler[T]{}
|
||||
}
|
||||
|
||||
if i == len-1 {
|
||||
value = dat.Value
|
||||
ok = dat.Children == nil
|
||||
return
|
||||
}
|
||||
|
||||
p.Children[a] = dat
|
||||
p = dat
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (p *prefixHandler[T]) Remove(prefix string) {
|
||||
arr := strings.Split(prefix, "/")
|
||||
len := len(arr)
|
||||
@@ -54,8 +85,8 @@ func (p *prefixHandler[T]) Remove(prefix string) {
|
||||
delete(p.Children, a)
|
||||
}
|
||||
|
||||
dat, ok := p.Children[a]
|
||||
if !ok {
|
||||
dat, found := p.Children[a]
|
||||
if !found {
|
||||
break
|
||||
}
|
||||
p = dat
|
||||
|
||||
@@ -217,7 +217,7 @@ func (manager *RoomManagerCtx) Create(settings types.RoomSettings) (string, erro
|
||||
labels["traefik.http.routers."+containerName+".tls.certresolver"] = t.Certresolver
|
||||
}
|
||||
} else {
|
||||
labels["m1k1o.neko_rooms.proxy"] = "true"
|
||||
labels["m1k1o.neko_rooms.proxy.enabled"] = "true"
|
||||
labels["m1k1o.neko_rooms.proxy.path"] = pathPrefix
|
||||
labels["m1k1o.neko_rooms.proxy.port"] = fmt.Sprintf("%d", frontendPort)
|
||||
}
|
||||
|
||||
+12
-24
@@ -55,20 +55,6 @@ func New(ApiManager types.ApiManager, roomConfig *config.Room, config *config.Se
|
||||
logger.Info().Msgf("with pprof endpoint at %s", pprofPath)
|
||||
}
|
||||
|
||||
//
|
||||
// rooms page
|
||||
//
|
||||
|
||||
router.Group(func(r chi.Router) {
|
||||
if !roomConfig.Traefik.Enabled {
|
||||
r.Handle("/*", proxyHandler)
|
||||
} else {
|
||||
// add simple lobby room
|
||||
r.Get("/{roomName}", ApiManager.RoomLobby)
|
||||
r.Get("/{roomName}/", ApiManager.RoomLobby)
|
||||
}
|
||||
})
|
||||
|
||||
//
|
||||
// admin page
|
||||
//
|
||||
@@ -94,25 +80,27 @@ func New(ApiManager types.ApiManager, roomConfig *config.Room, config *config.Se
|
||||
|
||||
// serve static files
|
||||
if config.Admin.Static != "" {
|
||||
prefix := config.Admin.PathPrefix
|
||||
dir := http.Dir(config.Admin.Static)
|
||||
fs := http.FileServer(http.Dir(config.Admin.Static))
|
||||
fs = http.StripPrefix(config.Admin.PathPrefix, fs)
|
||||
|
||||
fs := http.FileServer(dir)
|
||||
fs = http.StripPrefix(prefix, fs)
|
||||
|
||||
router.Handle(prefix+"/", fs)
|
||||
router.Handle(path.Join("/", config.Admin.PathPrefix, "*"), fs)
|
||||
}
|
||||
})
|
||||
|
||||
// redirect / to admin path prefix
|
||||
if config.Admin.PathPrefix != "/" {
|
||||
// redirect / to admin path prefix
|
||||
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, strings.TrimPrefix(config.Admin.PathPrefix, "/"), http.StatusTemporaryRedirect)
|
||||
http.Redirect(w, r, strings.TrimPrefix(config.Admin.PathPrefix, "/")+"/", http.StatusTemporaryRedirect)
|
||||
})
|
||||
|
||||
// redirect force admin path prefix ending with /
|
||||
router.Get(config.Admin.PathPrefix, func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, strings.TrimPrefix(config.Admin.PathPrefix, "/")+"/", http.StatusTemporaryRedirect)
|
||||
})
|
||||
}
|
||||
|
||||
// we could use custom 404
|
||||
router.NotFound(http.NotFound)
|
||||
// handle all remaining paths with proxy
|
||||
router.Handle("/*", proxyHandler)
|
||||
|
||||
return &ServerManagerCtx{
|
||||
logger: logger,
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
)
|
||||
|
||||
type ApiManager interface {
|
||||
Mount(r chi.Router)
|
||||
|
||||
RoomLobby(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user