Table of Contents
Service Lifecycle
The Core struct is the central DI container managing named services, lifecycle sequencing, and the message bus.
Core Struct
type Core struct {
App any // GUI runtime (Wails)
assets embed.FS // Embedded frontend
Features *Features // Feature flags
svc *serviceManager
bus *messageBus
taskIDCounter atomic.Uint64
}
Creating a Core Instance
core, err := core.New(
core.WithService(NewMyService), // Auto-discovers name from package
core.WithName("custom", factory), // Explicit name
core.WithApp(wailsApp), // Wails runtime injection
core.WithAssets(assets), // Embedded frontend
core.WithServiceLock(), // Prevent late registration
)
All configuration uses functional options: type Option func(*Core) error.
Service Registration
Auto-Named (WithService)
The service name is auto-discovered from the package path (last component):
// In myapp/services/database/service.go
package database
func NewService(c *core.Core) (any, error) {
return &Service{}, nil
}
// Registered as "database"
core.New(core.WithService(NewService))
If the service implements HandleIPCEvents(c *Core, msg Message) error, it is automatically registered as an action handler.
Explicit Name (WithName)
For anonymous packages or multiple services from the same package:
core.WithName("primary-db", NewService)
core.WithName("cache-db", NewService)
Service Lock (WithServiceLock)
Prevents late service registration after initialisation:
core, err := core.New(
core.WithService(NewLogger),
core.WithServiceLock(),
)
// RegisterService() now returns "service not permitted by the serviceLock"
Service Retrieval
Type-Safe (ServiceFor)
db, err := core.ServiceFor[DatabaseService](c, "database")
Panic on Error (MustServiceFor)
db := core.MustServiceFor[DatabaseService](c, "database")
Untyped
svc := c.Service("database") // Returns any, nil if not found
Built-in Accessors
c.Config() // Config interface
c.Display() // Display interface
c.Workspace() // Workspace interface
c.Crypt() // Crypt interface
These panic if the service is not registered.
Lifecycle Interfaces
Services implementing Startable are called during startup in registration order:
type Startable interface {
OnStartup(ctx context.Context) error
}
Services implementing Stoppable are called during shutdown in reverse order:
type Stoppable interface {
OnShutdown(ctx context.Context) error
}
Wails Runtime Wrapper
Runtime bridges Core to Wails v3:
rt, err := runtime.NewRuntime(wailsApp)
rt, err := runtime.NewWithFactories(wailsApp, factories)
// Wails lifecycle callbacks
func (r *Runtime) ServiceStartup(ctx context.Context, options any) error
func (r *Runtime) ServiceShutdown(ctx context.Context) error
Global Instance
For Wails integration where a global is needed:
core.SetInstance(c)
app := core.App() // Panics if not set
inst := core.GetInstance() // Returns nil if not set
core.ClearInstance() // For testing
See Message-Bus for the ACTION/QUERY/TASK patterns and Service-Runtime for the generic helper.