plugin

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 27, 2026 License: MIT Imports: 12 Imported by: 0

README

plugin — 插件系统

提供插件的接口定义、生命周期管理、服务注册、事件总线与应用上下文,是整个框架的扩展骨架。

核心概念

概念 说明
Plugin 插件接口,每个业务模块实现此接口注入框架
AppContext 插件运行时可访问的全局上下文(DB、Cache、Logger 等)
ServiceRegistry 服务注册表,用于插件间依赖注入
EventBus 发布/订阅事件总线,实现模块间解耦通信
Domain 多租户隔离域

主要接口

Plugin 接口
type Plugin interface {
    // Name 返回插件唯一标识,用于依赖解析
    Name() string
    // Dependencies 返回该插件依赖的其他插件 Name 列表
    Dependencies() []string
    // Setup 插件初始化入口,接收应用上下文
    Setup(ctx context.Context, app AppContext) error
    // Teardown 插件清理(可选),在关闭时调用
    Teardown(ctx context.Context) error
}
AppContext 接口
type AppContext interface {
    DB() *ent.Client
    Cache() cache.Cache
    Logger() logging.Logger
    Config() *config.Config
    EventBus() EventBus
    Services() ServiceRegistry
    Router() chi.Router
}
EventBus
// 订阅事件
bus.Subscribe("user.created", func(ctx context.Context, e Event) error {
    // 处理事件
    return nil
})

// 发布事件
bus.Publish(ctx, "user.created", map[string]any{"userID": "..."})
ServiceRegistry
// 注册服务
registry.Register("emailService", &EmailService{})

// 获取服务
svc := registry.Get("emailService").(*EmailService)

实现插件

package myplugin

import (
    "context"
    "github.com/leeforge/framework/plugin"
)

type MyPlugin struct{}

func (p *MyPlugin) Name() string { return "my-plugin" }

func (p *MyPlugin) Dependencies() []string {
    return []string{"auth"} // 声明依赖
}

func (p *MyPlugin) Setup(ctx context.Context, app plugin.AppContext) error {
    logger := app.Logger()
    logger.Info("my-plugin initialized")

    // 注册服务
    app.Services().Register("myService", &MyService{db: app.DB()})

    // 注册路由
    app.Router().Route("/my-resource", func(r chi.Router) {
        r.Get("/", handleList)
    })

    return nil
}

func (p *MyPlugin) Teardown(ctx context.Context) error {
    return nil
}

注意事项

  • 插件 Name() 必须全局唯一
  • 循环依赖会导致运行时 panic,框架会在启动时做拓扑排序检测
  • Setup 返回错误会中止整个应用启动流程
  • Teardown 保证按依赖逆序调用

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrBusClosed is returned when publishing to a closed EventBus.
	ErrBusClosed = errors.New("event bus is closed")

	// ErrPublishTimeout is returned when the publish buffer is full and context expires.
	ErrPublishTimeout = errors.New("event publish timeout: buffer full")
)

Functions

func MustResolve

func MustResolve[T any](sr *ServiceRegistry, key string) T

MustResolve retrieves a service, panicking if not found or wrong type.

func Resolve

func Resolve[T any](sr *ServiceRegistry, key string) (T, error)

Resolve retrieves a service with compile-time type safety via generics.

Types

type AppContext

type AppContext struct {
	Router   chi.Router
	DB       Database
	Redis    *redis.Client
	Logger   *zap.Logger
	Services *ServiceRegistry
	Config   ConfigProvider
	Events   EventBus
}

AppContext is the typed dependency injection context passed to all plugin lifecycle methods.

type ConfigProvider

type ConfigProvider interface {
	Get(key string) (any, bool)
	GetString(key string, defaultVal string) string
	GetInt(key string, defaultVal int) int
	GetBool(key string, defaultVal bool) bool
	Bind(target any) error
	IsEnabled() bool
}

ConfigProvider gives plugins type-safe access to their scoped configuration.

func EmptyConfig

func EmptyConfig() ConfigProvider

EmptyConfig returns a ConfigProvider that always returns defaults.

type Configurable

type Configurable interface {
	PluginOptions() PluginOptions
}

Configurable -- declare plugin options (optional flag, description).

type Database

type Database interface {
	Close() error
}

Database is the minimal interface for DB lifecycle management. Keeps frame-core decoupled from specific generated Ent clients.

type Disableable

type Disableable interface {
	Disable(ctx context.Context, app *AppContext) error
}

Disableable -- cleanup on shutdown (release resources, flush buffers).

type DomainPlugin

type DomainPlugin interface {
	TypeCode() string
	ResolveDomain(ctx context.Context, r *http.Request) (*ResolvedDomainInfo, bool, error)
	ValidateMembership(ctx context.Context, domainID uuid.UUID, subject Subject) (bool, error)
}

DomainPlugin is an optional capability for plugins that register a domain type.

type Event

type Event struct {
	Name      string    // e.g. "user.created"
	Data      any       // payload
	Source    string    // originating plugin name
	Timestamp time.Time // when the event was created
}

Event represents a system or plugin event.

type EventBus

type EventBus interface {
	// Publish sends an event. Blocks if buffer is full until ctx expires.
	Publish(ctx context.Context, event Event) error

	// Subscribe registers a handler for a topic. Returns a Subscription for unsubscribing.
	Subscribe(topic string, handler EventHandler) Subscription

	// Close drains pending events and waits for in-flight handlers to complete.
	Close() error
}

EventBus is the single event mechanism for plugin communication.

type EventHandler

type EventHandler func(ctx context.Context, event Event) error

EventHandler is the typed handler for events.

type EventSubscriber

type EventSubscriber interface {
	SubscribeEvents(bus EventBus)
}

EventSubscriber -- subscribe to system/plugin events.

type HealthReporter

type HealthReporter interface {
	HealthCheck(ctx context.Context) error
}

HealthReporter -- provide custom health checks.

type Installable

type Installable interface {
	Install(ctx context.Context, app *AppContext) error
}

Installable -- first-time setup (DB migrations, seed data).

type MapConfigProvider

type MapConfigProvider = PluginConfigEntry

MapConfigProvider is a simple ConfigProvider backed by a map. Used for testing and inline configuration.

type MiddlewareProvider

type MiddlewareProvider interface {
	RegisterMiddlewares(router chi.Router)
}

MiddlewareProvider -- register HTTP middleware.

type ModelProvider

type ModelProvider interface {
	RegisterModels() []any
}

ModelProvider -- declare Ent ORM models for auto-migration.

type Plugin

type Plugin interface {
	Name() string
	Version() string
	Dependencies() []string
	Enable(ctx context.Context, app *AppContext) error
}

Plugin is the minimal interface every plugin must implement.

type PluginConfigEntry

type PluginConfigEntry struct {
	// contains filtered or unexported fields
}

PluginConfigEntry represents a single plugin's configuration entry.

func NewMapConfigProvider

func NewMapConfigProvider(settings map[string]any) *PluginConfigEntry

NewMapConfigProvider creates a ConfigProvider from a settings map (always enabled).

func NewPluginConfigEntry

func NewPluginConfigEntry(name string, enabled bool, settings map[string]any) *PluginConfigEntry

NewPluginConfigEntry creates a plugin config entry.

func (*PluginConfigEntry) Bind

func (c *PluginConfigEntry) Bind(target any) error

func (*PluginConfigEntry) Get

func (c *PluginConfigEntry) Get(key string) (any, bool)

func (*PluginConfigEntry) GetBool

func (c *PluginConfigEntry) GetBool(key string, defaultVal bool) bool

func (*PluginConfigEntry) GetInt

func (c *PluginConfigEntry) GetInt(key string, defaultVal int) int

func (*PluginConfigEntry) GetString

func (c *PluginConfigEntry) GetString(key string, defaultVal string) string

func (*PluginConfigEntry) IsEnabled

func (c *PluginConfigEntry) IsEnabled() bool

type PluginOptions

type PluginOptions struct {
	Optional    bool   // If true, failure does not abort bootstrap.
	Description string // Human-readable description.
}

PluginOptions holds declarative metadata about a plugin.

type PluginState

type PluginState int

PluginState represents the lifecycle state of a plugin.

const (
	StateRegistered PluginState = iota // Registered, not yet processed
	StateInstalled                     // Install() succeeded
	StateEnabled                       // Enable() succeeded, running
	StateDisabled                      // Disable() succeeded, stopped
	StateFailed                        // Install() or Enable() failed
)

func (PluginState) IsTerminal

func (s PluginState) IsTerminal() bool

IsTerminal returns true if the state cannot transition further in normal flow.

func (PluginState) String

func (s PluginState) String() string

String returns a human-readable state name.

type ResolvedDomainInfo

type ResolvedDomainInfo struct {
	DomainID    uuid.UUID `json:"domainId"`
	TypeCode    string    `json:"typeCode"`
	Key         string    `json:"key"`
	DisplayName string    `json:"displayName"`
}

ResolvedDomainInfo holds resolved domain metadata from a DomainPlugin.

type RouteProvider

type RouteProvider interface {
	RegisterRoutes(router chi.Router)
}

RouteProvider -- register HTTP routes.

type ServiceRegistry

type ServiceRegistry struct {
	// contains filtered or unexported fields
}

ServiceRegistry provides type-safe, namespace-aware service registration and lookup. Services are keyed by "pluginName.serviceName" (e.g. "audit.service", "rbac.enforcer").

func NewServiceRegistry

func NewServiceRegistry() *ServiceRegistry

NewServiceRegistry creates an empty service registry.

func (*ServiceRegistry) Has

func (sr *ServiceRegistry) Has(key string) bool

Has returns true if a service is registered under the given key.

func (*ServiceRegistry) Keys

func (sr *ServiceRegistry) Keys() []string

Keys returns all registered service keys, sorted alphabetically.

func (*ServiceRegistry) MustRegister

func (sr *ServiceRegistry) MustRegister(key string, svc any)

MustRegister stores a service, panicking on duplicate.

func (*ServiceRegistry) Register

func (sr *ServiceRegistry) Register(key string, svc any) error

Register stores a service. Returns error if key already exists.

type Subject

type Subject struct {
	ID   uuid.UUID `json:"id"`
	Type string    `json:"type"`
}

Subject represents the actor requesting domain access.

type Subscription

type Subscription interface {
	Unsubscribe()
}

Subscription represents an active event subscription.

type Uninstallable

type Uninstallable interface {
	Uninstall(ctx context.Context, app *AppContext) error
}

Uninstallable -- permanent removal (drop tables, delete files).

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL