Hosted rooms (internal/hosted): room calls for them answered here, their IMQ queues served (a new proxy.IMQRouter hook takes them out of subscriptions to IMVU), chat relayed through the hub's WebSocket (hub.Client gains Send, OnRoom and OnConnect), the room list extended, room products checked against the real owner, and anything else naming a hosted room kept from IMVU. T5DE_INSTANCE gives a second client's proxy its own data folder and log. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
455dae1013
commit
d8332b21a8
12 files changed
+1492
-12
No files matched your search
+60
-2
@@ -17,6 +17,7 @@ import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -29,12 +30,15 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.t5de.dev/t5de/t5de-proxy/internal/buildinfo"
|
||||
"git.t5de.dev/t5de/t5de-proxy/internal/control"
|
||||
"git.t5de.dev/t5de/t5de-proxy/internal/fetch"
|
||||
"git.t5de.dev/t5de/t5de-proxy/internal/hosted"
|
||||
"git.t5de.dev/t5de/t5de-proxy/internal/hub"
|
||||
"git.t5de.dev/t5de/t5de-proxy/internal/imq"
|
||||
"git.t5de.dev/t5de/t5de-proxy/internal/parent"
|
||||
"git.t5de.dev/t5de/t5de-proxy/internal/products"
|
||||
"git.t5de.dev/t5de/t5de-proxy/internal/proxy"
|
||||
@@ -55,7 +59,7 @@ func main() {
|
||||
trace := flag.Bool("trace", false, "log full URLs and every IMQ frame")
|
||||
packs := flag.String("packs", "", "community product packs: directories of packs, separated by "+string(filepath.ListSeparator)+
|
||||
" (default: %APPDATA%/T5DE/packs and $T5DE_PACKS)")
|
||||
data := flag.String("data", "", "where the proxy keeps its state (default: %APPDATA%/T5DE/proxy)")
|
||||
data := flag.String("data", "", "where the proxy keeps its state (default: %APPDATA%/T5DE/proxy, or T5DE-<n> for $T5DE_INSTANCE)")
|
||||
version := flag.Bool("version", false, "print the version and exit")
|
||||
flag.Parse()
|
||||
if *version {
|
||||
@@ -65,6 +69,10 @@ func main() {
|
||||
|
||||
var out io.Writer = os.Stderr
|
||||
if *logFile != "" {
|
||||
if instance := os.Getenv("T5DE_INSTANCE"); instance != "" {
|
||||
// Another client beside the usual one (its T5DE_INSTANCE): its own log.
|
||||
*logFile = strings.TrimSuffix(*logFile, ".log") + "-" + instance + ".log"
|
||||
}
|
||||
f, err := os.Create(*logFile)
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
@@ -96,6 +104,9 @@ func dataDir(flagValue string) string {
|
||||
return flagValue
|
||||
}
|
||||
if config, err := os.UserConfigDir(); err == nil {
|
||||
if instance := os.Getenv("T5DE_INSTANCE"); instance != "" {
|
||||
return filepath.Join(config, "T5DE-"+instance, "proxy") // the client's own data (its T5DE_INSTANCE)
|
||||
}
|
||||
return filepath.Join(config, "T5DE", "proxy")
|
||||
}
|
||||
return "."
|
||||
@@ -138,10 +149,25 @@ func run(logger *log.Logger, listen, ready string, parentPID int, trace bool, pa
|
||||
handler.Interceptor, handler.IMQFilter = prods, prods
|
||||
logger.Printf("community products from %s", strings.Join(packs, ", "))
|
||||
}
|
||||
// T5DE-hosted rooms (internal/hosted), served with the hub the proxy is signed in to.
|
||||
hubNow := &hubRef{}
|
||||
rooms := &hosted.Rooms{Hub: hubNow, Logf: logger.Printf}
|
||||
if prods != nil {
|
||||
prods.Hosted = rooms
|
||||
rooms.User, rooms.LocalProduct, rooms.GlobalProduct = prods.User, prods.LocalID, prods.ProductID
|
||||
prods.HostedOwner = rooms.Owner
|
||||
rooms.Deliver = func(c *proxy.IMQConn, m imq.Delivered) {
|
||||
m.Message = prods.Incoming(c, m)
|
||||
c.Deliver(m)
|
||||
}
|
||||
}
|
||||
// The hub connection, which the client's T5DE settings can sign in and out (internal/control).
|
||||
manager := &control.Manager{Path: filepath.Join(data, "hub.json"), DefaultHub: envOr("T5DE_HUB", defaultHub),
|
||||
Log: logger, OpenBrowser: openBrowser}
|
||||
manager.Attach = func(client *hub.Client) {
|
||||
hubNow.set(client)
|
||||
client.OnRoom, client.OnConnect = rooms.FromHub, rooms.Reconnected
|
||||
rooms.OnJoin, rooms.OnLeave = client.Join, client.Leave
|
||||
fetcher := fetch.New(client, hubProducts, logger.Printf)
|
||||
client.OnLibrary = func() { fetcher.SyncLibrary(context.Background()) }
|
||||
if prods == nil {
|
||||
@@ -168,7 +194,7 @@ func run(logger *log.Logger, listen, ready string, parentPID int, trace bool, pa
|
||||
}
|
||||
}
|
||||
manager.Start()
|
||||
chain := proxy.Interceptors{manager}
|
||||
chain := proxy.Interceptors{manager, rooms} // hosted rooms' calls before the products'
|
||||
if prods != nil {
|
||||
chain = append(chain, prods)
|
||||
}
|
||||
@@ -186,6 +212,38 @@ func run(logger *log.Logger, listen, ready string, parentPID int, trace bool, pa
|
||||
return server.Serve(ln)
|
||||
}
|
||||
|
||||
// hubRef is the hub client the proxy is signed in with, for the hosted rooms (none while signed out).
|
||||
type hubRef struct {
|
||||
mu sync.Mutex
|
||||
c *hub.Client
|
||||
}
|
||||
|
||||
func (h *hubRef) set(c *hub.Client) {
|
||||
h.mu.Lock()
|
||||
h.c = c
|
||||
h.mu.Unlock()
|
||||
}
|
||||
|
||||
func (h *hubRef) get() *hub.Client {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
return h.c
|
||||
}
|
||||
|
||||
func (h *hubRef) Send(v any) bool {
|
||||
if c := h.get(); c != nil {
|
||||
return c.Send(v)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *hubRef) Call(ctx context.Context, method, path string, body, out any) error {
|
||||
if c := h.get(); c != nil {
|
||||
return c.Call(ctx, method, path, body, out)
|
||||
}
|
||||
return errors.New("not signed in to T5DE's hub")
|
||||
}
|
||||
|
||||
func writeReady(path, address, token string) error {
|
||||
data, err := json.Marshal(map[string]string{"address": address, "token": token})
|
||||
if err != nil {
|
||||
|
||||
Reference in new issue
Block a user