Documentation
¶
Overview ¶
Package plugin defines the unified interface for GoatKit plugins.
Plugins can be implemented as either:
- WASM modules (portable, sandboxed, via wazero)
- gRPC services (native, for I/O-heavy workloads, via go-plugin)
The host doesn't care which runtime backs a plugin - both implement this interface and are managed uniformly by the plugin manager.
Index ¶
- Variables
- func RegisterPluginJobs(mgr *Manager, sched *scheduler.Service) int
- func SetTemplateOverrides(registry *TemplateOverrideRegistry)
- func SetTemplatePluginManager(mgr *Manager)
- type DefaultHostAPI
- func (h *DefaultHostAPI) CacheDelete(ctx context.Context, key string) error
- func (h *DefaultHostAPI) CacheGet(ctx context.Context, key string) ([]byte, bool, error)
- func (h *DefaultHostAPI) CacheSet(ctx context.Context, key string, value []byte, ttlSeconds int) error
- func (h *DefaultHostAPI) CallPlugin(ctx context.Context, pluginName, fn string, args json.RawMessage) (json.RawMessage, error)
- func (h *DefaultHostAPI) ConfigGet(ctx context.Context, key string) (string, error)
- func (h *DefaultHostAPI) DBExec(ctx context.Context, query string, args ...any) (int64, error)
- func (h *DefaultHostAPI) DBQuery(ctx context.Context, query string, args ...any) ([]map[string]any, error)
- func (h *DefaultHostAPI) HTTPRequest(ctx context.Context, method, url string, headers map[string]string, ...) (int, []byte, error)
- func (h *DefaultHostAPI) Log(ctx context.Context, level, message string, fields map[string]any)
- func (h *DefaultHostAPI) SendEmail(ctx context.Context, to, subject, body string, html bool) error
- func (h *DefaultHostAPI) Translate(ctx context.Context, key string, args ...any) string
- type ErrorCodeSpec
- type GKRegistration
- type HostAPI
- type I18nSpec
- type JobSpec
- type LazyLoader
- type LogBuffer
- func (b *LogBuffer) Add(entry LogEntry)
- func (b *LogBuffer) Clear()
- func (b *LogBuffer) Count() int
- func (b *LogBuffer) GetAll() []LogEntry
- func (b *LogBuffer) GetByLevel(minLevel string) []LogEntry
- func (b *LogBuffer) GetByPlugin(pluginName string) []LogEntry
- func (b *LogBuffer) GetRecent(n int) []LogEntry
- func (b *LogBuffer) Log(plugin, level, message string, fields map[string]any)
- type LogEntry
- type Manager
- func (m *Manager) AllWidgets(location string) []PluginWidget
- func (m *Manager) Call(ctx context.Context, pluginName, fn string, args []byte) ([]byte, error)
- func (m *Manager) CallFrom(ctx context.Context, callerPlugin, targetPlugin, fn string, args []byte) ([]byte, error)
- func (m *Manager) Disable(name string) error
- func (m *Manager) Discovered() []string
- func (m *Manager) Enable(name string) error
- func (m *Manager) Get(name string) (Plugin, bool)
- func (m *Manager) IsEnabled(name string) bool
- func (m *Manager) Jobs() []PluginJob
- func (m *Manager) List() []GKRegistration
- func (m *Manager) MenuItems(location string) []PluginMenuItem
- func (m *Manager) Register(ctx context.Context, p Plugin) error
- func (m *Manager) Routes() []PluginRoute
- func (m *Manager) SetLazyLoader(loader LazyLoader)
- func (m *Manager) ShutdownAll(ctx context.Context) error
- func (m *Manager) Unregister(ctx context.Context, name string) error
- func (m *Manager) Widgets(location string) []PluginWidget
- type MenuItemSpec
- type Plugin
- type PluginCaller
- type PluginDisabledError
- type PluginJob
- type PluginMenuItem
- type PluginNotFoundError
- type PluginRoute
- type PluginWidget
- type ProdHostAPI
- func (h *ProdHostAPI) CacheDelete(ctx context.Context, key string) error
- func (h *ProdHostAPI) CacheGet(ctx context.Context, key string) ([]byte, bool, error)
- func (h *ProdHostAPI) CacheSet(ctx context.Context, key string, value []byte, ttlSeconds int) error
- func (h *ProdHostAPI) CallPlugin(ctx context.Context, pluginName, fn string, args json.RawMessage) (json.RawMessage, error)
- func (h *ProdHostAPI) ConfigGet(ctx context.Context, key string) (string, error)
- func (h *ProdHostAPI) DBExec(ctx context.Context, query string, args ...any) (int64, error)
- func (h *ProdHostAPI) DBQuery(ctx context.Context, query string, args ...any) ([]map[string]any, error)
- func (h *ProdHostAPI) HTTPRequest(ctx context.Context, method, url string, headers map[string]string, ...) (int, []byte, error)
- func (h *ProdHostAPI) Log(ctx context.Context, level, message string, fields map[string]any)
- func (h *ProdHostAPI) SendEmail(ctx context.Context, to, subject, body string, html bool) error
- func (h *ProdHostAPI) Translate(ctx context.Context, key string, args ...any) string
- type ProdHostAPIOption
- type RouteSpec
- type TemplateOverride
- type TemplateOverrideRegistry
- func (r *TemplateOverrideRegistry) GetOverride(templateName string) *TemplateOverride
- func (r *TemplateOverrideRegistry) HasOverride(templateName string) bool
- func (r *TemplateOverrideRegistry) List() map[string]*TemplateOverride
- func (r *TemplateOverrideRegistry) Register(pluginName string, templates []TemplateSpec)
- func (r *TemplateOverrideRegistry) RenderOverride(ctx context.Context, templateName string, data map[string]any) (string, bool)
- func (r *TemplateOverrideRegistry) Unregister(pluginName string)
- type TemplateSpec
- type WidgetSpec
Constants ¶
This section is empty.
Variables ¶
var PluginCallerKey = pluginCallerKeyType{}
PluginCallerKey is the context key for tracking which plugin is making a call.
var PluginLanguageKey = pluginLangKeyType{}
Functions ¶
func RegisterPluginJobs ¶
RegisterPluginJobs registers all plugin-defined jobs with the scheduler. Call this after plugins are loaded and the scheduler is created.
func SetTemplateOverrides ¶
func SetTemplateOverrides(registry *TemplateOverrideRegistry)
SetTemplateOverrides sets the global template override registry.
func SetTemplatePluginManager ¶
func SetTemplatePluginManager(mgr *Manager)
SetTemplatePluginManager sets the plugin manager for template tags. Call this during app initialization after creating the plugin manager.
Types ¶
type DefaultHostAPI ¶
type DefaultHostAPI struct {
}
DefaultHostAPI provides a basic implementation of HostAPI. In production, this would be wired to actual database, cache, etc.
func NewDefaultHostAPI ¶
func NewDefaultHostAPI() *DefaultHostAPI
NewDefaultHostAPI creates a new default host API.
func (*DefaultHostAPI) CacheDelete ¶
func (h *DefaultHostAPI) CacheDelete(ctx context.Context, key string) error
CacheDelete removes a value from cache.
func (*DefaultHostAPI) CacheSet ¶
func (h *DefaultHostAPI) CacheSet(ctx context.Context, key string, value []byte, ttlSeconds int) error
CacheSet stores a value in cache.
func (*DefaultHostAPI) CallPlugin ¶
func (h *DefaultHostAPI) CallPlugin(ctx context.Context, pluginName, fn string, args json.RawMessage) (json.RawMessage, error)
CallPlugin calls a function in another plugin.
func (*DefaultHostAPI) DBQuery ¶
func (h *DefaultHostAPI) DBQuery(ctx context.Context, query string, args ...any) ([]map[string]any, error)
DBQuery executes a query and returns rows as maps.
func (*DefaultHostAPI) HTTPRequest ¶
func (h *DefaultHostAPI) HTTPRequest(ctx context.Context, method, url string, headers map[string]string, body []byte) (int, []byte, error)
HTTPRequest makes an outbound HTTP request.
type ErrorCodeSpec ¶
type ErrorCodeSpec struct {
Code string `json:"code"` // error code without prefix, e.g. "export_failed"
Message string `json:"message"` // default English message
HTTPStatus int `json:"http_status"` // suggested HTTP status code
}
ErrorCodeSpec defines an API error code provided by the plugin. The plugin name is automatically prefixed to the code by the host (e.g., code "export_failed" in plugin "stats" becomes "stats:export_failed").
type GKRegistration ¶
type GKRegistration struct {
// Identity
Name string `json:"name"` // unique identifier, e.g. "stats"
Version string `json:"version"` // semver, e.g. "1.0.0"
Description string `json:"description"` // human-readable description
Author string `json:"author"` // author or organization
License string `json:"license"` // SPDX identifier, e.g. "Apache-2.0"
Homepage string `json:"homepage"` // URL to plugin docs/repo
// Capabilities - what the plugin exposes to the host
Routes []RouteSpec `json:"routes,omitempty"` // HTTP routes to register
MenuItems []MenuItemSpec `json:"menu_items,omitempty"` // navigation menu entries
Widgets []WidgetSpec `json:"widgets,omitempty"` // dashboard widgets
Jobs []JobSpec `json:"jobs,omitempty"` // scheduled/cron tasks
Templates []TemplateSpec `json:"templates,omitempty"` // template overrides/additions
I18n *I18nSpec `json:"i18n,omitempty"` // translations provided by plugin
ErrorCodes []ErrorCodeSpec `json:"error_codes,omitempty"` // API error codes provided by plugin
// Requirements
MinHostVersion string `json:"min_host_version,omitempty"` // minimum GoatFlow version
Permissions []string `json:"permissions,omitempty"` // required host permissions
}
GKRegistration describes what a plugin provides to the host. This is returned by GKRegister() - the self-describing plugin protocol.
type HostAPI ¶
type HostAPI interface {
// Database
DBQuery(ctx context.Context, query string, args ...any) ([]map[string]any, error)
DBExec(ctx context.Context, query string, args ...any) (int64, error)
// Cache
CacheGet(ctx context.Context, key string) ([]byte, bool, error)
CacheSet(ctx context.Context, key string, value []byte, ttlSeconds int) error
CacheDelete(ctx context.Context, key string) error
// HTTP (outbound)
HTTPRequest(ctx context.Context, method, url string, headers map[string]string, body []byte) (int, []byte, error)
// Email
SendEmail(ctx context.Context, to, subject, body string, html bool) error
// Logging
Log(ctx context.Context, level, message string, fields map[string]any)
// Config
ConfigGet(ctx context.Context, key string) (string, error)
// i18n
Translate(ctx context.Context, key string, args ...any) string
// Plugin-to-plugin calls
// Allows one plugin to call functions in another plugin
CallPlugin(ctx context.Context, pluginName, fn string, args json.RawMessage) (json.RawMessage, error)
}
HostAPI is the interface plugins use to access host services. Passed to Plugin.Init() - plugins store this for later use.
type I18nSpec ¶
type I18nSpec struct {
// Namespace prefix for plugin translations (e.g., "stats" -> "stats.dashboard.title")
Namespace string `json:"namespace,omitempty"`
// Languages supported by this plugin
Languages []string `json:"languages,omitempty"`
// Inline translations (language -> key -> value)
// For small plugins, translations can be embedded in the manifest
Translations map[string]map[string]string `json:"translations,omitempty"`
}
I18nSpec defines internationalization resources provided by the plugin.
type JobSpec ¶
type JobSpec struct {
ID string `json:"id"` // unique identifier
Handler string `json:"handler"` // plugin function to call
Schedule string `json:"schedule"` // cron expression, e.g. "0 * * * *"
Description string `json:"description,omitempty"` // human-readable description
Enabled bool `json:"enabled"` // whether job runs by default
Timeout string `json:"timeout,omitempty"` // max execution time, e.g. "5m"
}
JobSpec defines a scheduled/cron task.
type LazyLoader ¶
type LazyLoader interface {
EnsureLoaded(ctx context.Context, name string) error
Discovered() []string
}
LazyLoader is the interface for lazy-loading plugins on demand.
type LogBuffer ¶
type LogBuffer struct {
// contains filtered or unexported fields
}
LogBuffer is a ring buffer for plugin logs.
func GetLogBuffer ¶
func GetLogBuffer() *LogBuffer
GetLogBuffer returns the global plugin log buffer.
func NewLogBuffer ¶
NewLogBuffer creates a new log buffer with the given max size.
func (*LogBuffer) GetByLevel ¶
GetByLevel returns log entries at or above the given level, newest first.
func (*LogBuffer) GetByPlugin ¶
GetByPlugin returns log entries for a specific plugin, newest first.
type LogEntry ¶
type LogEntry struct {
Timestamp time.Time `json:"timestamp"`
Plugin string `json:"plugin"`
Level string `json:"level"` // debug, info, warn, error
Message string `json:"message"`
Fields map[string]any `json:"fields,omitempty"`
}
LogEntry represents a single plugin log entry.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager handles plugin lifecycle: loading, registration, and invocation.
func NewManager ¶
NewManager creates a plugin manager with the given host API.
func (*Manager) AllWidgets ¶
func (m *Manager) AllWidgets(location string) []PluginWidget
AllWidgets returns widgets from all plugins (including lazy-loaded) for a location. This triggers lazy loading for all discovered plugins to ensure complete widget list.
func (*Manager) Call ¶
Call invokes a function on a specific plugin. If lazy loading is enabled and the plugin isn't loaded yet, it will be loaded first.
func (*Manager) CallFrom ¶
func (m *Manager) CallFrom(ctx context.Context, callerPlugin, targetPlugin, fn string, args []byte) ([]byte, error)
CallFrom invokes a function on a plugin, with caller context for better errors. If lazy loading is enabled and the plugin isn't loaded yet, it will be loaded first.
func (*Manager) Discovered ¶
Discovered returns the names of discovered but not necessarily loaded plugins.
func (*Manager) Enable ¶
Enable enables a previously disabled plugin. If the plugin is lazy-loaded and not yet registered, it will be loaded first.
func (*Manager) List ¶
func (m *Manager) List() []GKRegistration
List returns all registered plugin manifests.
func (*Manager) MenuItems ¶
func (m *Manager) MenuItems(location string) []PluginMenuItem
MenuItems returns all menu items from all enabled plugins.
func (*Manager) Routes ¶
func (m *Manager) Routes() []PluginRoute
Routes returns all routes from all enabled plugins.
func (*Manager) SetLazyLoader ¶
func (m *Manager) SetLazyLoader(loader LazyLoader)
SetLazyLoader sets the lazy loader for on-demand plugin loading.
func (*Manager) ShutdownAll ¶
ShutdownAll shuts down all plugins gracefully.
func (*Manager) Unregister ¶
Unregister shuts down and removes a plugin.
func (*Manager) Widgets ¶
func (m *Manager) Widgets(location string) []PluginWidget
Widgets returns all widgets from all enabled plugins for a location.
type MenuItemSpec ¶
type MenuItemSpec struct {
ID string `json:"id"` // unique identifier
Label string `json:"label"` // display text (can be i18n key)
Icon string `json:"icon,omitempty"` // icon name or SVG
Path string `json:"path"` // URL path when clicked
Location string `json:"location"` // where to insert: "admin", "agent", "customer"
Parent string `json:"parent,omitempty"` // parent menu ID for submenus
Order int `json:"order,omitempty"` // sort order within location
Children []MenuItemSpec `json:"children,omitempty"` // nested menu items
}
MenuItemSpec defines a navigation menu entry.
type Plugin ¶
type Plugin interface {
// GKRegister returns plugin metadata. Called once at load time.
// This is how plugins self-describe their capabilities per the GoatKit spec.
GKRegister() GKRegistration
// Init is called after loading, before the plugin serves requests.
// The HostAPI provides access to host services (db, cache, http, etc).
Init(ctx context.Context, host HostAPI) error
// Call invokes a plugin function by name with JSON-encoded arguments.
// Returns JSON-encoded response or error.
// This is the primary communication channel between host and plugin.
Call(ctx context.Context, fn string, args json.RawMessage) (json.RawMessage, error)
// Shutdown is called before unloading the plugin.
// Plugins should clean up resources and finish pending work.
Shutdown(ctx context.Context) error
}
Plugin is the unified interface for WASM and gRPC plugins. Both runtime implementations must satisfy this interface.
type PluginCaller ¶
type PluginCaller struct {
Manager *Manager
PluginName string
Ctx context.Context // Optional context for i18n
}
PluginCaller wraps plugin function calls for templates. Exported so it can be used directly in template contexts.
func (*PluginCaller) Call ¶
func (pc *PluginCaller) Call(fn string, args ...interface{}) interface{}
Call invokes a plugin function. Used via {{ plugin.Call("fn", args) }}
func (*PluginCaller) Translate ¶
func (pc *PluginCaller) Translate(key string, args ...interface{}) string
Translate calls the plugin's translation with the current context language.
func (*PluginCaller) Widget ¶
func (pc *PluginCaller) Widget(widgetID string) string
Widget renders a plugin widget by ID. Returns HTML string.
type PluginDisabledError ¶
PluginDisabledError is returned when trying to call a disabled plugin.
func (*PluginDisabledError) Error ¶
func (e *PluginDisabledError) Error() string
type PluginMenuItem ¶
type PluginMenuItem struct {
PluginName string
MenuItemSpec
}
PluginMenuItem pairs a menu item spec with its plugin name.
type PluginNotFoundError ¶
type PluginNotFoundError struct {
PluginName string // The missing plugin
CallerPlugin string // The plugin that tried to call it (if known)
Function string // The function that was called
}
PluginNotFoundError is returned when a plugin dependency is missing.
func (*PluginNotFoundError) Error ¶
func (e *PluginNotFoundError) Error() string
type PluginRoute ¶
PluginRoute pairs a route spec with its plugin name.
type PluginWidget ¶
type PluginWidget struct {
PluginName string
WidgetSpec
}
PluginWidget pairs a widget spec with its plugin name.
type ProdHostAPI ¶
type ProdHostAPI struct {
PluginManager *Manager // For plugin-to-plugin calls
// contains filtered or unexported fields
}
ProdHostAPI is the production implementation of HostAPI. It wires plugins to real database, cache, email, and other services.
func NewProdHostAPI ¶
func NewProdHostAPI(opts ...ProdHostAPIOption) *ProdHostAPI
NewProdHostAPI creates a production host API with the given options.
func (*ProdHostAPI) CacheDelete ¶
func (h *ProdHostAPI) CacheDelete(ctx context.Context, key string) error
CacheDelete removes a value from cache.
func (*ProdHostAPI) CallPlugin ¶
func (h *ProdHostAPI) CallPlugin(ctx context.Context, pluginName, fn string, args json.RawMessage) (json.RawMessage, error)
CallPlugin calls a function in another plugin. This enables plugin-to-plugin communication via the host. If PluginCallerKey is set in the context, provides better error messages.
func (*ProdHostAPI) ConfigGet ¶
ConfigGet retrieves a configuration value by key path. Supports dot notation for nested values (e.g., "app.name").
func (*ProdHostAPI) DBExec ¶
DBExec executes an INSERT/UPDATE/DELETE and returns affected rows. Uses the default database. For named databases, prefix query with "@dbname:" (e.g., "@analytics:INSERT...").
func (*ProdHostAPI) DBQuery ¶
func (h *ProdHostAPI) DBQuery(ctx context.Context, query string, args ...any) ([]map[string]any, error)
DBQuery executes a SELECT query and returns rows as maps. Uses the default database. For named databases, prefix query with "@dbname:" (e.g., "@analytics:SELECT...").
func (*ProdHostAPI) HTTPRequest ¶
func (h *ProdHostAPI) HTTPRequest(ctx context.Context, method, url string, headers map[string]string, body []byte) (int, []byte, error)
HTTPRequest makes an outbound HTTP request.
type ProdHostAPIOption ¶
type ProdHostAPIOption func(*ProdHostAPI)
ProdHostAPIOption is a functional option for ProdHostAPI.
func WithCache ¶
func WithCache(c *cache.RedisCache) ProdHostAPIOption
WithCache sets the cache client.
func WithDB ¶
func WithDB(name string, db *sql.DB) ProdHostAPIOption
WithDB adds a named database connection. Use "default" for the primary database.
func WithDefaultDB ¶
func WithDefaultDB(name string) ProdHostAPIOption
WithDefaultDB sets which named database is the default.
func WithLogger ¶
func WithLogger(logger *slog.Logger) ProdHostAPIOption
WithLogger sets the logger.
func WithPluginManager ¶
func WithPluginManager(mgr *Manager) ProdHostAPIOption
WithPluginManager sets the plugin manager for plugin-to-plugin calls.
type RouteSpec ¶
type RouteSpec struct {
Method string `json:"method"` // GET, POST, PUT, DELETE, etc.
Path string `json:"path"` // URL path, e.g. "/admin/stats"
Handler string `json:"handler"` // plugin function to call
Middleware []string `json:"middleware,omitempty"` // middleware chain, e.g. ["auth", "admin"]
Description string `json:"description,omitempty"` // for documentation
}
RouteSpec defines an HTTP route the plugin wants to handle.
type TemplateOverride ¶
type TemplateOverride struct {
PluginName string // Plugin providing the override
TemplateName string // Original template name being overridden
Handler string // Plugin function to call for template content
}
TemplateOverride stores information about a template override.
type TemplateOverrideRegistry ¶
type TemplateOverrideRegistry struct {
// contains filtered or unexported fields
}
TemplateOverrideRegistry manages template overrides from plugins.
func GetTemplateOverrides ¶
func GetTemplateOverrides() *TemplateOverrideRegistry
GetTemplateOverrides returns the global template override registry.
func NewTemplateOverrideRegistry ¶
func NewTemplateOverrideRegistry(mgr *Manager) *TemplateOverrideRegistry
NewTemplateOverrideRegistry creates a new template override registry.
func (*TemplateOverrideRegistry) GetOverride ¶
func (r *TemplateOverrideRegistry) GetOverride(templateName string) *TemplateOverride
GetOverride returns the override for a template, if any.
func (*TemplateOverrideRegistry) HasOverride ¶
func (r *TemplateOverrideRegistry) HasOverride(templateName string) bool
HasOverride checks if a template has a plugin override.
func (*TemplateOverrideRegistry) List ¶
func (r *TemplateOverrideRegistry) List() map[string]*TemplateOverride
List returns all registered overrides.
func (*TemplateOverrideRegistry) Register ¶
func (r *TemplateOverrideRegistry) Register(pluginName string, templates []TemplateSpec)
Register registers template overrides from a plugin.
func (*TemplateOverrideRegistry) RenderOverride ¶
func (r *TemplateOverrideRegistry) RenderOverride(ctx context.Context, templateName string, data map[string]any) (string, bool)
RenderOverride renders a template override by calling the plugin. Returns the rendered HTML and true if an override exists, empty string and false otherwise.
func (*TemplateOverrideRegistry) Unregister ¶
func (r *TemplateOverrideRegistry) Unregister(pluginName string)
Unregister removes template overrides for a plugin.
type TemplateSpec ¶
type TemplateSpec struct {
Name string `json:"name"` // template name, e.g. "stats/dashboard.html"
Path string `json:"path"` // path within plugin package
Override bool `json:"override,omitempty"` // if true, overrides host template of same name
}
TemplateSpec defines a template the plugin provides.
type WidgetSpec ¶
type WidgetSpec struct {
ID string `json:"id"` // unique identifier
Title string `json:"title"` // display title (can be i18n key)
Description string `json:"description,omitempty"` // widget description
Handler string `json:"handler"` // plugin function that returns widget HTML
Location string `json:"location"` // dashboard location: "agent_home", "admin_home"
Size string `json:"size,omitempty"` // "small", "medium", "large", "full"
Order int `json:"order,omitempty"` // sort order within location
Refreshable bool `json:"refreshable,omitempty"` // can be refreshed via AJAX
RefreshSec int `json:"refresh_sec,omitempty"` // auto-refresh interval
}
WidgetSpec defines a dashboard widget.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package core provides core built-in plugins for GoatFlow.
|
Package core provides core built-in plugins for GoatFlow. |
|
Package example provides example plugin implementations for testing.
|
Package example provides example plugin implementations for testing. |
|
Package grpc provides gRPC-based plugin runtime using HashiCorp go-plugin.
|
Package grpc provides gRPC-based plugin runtime using HashiCorp go-plugin. |
|
example
command
Example gRPC plugin for GoatKit.
|
Example gRPC plugin for GoatKit. |
|
Package packaging provides ZIP-based plugin packaging and extraction.
|
Package packaging provides ZIP-based plugin packaging and extraction. |
|
Package wasm provides a WASM-based plugin runtime using wazero.
|
Package wasm provides a WASM-based plugin runtime using wazero. |