mirror of
https://github.com/m1k1o/neko-rooms.git
synced 2026-11-02 22:51:34 -06:00
add room wait handler.
This commit is contained in:
@@ -6,6 +6,40 @@ import (
|
||||
"github.com/m1k1o/neko-rooms/internal/utils"
|
||||
)
|
||||
|
||||
func roomWait(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(`<script>
|
||||
(async function() {
|
||||
document.querySelector(".swal2-loader").style.display = 'block'
|
||||
document.querySelector(".swal2-loader").style.visibility = 'hidden'
|
||||
|
||||
let lastAttempt = (new Date()).getTime()
|
||||
while(true) {
|
||||
try {
|
||||
lastAttempt = (new Date()).getTime()
|
||||
document.querySelector(".swal2-loader").style.visibility = 'visible'
|
||||
|
||||
await fetch("?wait")
|
||||
location.href = location.href
|
||||
} catch {
|
||||
let now = (new Date()).getTime()
|
||||
let diff = now - lastAttempt
|
||||
|
||||
// if the gap between last attempt and now
|
||||
// is gt 20s, do reconnect immediatly
|
||||
if ((now - lastAttempt) > 20*1000) {
|
||||
continue
|
||||
}
|
||||
|
||||
// wait for 10 sec
|
||||
await new Promise(res => setTimeout(res, 2500))
|
||||
document.querySelector(".swal2-loader").style.visibility = 'hidden'
|
||||
await new Promise(res => setTimeout(res, 7500))
|
||||
}
|
||||
}
|
||||
}())
|
||||
</script>`))
|
||||
}
|
||||
|
||||
func RoomNotFound(w http.ResponseWriter, r *http.Request) {
|
||||
utils.Swal2Response(w, `
|
||||
<div class="swal2-header">
|
||||
@@ -16,8 +50,14 @@ func RoomNotFound(w http.ResponseWriter, r *http.Request) {
|
||||
</div>
|
||||
<div class="swal2-content">
|
||||
<div>The room you are trying to join does not exist.</div>
|
||||
<div>You can wait on this page until it will be created.</div>
|
||||
</div>
|
||||
<div class="swal2-actions">
|
||||
<div class="swal2-loader" style="display:none;"></div>
|
||||
</div>
|
||||
`)
|
||||
|
||||
roomWait(w, r)
|
||||
}
|
||||
|
||||
func RoomNotRunning(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -30,8 +70,14 @@ func RoomNotRunning(w http.ResponseWriter, r *http.Request) {
|
||||
</div>
|
||||
<div class="swal2-content">
|
||||
<div>The room you are trying to join is not running.</div>
|
||||
<div>You can wait on this page until it will be started.</div>
|
||||
</div>
|
||||
<div class="swal2-actions">
|
||||
<div class="swal2-loader" style="display:none;"></div>
|
||||
</div>
|
||||
`)
|
||||
|
||||
roomWait(w, r)
|
||||
}
|
||||
|
||||
func RoomNotReady(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -23,12 +24,20 @@ type entry struct {
|
||||
handler *httputil.ReverseProxy
|
||||
}
|
||||
|
||||
type wait struct {
|
||||
subs int
|
||||
signal chan struct{}
|
||||
}
|
||||
|
||||
type ProxyManagerCtx struct {
|
||||
logger zerolog.Logger
|
||||
mu sync.RWMutex
|
||||
ctx context.Context
|
||||
cancel func()
|
||||
|
||||
waitMu sync.RWMutex
|
||||
waitChans map[string]*wait
|
||||
|
||||
client *dockerClient.Client
|
||||
instanceName string
|
||||
handlers *prefixHandler[*entry]
|
||||
@@ -36,7 +45,8 @@ type ProxyManagerCtx struct {
|
||||
|
||||
func New(client *dockerClient.Client, instanceName string) *ProxyManagerCtx {
|
||||
return &ProxyManagerCtx{
|
||||
logger: log.With().Str("module", "proxy").Logger(),
|
||||
logger: log.With().Str("module", "proxy").Logger(),
|
||||
waitChans: map[string]*wait{},
|
||||
|
||||
client: client,
|
||||
instanceName: instanceName,
|
||||
@@ -83,6 +93,15 @@ func (p *ProxyManagerCtx) Start() {
|
||||
Str("host", host).
|
||||
Msg("got docker event")
|
||||
|
||||
// terminate waiting for any events
|
||||
p.waitMu.Lock()
|
||||
ch, ok := p.waitChans[path]
|
||||
if ok {
|
||||
close(ch.signal)
|
||||
delete(p.waitChans, path)
|
||||
}
|
||||
p.waitMu.Unlock()
|
||||
|
||||
p.mu.Lock()
|
||||
switch msg.Action {
|
||||
case "create":
|
||||
@@ -222,27 +241,75 @@ func (p *ProxyManagerCtx) parseLabels(labels map[string]string) (enabled bool, p
|
||||
return
|
||||
}
|
||||
|
||||
func (p *ProxyManagerCtx) waitForPath(w http.ResponseWriter, r *http.Request, path string) {
|
||||
p.logger.Debug().Str("path", path).Msg("adding new wait handler")
|
||||
|
||||
p.waitMu.Lock()
|
||||
ch, ok := p.waitChans[path]
|
||||
if !ok {
|
||||
ch = &wait{
|
||||
subs: 1,
|
||||
signal: make(chan struct{}),
|
||||
}
|
||||
p.waitChans[path] = ch
|
||||
} else {
|
||||
p.waitChans[path].subs += 1
|
||||
}
|
||||
p.waitMu.Unlock()
|
||||
|
||||
select {
|
||||
case <-ch.signal:
|
||||
w.Write([]byte("ready"))
|
||||
case <-r.Context().Done():
|
||||
http.Error(w, r.Context().Err().Error(), http.StatusRequestTimeout)
|
||||
|
||||
p.waitMu.Lock()
|
||||
ch.subs -= 1
|
||||
if ch.subs <= 0 {
|
||||
delete(p.waitChans, path)
|
||||
}
|
||||
p.waitMu.Unlock()
|
||||
p.logger.Debug().Str("path", path).Msg("wait handler removed")
|
||||
case <-p.ctx.Done():
|
||||
w.Write([]byte("shutdown"))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ProxyManagerCtx) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
cleanPath := path.Clean(r.URL.Path)
|
||||
|
||||
// get proxy by room name
|
||||
p.mu.RLock()
|
||||
proxy, prefix, ok := p.handlers.Match(r.URL.Path)
|
||||
proxy, prefix, ok := p.handlers.Match(cleanPath)
|
||||
p.mu.RUnlock()
|
||||
|
||||
// if room not found
|
||||
if !ok {
|
||||
// blocking until room is created
|
||||
if r.URL.Query().Has("wait") {
|
||||
p.waitForPath(w, r, cleanPath)
|
||||
return
|
||||
}
|
||||
|
||||
RoomNotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// redirect to room ending with /
|
||||
if r.URL.Path == prefix {
|
||||
r.URL.Path += "/"
|
||||
if cleanPath == prefix && !strings.HasSuffix(r.URL.Path, "/") {
|
||||
r.URL.Path = cleanPath + "/"
|
||||
http.Redirect(w, r, r.URL.String(), http.StatusTemporaryRedirect)
|
||||
return
|
||||
}
|
||||
|
||||
// if room not running
|
||||
if !proxy.running {
|
||||
// blocking until room is running
|
||||
if r.URL.Query().Has("wait") {
|
||||
p.waitForPath(w, r, cleanPath)
|
||||
return
|
||||
}
|
||||
|
||||
RoomNotRunning(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user