package backpack import ( "fmt" "sync" "git.golem15.com/golem15/summercms/compass" "git.golem15.com/golem15/summercms/modules/festival" ) // App is the per-instance application container. It must not import party. type App struct { Config *compass.Config Services *Registry Events *festival.Bus mu sync.RWMutex plugins map[string]struct{} } // New returns an App that owns cfg. func New(cfg *compass.Config) *App { return &App{ Config: cfg, Services: NewRegistry(), Events: festival.New(), plugins: make(map[string]struct{}), } } // SetPlugins records the complete activated plugin set. HasPlugin uses this // list, including plugins that have not yet Booted. func (a *App) SetPlugins(ids []string) { if a == nil { return } next := make(map[string]struct{}, len(ids)) for _, id := range ids { if id != "" { next[id] = struct{}{} } } a.mu.Lock() a.plugins = next a.mu.Unlock() } // HasPlugin reports whether id is in the complete registered set. func (a *App) HasPlugin(id string) bool { if a == nil { return false } a.mu.RLock() defer a.mu.RUnlock() _, ok := a.plugins[id] return ok } // Publish stores an app-scoped service under T. func (a *App) Publish[T any](value T) error { if a == nil || a.Services == nil { return fmt.Errorf("backpack: app has no service registry") } return a.Services.Publish(value) } // Lookup returns the app-scoped service published under T. func (a *App) Lookup[T any]() (T, bool) { var zero T if a == nil || a.Services == nil { return zero, false } return a.Services.Lookup[T]() }