go/pkg/core/runtime_pkg.go
Snider 29e6d06633 fix(core): replace fmt.Errorf with structured errors, add log service tests
- Replace all fmt.Errorf calls with coreerr.E() from go-log for structured
  error context (op, msg, underlying error) across core.go, service_manager.go,
  and runtime_pkg.go (12 violations fixed)
- Replace local Error type and E() in e.go with re-exports from go-log,
  eliminating duplicate implementation while preserving public API
- Add comprehensive tests for pkg/log Service (NewService, OnStartup,
  QueryLevel, TaskSetLevel) — coverage 72.2% → 87.8%
- Update CLAUDE.md: Go 1.25 → 1.26, runtime.go → runtime_pkg.go,
  document go-log error convention
- No os.ReadFile/os.WriteFile violations found (all I/O uses go-io)

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-17 08:03:05 +00:00

113 lines
3.4 KiB
Go

package core
import (
"context"
"fmt"
"maps"
"slices"
)
// ServiceRuntime is a helper struct embedded in services to provide access to the core application.
// It is generic and can be parameterized with a service-specific options struct.
type ServiceRuntime[T any] struct {
core *Core
opts T
}
// NewServiceRuntime creates a new ServiceRuntime instance for a service.
// This is typically called by a service's constructor.
func NewServiceRuntime[T any](c *Core, opts T) *ServiceRuntime[T] {
return &ServiceRuntime[T]{
core: c,
opts: opts,
}
}
// Core returns the central core instance, providing access to all registered services.
func (r *ServiceRuntime[T]) Core() *Core {
return r.core
}
// Opts returns the service-specific options.
func (r *ServiceRuntime[T]) Opts() T {
return r.opts
}
// Config returns the registered Config service from the core application.
// This is a convenience method for accessing the application's configuration.
func (r *ServiceRuntime[T]) Config() Config {
return r.core.Config()
}
// Runtime is the container that holds all instantiated services.
// Its fields are the concrete types, allowing GUI runtimes to bind them directly.
// This struct is the primary entry point for the application.
type Runtime struct {
app any // GUI runtime (e.g., Wails App)
Core *Core
}
// ServiceFactory defines a function that creates a service instance.
// This is used to decouple the service creation from the runtime initialization.
type ServiceFactory func() (any, error)
// NewWithFactories creates a new Runtime instance using the provided service factories.
// This is the most flexible way to create a new Runtime, as it allows for
// the registration of any number of services.
func NewWithFactories(app any, factories map[string]ServiceFactory) (*Runtime, error) {
coreOpts := []Option{
WithApp(app),
}
names := slices.Sorted(maps.Keys(factories))
for _, name := range names {
factory := factories[name]
if factory == nil {
return nil, E("core.NewWithFactories", fmt.Sprintf("factory is nil for service %q", name), nil)
}
svc, err := factory()
if err != nil {
return nil, E("core.NewWithFactories", fmt.Sprintf("failed to create service %q", name), err)
}
svcCopy := svc
coreOpts = append(coreOpts, WithName(name, func(c *Core) (any, error) { return svcCopy, nil }))
}
coreInstance, err := New(coreOpts...)
if err != nil {
return nil, err
}
return &Runtime{
app: app,
Core: coreInstance,
}, nil
}
// NewRuntime creates and wires together all application services.
// This is the simplest way to create a new Runtime, but it does not allow for
// the registration of any custom services.
func NewRuntime(app any) (*Runtime, error) {
return NewWithFactories(app, map[string]ServiceFactory{})
}
// ServiceName returns the name of the service. This is used by GUI runtimes to identify the service.
func (r *Runtime) ServiceName() string {
return "Core"
}
// ServiceStartup is called by the GUI runtime at application startup.
// This is where the Core's startup lifecycle is initiated.
func (r *Runtime) ServiceStartup(ctx context.Context, options any) error {
return r.Core.ServiceStartup(ctx, options)
}
// ServiceShutdown is called by the GUI runtime at application shutdown.
// This is where the Core's shutdown lifecycle is initiated.
func (r *Runtime) ServiceShutdown(ctx context.Context) error {
if r.Core != nil {
return r.Core.ServiceShutdown(ctx)
}
return nil
}