Choose the hub: Settings' choice, else the install's channel's; state kept per hub
CI / build (push) Successful in 18s
CI / build (push) Successful in 18s
The client's Settings > T5DE chooses the hub from the next start on (POST /hub/server, kept in server.json); without a choice, -channel (which the client passes) decides: staging for nightly and dev, T5DE's hub for releases. $T5DE_HUB still wins. Each hub's sign-in, product IDs and products are kept in their own folder (T5DE's hub in the data folder as before, others in hubs/<host>), so a hub never gets another's token and product IDs from two hubs never clash; a sign-in saved for another hub is ignored. Signing in always goes to this run's hub. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
8daf91ede3
commit
8ae45fc07a
6 files changed
+292
-53
No files matched your search
+42
-24
@@ -2,9 +2,10 @@
|
||||
// change it: requests to http://t5de-proxy.local/ (only the client can make them: they need the proxy's token)
|
||||
// are answered here.
|
||||
//
|
||||
// GET /hub {signedIn, hub, username, signingIn, code, page, error}
|
||||
// POST /hub/signin starts signing in (hub=<URL> optional): opens the hub's page for the code in the browser
|
||||
// GET /hub {signedIn, hub, username, signingIn, code, page, error, choice, default, fixed, restart}
|
||||
// POST /hub/signin starts signing in to this run's hub: opens the hub's page for the code in the browser
|
||||
// POST /hub/signout signs this computer out
|
||||
// POST /hub/server hub=<URL>, or empty for the install's default: the hub from the next start on (restart)
|
||||
// POST /badges {"imvuIds": [...]} -> {"badges": [...]}: which of those IMVU accounts show the T5 badge (their
|
||||
// T5DE users opted in), from the hub, remembered for a while
|
||||
package control
|
||||
@@ -29,9 +30,12 @@ const Host = "t5de-proxy.local"
|
||||
|
||||
// Manager keeps the hub connection running and answers the client's settings page.
|
||||
type Manager struct {
|
||||
Path string // hub.json
|
||||
DefaultHub string
|
||||
Log *log.Logger
|
||||
Path string // hub.json, in the hub's state folder (StateDir)
|
||||
// Hub is this run's hub (Server); Default the install's (ChannelDefault); ChoicePath where the person's
|
||||
// choice is kept. Fixed means $T5DE_HUB chose it, so the choice can't.
|
||||
Hub, Default, ChoicePath string
|
||||
Fixed bool
|
||||
Log *log.Logger
|
||||
// Attach is called with each new hub client before it runs (to connect it to the rest of the proxy).
|
||||
Attach func(c *hub.Client)
|
||||
// OpenBrowser opens a page in the person's browser.
|
||||
@@ -42,7 +46,6 @@ type Manager struct {
|
||||
saved *hub.Saved
|
||||
stop context.CancelFunc
|
||||
username string
|
||||
lastHub string // the hub last signed in to, for signing in again after signing out
|
||||
signin *signin
|
||||
badges map[int64]badgeAnswer
|
||||
}
|
||||
@@ -125,6 +128,11 @@ func (m *Manager) Start() {
|
||||
}
|
||||
return
|
||||
}
|
||||
if saved.URL != m.Hub {
|
||||
// Signed in to another hub (by an older proxy, before hubs had their own folders): not this run's.
|
||||
m.Log.Printf("hub: the sign-in is for %s, not %s; signed out", saved.URL, m.Hub)
|
||||
return
|
||||
}
|
||||
m.run(saved)
|
||||
}
|
||||
|
||||
@@ -168,17 +176,23 @@ type status struct {
|
||||
Code string `json:"code"`
|
||||
Page string `json:"page"`
|
||||
Error string `json:"error"`
|
||||
Choice string `json:"choice"` // the hub chosen for the next start, "" for the default
|
||||
Default string `json:"default"` // the install's
|
||||
Fixed bool `json:"fixed"` // chosen by $T5DE_HUB
|
||||
Restart bool `json:"restart"` // the next start's hub isn't this run's
|
||||
}
|
||||
|
||||
func (m *Manager) status() status {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
s := status{Hub: m.DefaultHub}
|
||||
if m.lastHub != "" {
|
||||
s.Hub = m.lastHub
|
||||
s := status{Hub: m.Hub, Default: m.Default, Fixed: m.Fixed, Choice: LoadChoice(m.ChoicePath)}
|
||||
next := s.Choice
|
||||
if next == "" {
|
||||
next = m.Default
|
||||
}
|
||||
s.Restart = !m.Fixed && next != m.Hub
|
||||
if m.saved != nil {
|
||||
s.SignedIn, s.Hub, s.Username = true, m.saved.URL, m.username
|
||||
s.SignedIn, s.Username = true, m.username
|
||||
}
|
||||
if si := m.signin; si != nil {
|
||||
s.SigningIn, s.Code, s.Page, s.Error = si.running, si.code, si.page, si.err
|
||||
@@ -186,11 +200,10 @@ func (m *Manager) status() status {
|
||||
return s
|
||||
}
|
||||
|
||||
// SignIn starts signing in to a hub; the code to enter shows in the status, and the browser opens the page.
|
||||
func (m *Manager) SignIn(hubURL string) {
|
||||
if hubURL == "" {
|
||||
hubURL = m.status().Hub
|
||||
}
|
||||
// SignIn starts signing in to this run's hub; the code to enter shows in the status, and the browser opens the
|
||||
// page.
|
||||
func (m *Manager) SignIn() {
|
||||
hubURL := m.Hub
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
si := &signin{running: true, cancel: cancel}
|
||||
m.mu.Lock()
|
||||
@@ -230,9 +243,6 @@ func (m *Manager) SignIn(hubURL string) {
|
||||
func (m *Manager) SignOut() {
|
||||
m.mu.Lock()
|
||||
c, stop := m.client, m.stop
|
||||
if m.saved != nil {
|
||||
m.lastHub = m.saved.URL
|
||||
}
|
||||
m.client, m.saved, m.stop, m.username, m.signin, m.badges = nil, nil, nil, "", nil, nil
|
||||
m.mu.Unlock()
|
||||
if c != nil {
|
||||
@@ -256,16 +266,24 @@ func (m *Manager) Intercept(x *proxy.Exchange) error {
|
||||
switch {
|
||||
case x.URL.Path == "/hub" && method == "GET":
|
||||
case x.URL.Path == "/hub/signin" && method == "POST":
|
||||
m.SignIn()
|
||||
case x.URL.Path == "/hub/server" && method == "POST":
|
||||
form, _ := url.ParseQuery(string(x.Body))
|
||||
hubURL := strings.TrimSuffix(form.Get("hub"), "/")
|
||||
if hubURL != "" {
|
||||
u, err := url.Parse(hubURL)
|
||||
if err != nil || (u.Scheme != "https" && u.Hostname() != "localhost" && u.Hostname() != "127.0.0.1") {
|
||||
x.Response = proxy.LocalResponse(400, "application/json", []byte(`{"error":"the hub needs an https address"}`))
|
||||
hub := form.Get("hub")
|
||||
if hub != "" {
|
||||
var err error
|
||||
if hub, err = CheckHub(hub); err != nil {
|
||||
b, _ := json.Marshal(map[string]string{"error": err.Error()})
|
||||
x.Response = proxy.LocalResponse(400, "application/json", b)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
m.SignIn(hubURL)
|
||||
if hub == m.Default {
|
||||
hub = "" // the default stays the default, should it change
|
||||
}
|
||||
if err := SaveChoice(m.ChoicePath, hub); err != nil {
|
||||
m.Log.Printf("hub: saving the choice: %v", err)
|
||||
}
|
||||
case x.URL.Path == "/hub/signout" && method == "POST":
|
||||
m.SignOut()
|
||||
case x.URL.Path == "/badges" && method == "POST":
|
||||
|
||||
Reference in new issue
Block a user