- lighthouse: Service/From with realtime.driver selection, RegisterDriver registry, null/log/memory drivers, Route/Surface/Mount, users and actors - centrifugo: HTTP API client (apikey header, 2xx success, no request without a key), five-generator HS256 TokenIssuer, TokenHandler with the WinterCMS 401/503 bodies - module README and root modules table row
72 lines
1.8 KiB
Go
72 lines
1.8 KiB
Go
package lighthouse
|
|
|
|
import (
|
|
"context"
|
|
|
|
"git.golem15.com/golem15/summercms/modules/bouncer"
|
|
)
|
|
|
|
// User is the identity a realtime driver needs: the id and display name.
|
|
type User struct {
|
|
ID uint
|
|
Name *string
|
|
}
|
|
|
|
// UserLookup loads a user by id. found is false when no such user exists.
|
|
type UserLookup func(ctx context.Context, id uint) (user User, found bool, err error)
|
|
|
|
// SetUserLookup installs the application's user lookup.
|
|
func (s *Service) SetUserLookup(fn UserLookup) {
|
|
if s == nil {
|
|
return
|
|
}
|
|
s.mu.Lock()
|
|
s.lookup = fn
|
|
s.mu.Unlock()
|
|
}
|
|
|
|
// User loads user id through the installed lookup. Without a lookup it
|
|
// returns User{ID: id} with a nil Name and found true.
|
|
func (s *Service) User(ctx context.Context, id uint) (User, bool, error) {
|
|
if s == nil {
|
|
return User{ID: id}, true, nil
|
|
}
|
|
s.mu.RLock()
|
|
fn := s.lookup
|
|
s.mu.RUnlock()
|
|
if fn == nil {
|
|
return User{ID: id}, true, nil
|
|
}
|
|
return fn(ctx, id)
|
|
}
|
|
|
|
// Actor is who caused a broadcast. It marshals as {"user_id":…,"name":…}.
|
|
type Actor struct {
|
|
UserID *uint `json:"user_id"`
|
|
Name *string `json:"name"`
|
|
}
|
|
|
|
// SystemActor is the actor of writes made without a signed-in user:
|
|
// {"user_id":null,"name":"System"}.
|
|
func SystemActor() Actor {
|
|
name := "System"
|
|
return Actor{Name: &name}
|
|
}
|
|
|
|
// Actor returns the actor of the request in ctx. No principal, or a
|
|
// backend-admin principal, gives SystemActor: the WinterCMS frontend user is
|
|
// empty in backend requests. Otherwise it is the principal's id and the
|
|
// looked-up name (nil when the lookup fails or finds nothing).
|
|
func (s *Service) Actor(ctx context.Context) Actor {
|
|
p, ok := bouncer.User(ctx)
|
|
if !ok || p == nil || p.Backend {
|
|
return SystemActor()
|
|
}
|
|
id := p.ID
|
|
a := Actor{UserID: &id}
|
|
if u, found, err := s.User(ctx, id); err == nil && found {
|
|
a.Name = u.Name
|
|
}
|
|
return a
|
|
}
|