plugin

package
v0.0.0-...-9206028 Latest Latest
Warning

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

Go to latest
Published: Jul 22, 2026 License: AGPL-3.0 Imports: 38 Imported by: 0

Documentation

Index

Constants

View Source
const (
	EventBusTopicPlugin  = "plugin"  // Topic to kernel plugin
	EventBusTopicRuntime = "runtime" // Topic to javascript runtime
)
View Source
const (
	SseHeaderAcceptName  = "Accept"
	SseHeaderAcceptValue = "text/event-stream"
)
View Source
const (
	AccessScopePublic  AccessScope = "public"
	AccessScopePrivate AccessScope = "private"

	SerializedTypeJSON         SerializedType = "JSON"
	SerializedTypeJSONP        SerializedType = "JSONP"
	SerializedTypeAsciiJSON    SerializedType = "AsciiJSON"
	SerializedTypeIndentedJSON SerializedType = "IndentedJSON"
	SerializedTypePureJSON     SerializedType = "PureJSON"
	SerializedTypeSecureJSON   SerializedType = "SecureJSON"

	SerializedTypeXML      SerializedType = "XML"
	SerializedTypeYAML     SerializedType = "YAML"
	SerializedTypeTOML     SerializedType = "TOML"
	SerializedTypeProtoBuf SerializedType = "ProtoBuf"

	RequestTypeHTTP RequestType = "http"
	RequestTypeWS   RequestType = "ws"
	RequestTypeSSE  RequestType = "es"
)

Variables

View Source
var (
	JsonRpcErrorParseError     = &JsonRpcError{Code: JsonRpcErrorCodeParseError, Message: "Parse error"}
	JsonRpcErrorInvalidRequest = &JsonRpcError{Code: JsonRpcErrorCodeInvalidRequest, Message: "Invalid Request"}
	JsonRpcErrorMethodNotFound = &JsonRpcError{Code: JsonRpcErrorCodeMethodNotFound, Message: "Method not found"}
	JsonRpcErrorInvalidParams  = &JsonRpcError{Code: JsonRpcErrorCodeInvalidParams, Message: "Invalid params"}
	JsonRpcErrorInternalError  = &JsonRpcError{Code: JsonRpcErrorCodeInternalError, Message: "Internal error"}

	JsonRpcErrorPluginNotLoaded  = &JsonRpcError{Code: JsonRpcErrorCodePluginNotLoaded, Message: "Plugin not loaded"}
	JsonRpcErrorPluginNotRunning = &JsonRpcError{Code: JsonRpcErrorCodePluginNotRunning, Message: "Plugin not running"}
)

Functions

func EnableExtendModules

func EnableExtendModules(p *KernelPlugin, rt *goja.Runtime) (err error)

EnableExtendModules registers extended modules (e.g. url, buffer) to the plugin's goja runtime.

func EnableSiyuanModule

func EnableSiyuanModule(p *KernelPlugin, rt *goja.Runtime) (err error)

EnableSiyuanModule injects all siyuan.* APIs into the plugin's goja global context.

func HandleHttpRequest

func HandleHttpRequest(c *gin.Context, scope AccessScope)

func HandleRpcHttp

func HandleRpcHttp(c *gin.Context)

HandleRpcHttp handles POST /api/plugin/rpc/:name Supports single call, batch call, and notification (no response for notification).

func HandleRpcWebSocket

func HandleRpcWebSocket(c *gin.Context)

HandleRpcWebSocket handles GET /ws/plugin/rpc/:name Supports single call, batch call, notification, and server push notifications.

func InitManager

func InitManager()

InitManager initializes the global PluginManager singleton and starts it.

func NewDataObject

func NewDataObject(p *KernelPlugin, rt *goja.Runtime, data []byte) (*goja.Object, error)

NewDataObject creates a new JS object with text(), json(), buffer() and arrayBuffer() methods for the given data.

func ObjectFreeze

func ObjectFreeze(rt *goja.Runtime, obj *goja.Object) error

ObjectFreeze calls Object.freeze() on the given goja object.

func ObjectSeal

func ObjectSeal(rt *goja.Runtime, obj *goja.Object) error

ObjectSeal calls Object.seal() on the given goja object.

func ObjectSetDataMethods

func ObjectSetDataMethods(p *KernelPlugin, rt *goja.Runtime, object *goja.Object, data []byte) (err error)

ObjectSetDataMethods attaches text(), json(), buffer() and arrayBuffer() methods to a JS object, each returning a Promise that resolves with the corresponding representation of data.

Types

type AccessScope

type AccessScope string

type CallResult

type CallResult FunctionResult[goja.Value]

func (*CallResult) TaskResult

func (r *CallResult) TaskResult() *TaskResult

type EventSourceState

type EventSourceState int64
const (
	EventSourceConnecting EventSourceState = iota
	EventSourceOpen
	EventSourceClosed
)

type FunctionResult

type FunctionResult[T any] struct {
	Value T
	Error error
}

type HttpResponse

type HttpResponse struct {
	StatusCode int                 `json:"statusCode"` // e.g. 200
	Headers    map[string][]string `json:"headers"`    // e.g. {"Content-Type": ["application/json"], "Set-Cookie": ["siyuan=abc123; Path=/; HttpOnly"]}
	Cookies    []*http.Cookie      `json:"cookies"`    // e.g. [{"Name": "plugin-sample", "Value": "abc123", "Quoted": false, "Path": "/plugin/private/plugin-sample/", "Domain": "", "Expires": "0001-01-01T00:00:00Z", "RawExpires": "", "MaxAge": 0, "Secure": false, "HttpOnly": false, "SameSite": 0, "Partitioned": false, "Raw": "", "Unparsed": null}]
	Body       *ResponseBody       `json:"body"`       // response body, can be either raw data or a file
}

type JsonRpcError

type JsonRpcError struct {
	Code    JsonRpcErrorCode `json:"code"`
	Message string           `json:"message"`
	Data    any              `json:"data,omitempty"`
}

JsonRpcError represents a JSON-RPC 2.0 error.

func (*JsonRpcError) Error

func (e *JsonRpcError) Error() string

type JsonRpcErrorCode

type JsonRpcErrorCode int
const (
	JsonRpcVersion = "2.0"

	JsonRpcErrorCodeParseError     JsonRpcErrorCode = -32700
	JsonRpcErrorCodeInvalidRequest JsonRpcErrorCode = -32600
	JsonRpcErrorCodeMethodNotFound JsonRpcErrorCode = -32601
	JsonRpcErrorCodeInvalidParams  JsonRpcErrorCode = -32602
	JsonRpcErrorCodeInternalError  JsonRpcErrorCode = -32603

	// Server-defined error codes (-32099 to -32000)
	JsonRpcErrorCodePluginNotLoaded  JsonRpcErrorCode = -32001
	JsonRpcErrorCodePluginNotRunning JsonRpcErrorCode = -32002
)

type JsonRpcErrorResponse

type JsonRpcErrorResponse struct {
	JsonRpc string        `json:"jsonrpc"`
	Error   *JsonRpcError `json:"error"`
	ID      any           `json:"id"`
}

JsonRpcErrorResponse represents a JSON-RPC 2.0 error response. error MUST be present; result MUST NOT be present.

type JsonRpcProcessingRequest

type JsonRpcProcessingRequest struct {
	Request *JsonRpcRequest       // The parsed request, or nil if the request was invalid
	Error   *JsonRpcErrorResponse // The error if the request was invalid, or nil if the request is valid
}

JsonRpcProcessingRequest represents the result of parsing and validating a single JSON-RPC request, including any error if the request is invalid.

type JsonRpcProcessingResponse

type JsonRpcProcessingResponse struct {
	Response *JsonRpcRequestResponse // The success response, or nil if the request was a notification or the response is an error
	Error    *JsonRpcErrorResponse   // The error response, or nil if the request was a notification or the response is a success
}

JsonRpcProcessingResponse represents the response to a JSON-RPC request, including either the success response or the error response (but not both).

  • For notifications, both fields will be nil, indicating that no response should be sent.
  • For successful requests, Response will be non-nil and Error will be nil.
  • For failed requests, Error will be non-nil and Response will be nil.

func (*JsonRpcProcessingResponse) JsonRpcResponse

func (r *JsonRpcProcessingResponse) JsonRpcResponse() any

JsonRpcResponse returns the appropriate response (either success or error) to be sent back to the client, or nil if this is a notification and no response should be sent.

type JsonRpcRequest

type JsonRpcRequest struct {
	JsonRpc string             `json:"jsonrpc"`
	Method  string             `json:"method"`
	Params  util.Optional[any] `json:"params"`
	ID      util.Optional[any] `json:"id"`
}

JsonRpcRequest represents a JSON-RPC 2.0 request.

func (*JsonRpcRequest) IsNotification

func (r *JsonRpcRequest) IsNotification() bool

IsNotification returns true if this request is a notification (no ID field).

func (JsonRpcRequest) MarshalJSON

func (r JsonRpcRequest) MarshalJSON() ([]byte, error)

func (*JsonRpcRequest) UnmarshalJSON

func (r *JsonRpcRequest) UnmarshalJSON(data []byte) error

func (*JsonRpcRequest) Validate

func (r *JsonRpcRequest) Validate() *JsonRpcError

Validate validates the JSON-RPC request structure.

type JsonRpcRequestProcessingResults

type JsonRpcRequestProcessingResults struct {
	Batch       bool                  // Whether the original request was a batch (array) or single request
	GlobalError *JsonRpcErrorResponse // If the entire request is invalid
	Requests    []*JsonRpcProcessingRequest
}

JsonRpcRequestProcessingResults represents the results of parsing and validating JSON-RPC requests, including any global error and the individual results for each request in a batch.

type JsonRpcRequestResponse

type JsonRpcRequestResponse struct {
	JsonRpc string `json:"jsonrpc"`
	Result  any    `json:"result"`
	ID      any    `json:"id"`
}

JsonRpcRequestResponse represents a JSON-RPC 2.0 success response. result MUST be present (even if null); error MUST NOT be present.

type KernelPlugin

type KernelPlugin struct {
	*model.Petal
	// contains filtered or unexported fields
}

KernelPlugin represents a single kernel-side plugin instance.

func NewKernelPlugin

func NewKernelPlugin(ctx context.Context, petal *model.Petal) *KernelPlugin

func (*KernelPlugin) BroadcastNotification

func (p *KernelPlugin) BroadcastNotification(method string, params util.Optional[any])

BroadcastNotification sends a JSON-RPC 2.0 notification to all inbound RPC WebSocket clients.

func (*KernelPlugin) Clear

func (p *KernelPlugin) Clear()

Clear removes all registered MCP tools and RPC methods for this plugin. Called on plugin stop to prevent residue in global registries.

func (*KernelPlugin) Eval

func (p *KernelPlugin) Eval(rt *goja.Runtime, code string) (goja.Value, error)

Eval evaluates JavaScript code in the plugin's goja runtime, returning the result or error.

func (*KernelPlugin) GetRpcMethodsInfo

func (p *KernelPlugin) GetRpcMethodsInfo() (methods []*RpcMethodInfo)

GetRpcMethodsInfo returns a list of registered RPC methods with their descriptions.

func (*KernelPlugin) InitRuntime

func (p *KernelPlugin) InitRuntime() (err error)

InitRuntime initializes the goja runtime and evaluates kernel.js.

func (*KernelPlugin) State

func (p *KernelPlugin) State() PluginState

State returns the current plugin state (safe for concurrent reads).

func (*KernelPlugin) TrackRpcSocket

func (p *KernelPlugin) TrackRpcSocket(conn *gws.Conn)

TrackRpcSocket adds a RPC WebSocket connection to the plugin's tracked list.

func (*KernelPlugin) UntrackRpcSocket

func (p *KernelPlugin) UntrackRpcSocket(conn *gws.Conn)

UntrackRpcSocket removes a gws WebSocket connection from the plugin's tracked list.

type PluginInfo

type PluginInfo struct {
	Name      string           `json:"name"`
	State     string           `json:"state"`
	StateCode int              `json:"stateCode"`
	Methods   []*RpcMethodInfo `json:"methods"`
}

type PluginManager

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

PluginManager discovers, loads, starts, and stops kernel plugins.

func GetManager

func GetManager() *PluginManager

GetManager returns the singleton PluginManager.

func (*PluginManager) GetLoadedPlugin

func (m *PluginManager) GetLoadedPlugin(name string) (plugin *PluginInfo, found bool)

GetLoadedPlugin returns the plugin info for a loaded KernelPlugin by name, or nil.

func (*PluginManager) GetLoadedPluginsInfo

func (m *PluginManager) GetLoadedPluginsInfo() (plugins []*PluginInfo)

GetLoadedPluginInfo returns a list of all loaded plugins with their RPC method info.

func (*PluginManager) GetPlugin

func (m *PluginManager) GetPlugin(name string) *KernelPlugin

GetPlugin returns a loaded KernelPlugin by name, or nil.

func (*PluginManager) Start

func (m *PluginManager) Start()

Start loads and starts all kernel-eligible plugins. Called from main.go after model initialization.

func (*PluginManager) StartPlugin

func (m *PluginManager) StartPlugin(petal *model.Petal) (ok bool)

StartPlugin starts a single kernel plugin. Called when a petal is enabled via SetPetalEnabled.

func (*PluginManager) State

func (m *PluginManager) State() PluginManagerState

func (*PluginManager) Stop

func (m *PluginManager) Stop()

Stop shuts down all running kernel plugins. Called from model.Close() before process exit.

func (*PluginManager) StopPlugin

func (m *PluginManager) StopPlugin(petal *model.Petal) (ok bool)

StopPlugin stops a single kernel plugin. Called when a petal is disabled via SetPetalEnabled.

type PluginManagerState

type PluginManagerState int64
const (
	PluginManagerStateStopped PluginManagerState = iota
	PluginManagerStateRunning
)

type PluginState

type PluginState int64
const (
	PluginStateReady PluginState = iota
	PluginStateLoading
	PluginStateRunning
	PluginStateStopping
	PluginStateStopped
	PluginStateError
)

func (PluginState) String

func (s PluginState) String() string

type Printer

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

func (*Printer) Error

func (p *Printer) Error(s string)

func (*Printer) Log

func (p *Printer) Log(s string)

func (*Printer) Warn

func (p *Printer) Warn(s string)

type Promise

type Promise struct {
	Resolve func(reason interface{}) error
	Reject  func(reason interface{}) error
}

type R

type R map[string]any

type Request

type Request struct {
	URL     RequestUrl     `json:"url"`
	Request RequestContent `json:"request"`
	Context RequestContext `json:"context"`
	Port    *goja.Object   `json:"port"`
}

type RequestBody

type RequestBody struct {
	Form *RequestForm `json:"form"` // parsed form data if Content-Type is application/x-www-form-urlencoded or multipart/form-data
	Data any          `json:"data"` // *[]byte | *goja.Object, content of all request body (if form != nil, it will be an empty byte array)
}

type RequestContent

type RequestContent struct {
	/* Request Line */
	Method     string `json:"method"`     // e.g. "GET"
	URI        string `json:"uri"`        // e.g. "/plugin/public/sample/api/hello?a=1&b=2"
	Proto      string `json:"proto"`      // e.g. "HTTP/1.1"
	ProtoMajor int    `json:"protoMajor"` // e.g. 1
	ProtoMinor int    `json:"protoMinor"` // e.g. 1

	/* Request Headers */
	Headers map[string][]string `json:"headers"` // e.g. {"Content-Type": ["application/json"], "Accept": ["*/*"]}
	Cookies map[string][]string `json:"cookies"` // e.g. {"siyuan": ["abc123"]}

	ContentType   string `json:"contentType"`   // e.g. "application/json"
	ContentLength int64  `json:"contentLength"` // e.g. 123
	Referer       string `json:"referer"`       // e.g. "http://127.0.0.1:6806/stage/build/app/"
	UserAgent     string `json:"userAgent"`     // e.g. "SiYuan/3.6.5 https://b3log.org/siyuan Electron Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) SiYuan/3.6.5 Chrome/144.0.7559.236 Electron/40.9.1 Safari/537.36"

	/* Request Body */
	Body RequestBody `json:"body"`
}

type RequestContext

type RequestContext struct {
	Path     string `json:"path"`     // e.g. "/api/hello"
	FullPath string `json:"fullPath"` // e.g. "/plugin/public/:name/*path"

	ClientIP   string `json:"clientIp"`   // e.g. "127.0.0.1"
	RemoteIP   string `json:"remoteIp"`   // e.g. "127.0.0.1"
	RemoteAddr string `json:"remoteAddr"` // e.g. "127.0.0.1:54321"

	Params map[string][]string `json:"params"` // e.g. [{"Key": "name", "Value": "plugin-sample"}, {"Key": "path", "Value": "/api/hello"}]

	IsWebsocket bool `json:"-"`
	IsSse       bool `json:"-"`
}

type RequestFile

type RequestFile struct {
	Filename string              `json:"filename"` // e.g. "hello.txt"
	Headers  map[string][]string `json:"headers"`  // e.g. {"Content-Disposition": ["form-data; name=\"file1\"; filename=\"hello.txt\""], "Content-Type": ["text/plain"]}
	Size     int64               `json:"size"`     // e.g. 123
	Data     any                 `json:"data"`     // *[]byte | *goja.Object, content of the file
}

type RequestForm

type RequestForm struct {
	Value map[string][]string       `json:"values"` // e.g. {"field1": ["value1"], "field2": ["value2-1", "value2-2"]}
	File  map[string][]*RequestFile `json:"files"`  // e.g. {"file1": [{"Filename": "hello.txt", "Headers": {"Content-Disposition": ["form-data; name=\"file1\"; filename=\"hello.txt\""], "Content-Type": ["text/plain"]}, "Size": 123, "Data": []byte{...}}]}
}

type RequestType

type RequestType string

type RequestUrl

type RequestUrl struct {
	User            *RequestUser `json:"user"`
	Host            string       `json:"host"`     // e.g. 127.0.0.1:6806
	Path            string       `json:"path"`     // e.g. /plugin/public/sample/api/hello/a space
	EscapedPath     string       `json:"pathname"` // e.g. /plugin/public/sample/api/hello/a%20space
	Fragment        string       `json:"fragment"` // e.g. "hash abc"
	EscapedFragment string       `json:"hash"`     // e.g. "hash%20abc"
	RawQuery        string       `json:"search"`   // e.g. a=1&b=2

	Query map[string][]string `json:"query"` // e.g. {"a": ["1"], "b": ["2"]}
}

type RequestUser

type RequestUser struct {
	Username string `json:"username"` // e.g. "alice"
	Password string `json:"password"` // e.g. "123456"
}

type ResponseBody

type ResponseBody struct {
	Data     *ResponseSerializedData `json:"data"`     // if the response is serialized data, Data will be non-nil.
	File     *ResponseFile           `json:"file"`     // if the response is a file, File will be non-nil.
	String   *ResponseString         `json:"string"`   // if the response is a formatted string, String will be non-nil.
	Raw      *ResponseRawData        `json:"raw"`      // if the response is raw data, Raw will be non-nil.
	Redirect *ResponseRedirect       `json:"redirect"` // if the response is a redirect, Redirect will be non-nil.
	Proxy    *ResponseProxy          `json:"proxy"`    // if the response is a streaming proxy, Proxy will be non-nil.
}

type ResponseFile

type ResponseFile struct {
	Name string `json:"name"` // e.g. "index.html". If Name is not empty, the file will be sent with Content-Disposition header.
	Path string `json:"path"` // e.g. "/data/plugins/<plugin-name>/app/index.html"
}

type ResponseProxy

type ResponseProxy struct {
	URL     string              `json:"url"`     // target http/https URL
	Method  string              `json:"method"`  // optional, defaults to the incoming request method, only GET/HEAD are supported
	Headers map[string][]string `json:"headers"` // request headers forwarded to the target
}

type ResponseRawData

type ResponseRawData struct {
	ContentType string `json:"contentType"` // e.g. "image/png"
	Data        []byte `json:"data"`        // content of the response body
}

type ResponseRedirect

type ResponseRedirect struct {
	Location string `json:"location"` // the URL to redirect to
}

type ResponseSerializedData

type ResponseSerializedData struct {
	Type SerializedType `json:"type"` // the serialization type, e.g. JSON, XML, etc.
	Data any            `json:"data"` // the data to be serialized and sent in the response body
}

type ResponseString

type ResponseString struct {
	Format string `json:"format"` // string formatting template (Go string formatting style)
	Values []any  `json:"values"` // the values to be formatted into the template
}

type RpcMethod

type RpcMethod struct {
	Name         string
	Descriptions []string
	Method       goja.Callable
}

type RpcMethodInfo

type RpcMethodInfo struct {
	Name         string   `json:"name"`
	Descriptions []string `json:"descriptions"`
}

type SerializedType

type SerializedType string

type TaskCallback

type TaskCallback func(rt *goja.Runtime, result any, err error)

type TaskExecutor

type TaskExecutor func(rt *goja.Runtime) (result any, err error)

type TaskResult

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

type WebSocketState

type WebSocketState int64
const (
	WebSocketReadyStateConnecting WebSocketState = iota
	WebSocketReadyStateOpen
	WebSocketReadyStateClosing
	WebSocketReadyStateClosed
)

type Worker

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

func (*Worker) Run

func (w *Worker) Run(executor TaskExecutor, callback TaskCallback) error

func (*Worker) RunSync

func (w *Worker) RunSync(fn TaskExecutor) (result any, err error)

func (*Worker) Start

func (w *Worker) Start(loop *eventloop.EventLoop)

type WsEventHandler

type WsEventHandler struct {
	gws.BuiltinEventHandler
	// contains filtered or unexported fields
}

WsEventHandler implements gws.Event with settable callback fields so closures capturing the JS runtime context can be assigned after the upgrader/dialer is created.

func (*WsEventHandler) BindOnClose

func (h *WsEventHandler) BindOnClose(manager *WsManager)

func (*WsEventHandler) BindOnMessage

func (h *WsEventHandler) BindOnMessage(manager *WsManager)

func (*WsEventHandler) BindOnOpen

func (h *WsEventHandler) BindOnOpen(manager *WsManager)

func (*WsEventHandler) BindOnPing

func (h *WsEventHandler) BindOnPing(manager *WsManager)

func (*WsEventHandler) BindOnPong

func (h *WsEventHandler) BindOnPong(manager *WsManager)

func (*WsEventHandler) OnClose

func (h *WsEventHandler) OnClose(socket *gws.Conn, err error)

func (*WsEventHandler) OnMessage

func (h *WsEventHandler) OnMessage(socket *gws.Conn, message *gws.Message)

func (*WsEventHandler) OnOpen

func (h *WsEventHandler) OnOpen(socket *gws.Conn)

func (*WsEventHandler) OnPing

func (h *WsEventHandler) OnPing(socket *gws.Conn, payload []byte)

func (*WsEventHandler) OnPong

func (h *WsEventHandler) OnPong(socket *gws.Conn, payload []byte)

type WsManager

type WsManager struct {
	BufferedAmount *atomic.Int64

	InvokeHook    func(rt *goja.Runtime, eventName string, args ...goja.Value)
	SetProtocol   func(rt *goja.Runtime, protocol string)
	SetReadyState func(rt *goja.Runtime, state WebSocketState)
}

Jump to

Keyboard shortcuts

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