简体中文 English 繁體中文 日本語 Русский
本文为静态镜像,内容以交互版为准 在交互式文档中心打开 →

Core Concepts

This guide introduces the core concepts of ErisPulse, helping you understand the framework's design philosophy and basic architecture.

Event-Driven Architecture

ErisPulse adopts an event-driven architecture, where all interactions are passed and processed through events.

Event Flow

User sends message
      │
      ▼
Platform receives
      │
      ▼
Adapter receives native platform event
      │
      ▼
Converts to OneBot12 standard event
      │
      ▼
Submits to event system
      │
      ▼
Distributes to registered handlers
      │
      ▼
Module processes event
      │
      ▼
Sends response via adapter
      │
      ▼
Platform displays to user

OneBot12 Standard

ErisPulse uses OneBot12 as its core event standard. OneBot12 is a generic chatbot application programming interface standard that defines a unified event format.

All adapters convert platform-specific events into OneBot12 format, ensuring code consistency.

Core Components

1. SDK Object

The SDK is the unified entry point for all features, providing access to core components.

from ErisPulse import sdk

# Access core modules
sdk.storage    # Storage system
sdk.config     # Configuration system
sdk.logger     # Logging system
sdk.adapter    # Adapter system
sdk.module     # Module system
sdk.router     # Router system
sdk.client     # HTTP client
sdk.lifecycle  # Lifecycle system

2. Event Object

The Event object encapsulates event data and provides convenient access methods.

@command("info")
async def info_handler(event):
    # Get event information
    event_id = event.get_id()
    user_id = event.get_user_id()
    platform = event.get_platform()
    text = event.get_text()
    
    # Send reply
    await event.reply(f"User: {user_id}, Platform: {platform}")

3. Adapters

Adapters serve as bridges between ErisPulse and external platforms.

Responsibilities:

Example Adapters:

4. Modules

Modules are the basic units for functionality extensions, capable of:

Module Discovery Mechanism

ErisPulse discovers installed modules via Python's importlib.metadata.entry_points. Modules declare entry points in pyproject.toml:

[project.entry-points."erispulse.module"]
MyModule = "my_package:Main"

During SDK initialization, all entry points under the erispulse.module group are scanned, the module class is registered to ModuleManager, and then initialized in topological order based on dependencies.

Minimal Viable Module

from ErisPulse.Core.Bases import BaseModule
from ErisPulse import sdk

class Main(BaseModule):
    def __init__(self):
        self.sdk = sdk
        self.logger = sdk.logger.get_child("MyModule")

    async def on_load(self, event):
        self.logger.info("Module loaded")

    async def on_unload(self, event):
        self.logger.info("Module unloaded")

Module Lifecycle

Loading Strategy

Declare the module's loading behavior using get_load_strategy():

from ErisPulse.loaders import ModuleLoadStrategy

class Main(BaseModule):
    @staticmethod
    def get_load_strategy():
        return ModuleLoadStrategy(
            lazy_load=True,   # Whether to lazy load (default: True)
            priority=0        # Loading priority; higher values are initialized first
        )

For detailed information about the lazy loading mechanism, refer to Lazy Loading System.

Event Types

ErisPulse supports five types of events:

Event Type Decorator Description
Message Event @message.on_message() Any message sent by the user (private chat, group chat)
Command Event @command("name") Messages starting with a command prefix (e.g., /hello)
Notice Event @notice.on_friend_add() etc. System notifications (friend added, group member changes, etc.)
Request Event @request.on_friend_request() etc. User requests (friend requests, group invitations)
Meta Event @meta.on_connect() etc. System-level events (connection, disconnection, heartbeat)

For detailed usage and code examples of each event type, refer to Event Handling Introduction.

Core Module Descriptions

Storage (Storage)

A key-value storage system based on SQLite, used for persistent data storage.

# Set value
sdk.storage.set("key", "value")

# Get value
value = sdk.storage.get("key", "default_value")

# Batch operations
sdk.storage.set_multi({
    "key1": "value1",
    "key2": "value2"
})

# Transactions
with sdk.storage.transaction():
    sdk.storage.set("key1", "value1")
    sdk.storage.set("key2", "value2")

Config (Configuration)

TOML-based configuration file management.

# Get configuration
config = sdk.config.getConfig("MyModule", {})

# Set configuration
sdk.config.setConfig("MyModule", {"key": "value"})

# Read nested configuration
value = sdk.config.getConfig("MyModule.subkey", "default")

Logger (Logging)

A modular logging system.

# Log messages
sdk.logger.info("This is an info message")
sdk.logger.warning("This is a warning message")
sdk.logger.error("This is an error message")

# Get child logger
child_logger = sdk.logger.get_child("submodule")
child_logger.info("Submodule log message")

Attribute Access Syntactic Sugar

In addition to using the get_child() method, you can also create a child logger using attribute access, which is a more concise syntactic sugar:

# Create child logger using attribute access
sdk.logger.mymodule.info("Module message")

# Supports nested access
sdk.logger.mymodule.database.info("Database message")

Router (Routing)

HTTP and WebSocket routing management, based on FastAPI + Uvicorn. Supports decorator-based routing, middleware, grouping, rate limiting, and CORS.

from ErisPulse.Core import HttpRequest

@sdk.router.get("MyModule", "/api")
async def handler(request: HttpRequest):
    data = await request.json()
    return {"status": "ok"}

For the complete routing API (WebSocket, middleware, rate limiting, CORS, etc.), refer to Router Manager.

Client (Network Client)

A unified network client that aggregates HTTP requests, WebSocket connections, connection pool management, automatic retries, timeout control, request statistics, and lifecycle event integration.

from ErisPulse.Core import client

# HTTP request
resp = await client.get("https://api.example.com/users")
data = await resp.json()

# With retry and timeout
resp = await client.get(url, timeout=30, max_retries=3)

# WebSocket connection
ws = await client.ws_connect("wss://example.com/ws")
async for text in ws.iter_text():
    await ws.send_text(f"Echo: {text}")

For the complete network client API, refer to Network Client.

SendDSL Message Sending

Adapters provide a chain-call interface for message sending.

Basic Sending

# Get adapter instance
yunhu = sdk.adapter.get("yunhu")

# Send message
await yunhu.Send.To("user", "U1001").Text("Hello")

# Specify sending account
await yunhu.Send.Using("bot1").To("group", "G1001").Text("Group message")

Chain Modifiers

# @ user
await yunhu.Send.To("group", "G1001").At("U2001").Text("@ message")

# Reply to message
await yunhu.Send.To("group", "G1001").Reply("msg123").Text("Reply")

# @ all
await yunhu.Send.To("group", "G1001").AtAll().Text("Announcement")

Event Reply Methods

The Event object provides convenient reply methods:

@command("test")
async def test_handler(event):
    # Simple text reply
    await event.reply("Reply content")
    
    # Send image
    await event.reply("http://example.com/image.jpg", method="Image")
    
    # Send voice
    await event.reply("http://example.com/voice.mp3", method="Voice")

Lazy Loading System

ErisPulse enables module lazy loading by default. Modules are only initialized when first accessed (e.g., sdk.MyModule), significantly improving startup speed.

from ErisPulse.loaders import ModuleLoadStrategy

class Main(BaseModule):
    @staticmethod
    def get_load_strategy():
        return ModuleLoadStrategy(
            lazy_load=True,   # Enable lazy loading (default)
            priority=0        # Loading priority; higher values are initialized first
        )

Scenarios requiring disabling lazy loading (lazy_load=False):

For detailed information about the lazy loading mechanism and considerations, refer to Lazy Loading System.

Next Steps