Sign in to T5DE's hub and report presence and community outfits
CI / build (push) Successful in 1m6s

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
dhkatzandClaude Opus 5.5 committed 2026-10-29 03:45:55 -07:00
1 parent 50e4db8521
commit 7887eada61
9 files changed
+476 -2

No files matched your search

+7
View File
@@ -50,6 +50,11 @@ func (p *Products) interceptXMLRPC(x *proxy.Exchange) error {
case "test.avatarInfoForLogin2":
x.ModifyResponse = func(resp *http.Response, body []byte) ([]byte, error) {
p.keys.learn(body)
if m := userIDPattern.FindSubmatch(body); m != nil && p.Observer != nil {
if id, err := strconv.ParseInt(string(m[1]), 10, 64); err == nil {
p.Observer.Session(id)
}
}
return p.addToLook(body)
}
case "test.inventoryProductBatch":
@@ -90,6 +95,7 @@ func (p *Products) addToLook(body []byte) ([]byte, error) {
if mem.Name == "look" {
if look, ok := productList(mem.Value); ok {
if worn := p.wornLocal(user, look); len(worn) > 0 {
p.reportOutfit(user, worn)
v[i].Value = appendIDs(mem.Value.([]xmlrpc.Value), worn)
changed = true
}
@@ -401,6 +407,7 @@ func (p *Products) interceptBaseLook(x *proxy.Exchange) error {
return body, err
}
worn := p.wornLocal(user, ids)
p.reportOutfit(user, worn)
if len(worn) == 0 {
return body, nil
}
+30
View File
@@ -28,6 +28,7 @@ import (
"git.t5de.dev/t5de/t5de-api/cfl"
"git.t5de.dev/t5de/t5de-api/pack"
"git.t5de.dev/t5de/t5de-proxy/internal/hub"
)
// Products is the proxy's community products: an Interceptor for HTTP and an IMQFilter for chat.
@@ -42,6 +43,16 @@ type Products struct {
byLocal map[int64]*served
byID map[string]*served
problems map[string]string // pack directory -> last error logged
// Observer, if set, hears which IMVU account the client signs in as and the community products it wears (the
// hub client).
Observer Observer
}
// Observer hears about the client's IMVU account and its community outfit.
type Observer interface {
Session(imvuID int64)
Outfit(imvuID int64, items []hub.Item)
}
// served is a pack ready to serve.
@@ -268,6 +279,7 @@ func (p *Products) wornLocal(user string, look []int64) []int64 {
// recordWorn remembers the user's outfit: the IMVU products sent to IMVU, and the community products (local IDs)
// taken out.
func (p *Products) recordWorn(user string, imvu, locals []int64) {
p.reportOutfit(user, locals)
var ids []string
for _, local := range locals {
if id, ok := p.state.productID(local); ok {
@@ -280,3 +292,21 @@ func (p *Products) recordWorn(user string, imvu, locals []int64) {
}
var errNoKey = errors.New("products: can't re-sign the request (no session key yet)")
// reportOutfit tells the observer the community products (local IDs) the user wears.
func (p *Products) reportOutfit(user string, locals []int64) {
if p.Observer == nil {
return
}
id, err := strconv.ParseInt(user, 10, 64)
if err != nil {
return
}
items := []hub.Item{}
for _, local := range locals {
if s := p.lookup(local); s != nil {
items = append(items, hub.Item{ID: s.pack.Manifest.ID, Name: s.pack.Manifest.Name})
}
}
p.Observer.Outfit(id, items)
}