139 lines
3.4 KiB
Go
139 lines
3.4 KiB
Go
package core
|
||
|
||
import (
|
||
"context"
|
||
"embed"
|
||
"errors"
|
||
"fmt"
|
||
|
||
"github.com/wailsapp/wails/v3/pkg/application"
|
||
)
|
||
|
||
// Service initialises a Core instance using the provided options and performs the necessary setup.
|
||
func Service(opts ...Option) *Core {
|
||
c := &Core{
|
||
mods: make(map[string]any),
|
||
}
|
||
// Apply all options (including WithService calls)
|
||
for _, o := range opts {
|
||
if err := o(c); err != nil {
|
||
return nil
|
||
}
|
||
}
|
||
c.once.Do(func() {
|
||
// any one‑time initialisation you need
|
||
instance = c
|
||
c.initErr = nil
|
||
})
|
||
if c.initErr != nil {
|
||
return nil
|
||
}
|
||
if c.serviceLock {
|
||
c.servicesLocked = true
|
||
}
|
||
return c
|
||
}
|
||
|
||
// WithService wraps a function that registers a package or module with the provided Core instance as an Option.
|
||
func WithService(reg func(*Core) error) Option {
|
||
return func(c *Core) error {
|
||
return reg(c)
|
||
}
|
||
}
|
||
|
||
// WithWails sets the Wails application instance to the Core configuration and returns an Option function.
|
||
func WithWails(app *application.App) Option {
|
||
return func(c *Core) error {
|
||
c.App = app
|
||
return nil
|
||
}
|
||
}
|
||
|
||
// WithAssets sets the provided embedded filesystem as the assets for the Core instance.
|
||
func WithAssets(fs embed.FS) Option {
|
||
return func(c *Core) error {
|
||
c.assets = fs
|
||
return nil
|
||
}
|
||
}
|
||
|
||
func WithServiceLock() Option {
|
||
return func(c *Core) error {
|
||
c.serviceLock = true
|
||
return nil
|
||
}
|
||
}
|
||
|
||
// ServiceStartup initializes the service during application startup by executing the ActionServiceStartup message.
|
||
func (c *Core) ServiceStartup(ctx context.Context, options application.ServiceOptions) error {
|
||
return c.ACTION(ActionServiceStartup{})
|
||
}
|
||
|
||
// ACTION processes a Message by invoking all registered handlers and returns an aggregated error if any handlers fail.
|
||
func (c *Core) ACTION(msg Message) error {
|
||
c.ipcMu.RLock()
|
||
handlers := append([]func(*Core, Message) error(nil), c.ipcHandlers...)
|
||
c.ipcMu.RUnlock()
|
||
|
||
var agg error
|
||
for _, h := range handlers {
|
||
if err := h(c, msg); err != nil {
|
||
agg = fmt.Errorf("%w; %v", agg, err)
|
||
}
|
||
}
|
||
return agg
|
||
}
|
||
|
||
// RegisterAction adds a single handler function to the list of registered IPC handlers in a thread-safe manner.
|
||
func (c *Core) RegisterAction(handler func(*Core, Message) error) {
|
||
c.ipcMu.Lock()
|
||
c.ipcHandlers = append(c.ipcHandlers, handler)
|
||
c.ipcMu.Unlock()
|
||
}
|
||
|
||
// RegisterActions registers multiple IPC handler functions to be executed during message processing in a thread-safe manner.
|
||
func (c *Core) RegisterActions(handlers ...func(*Core, Message) error) {
|
||
c.ipcMu.Lock()
|
||
c.ipcHandlers = append(c.ipcHandlers, handlers...)
|
||
c.ipcMu.Unlock()
|
||
}
|
||
|
||
// RegisterModule inserts an API object under a unique name.
|
||
func (c *Core) RegisterModule(name string, api any) error {
|
||
|
||
if c.servicesLocked {
|
||
return fmt.Errorf("core: module %q is not permitted by the serviceLock setting", name)
|
||
}
|
||
|
||
if name == "" {
|
||
return errors.New("core: module name cannot be empty")
|
||
}
|
||
c.modMu.Lock()
|
||
defer c.modMu.Unlock()
|
||
if _, exists := c.mods[name]; exists {
|
||
return fmt.Errorf("core: module %q already registered", name)
|
||
}
|
||
c.mods[name] = api
|
||
return nil
|
||
}
|
||
|
||
// Mod caller must type‑assert the result to the concrete API type it expects.
|
||
func (c *Core) Mod(name string) any {
|
||
c.modMu.RLock()
|
||
api, ok := c.mods[name]
|
||
c.modMu.RUnlock()
|
||
if !ok {
|
||
return nil
|
||
}
|
||
return api
|
||
}
|
||
|
||
// Mod is a generic helper to get a module of expected type T.
|
||
func Mod[T any](c *Core, name string) *T {
|
||
raw := c.Mod(name)
|
||
typed, ok := raw.(*T)
|
||
if !ok {
|
||
return nil
|
||
}
|
||
return typed
|
||
}
|