跳到主内容

v0.25.0 版本说明

EnerOS v0.25.0 版本说明

发布日期:2025-09-14 版本代号:Plugin Git Tag:v0.25.0 支持状态:稳定(Stable) Crate 总数:64(新增 4 个) 测试用例数:8100+(新增 500+)

概述

EnerOS v0.25.0「Plugin」是插件系统专项版本,将 EnerOS 从封闭系统升级为可扩展平台。电力行业场景碎片、协议繁多、设备多样,单靠内核无法覆盖所有需求。v0.25.0 引入完整的插件系统,允许第三方以插件形式扩展内核能力——接入私有协议、自定义设备模型、扩展分析算法、集成外部系统——同时保证内核的安全与稳定。

本版本引入了五大核心能力:插件系统(Plugin System)、插件 SDK(Plugin SDK)、动态加载(Dynamic Loading)、插件市场(Plugin Marketplace)、沙箱隔离(Sandbox Isolation)。插件以 WebAssembly(WASM)模块形式分发,在沙箱中运行,通过显式能力授权访问内核资源。

设计哲学上,v0.25.0 坚持「安全优先」——所有插件默认运行在沙箱中,仅能访问显式授予的能力(Capability);「热插拔」——插件支持运行时加载与卸载,无需重启;「可治理」——插件的安装、更新、卸载均有审计记录。

关键数据

指标数值说明
插件加载时间< 50msWASM 模块
插件调用延迟120μs沙箱内
沙箱隔离强度进程级WASM + 能力授权
初始市场插件32 个官方+社区
新增 Crate4插件相关
新增测试500+含安全测试

新特性

1. 插件系统

引入 eneros-plugin Crate,提供完整的插件运行时。插件以 WASM 模块形式存在,通过宿主提供的接口访问内核能力。

插件注册

use eneros_plugin::{PluginManager, Plugin, PluginManifest};

let mut manager = PluginManager::new()
    .sandbox(Sandbox::strict())
    .capability_store(CapabilityStore::new());

// 安装插件
let manifest = PluginManifest::from_file("modbus-advanced.wasm")?;
let plugin: Plugin = manager.install(manifest).await?;

// 授予能力
plugin.grant(Capability::Network("modbus-tcp"))?;
plugin.grant(Capability::Device("read-only"))?;

// 启动插件
plugin.start().await?;

插件清单

# plugin.toml
name = "modbus-advanced"
version = "1.2.0"
author = "EnerOS Community"
description = "高级 Modbus 协议插件"

[capabilities]
network = ["modbus-tcp", "modbus-rtu"]
device = ["read-only"]
storage = ["config"]

[entry]
init = "plugin_init"
poll = "plugin_poll"
cleanup = "plugin_cleanup"

插件类型

类型用途示例
协议适配器设备接入Modbus、IEC 104、DNP3
设备模型设备扩展私有设备参数库
分析算法分析扩展自定义稳定算法
数据源数据集成外部数据库接入
UI 组件界面扩展自定义仪表盘

2. 插件 SDK

引入 eneros-plugin-sdk Crate,为插件开发者提供 Rust SDK。SDK 封装了与宿主的交互逻辑,开发者只需实现 trait 即可。

SDK 示例

use eneros_plugin_sdk::{Plugin, Context, Result};

struct ModbusPlugin {
    client: ModbusClient,
}

impl Plugin for ModbusPlugin {
    fn init(ctx: &Context) -> Result<Self> {
        let addr = ctx.config("address")?;
        let client = ModbusClient::connect(addr)?;
        Ok(ModbusPlugin { client })
    }

    fn poll(&mut self, ctx: &Context) -> Result<()> {
        // 读取寄存器
        let values = self.client.read_holding(0, 10)?;

        // 写入内核时序库
        for (i, v) in values.iter().enumerate() {
            ctx.write_timeseries(
                &format!("modbus.register.{}", i),
                *v as f64,
            )?;
        }
        Ok(())
    }

    fn cleanup(&mut self) -> Result<()> {
        self.client.close();
        Ok(())
    }
}

eneros_plugin_sdk::export_plugin!(ModbusPlugin);

SDK 能力 API

API说明需要能力
ctx.read_bus(id)读母线device.read
ctx.write_timeseries(key, val)写时序storage.write
ctx.send_event(event)发事件event.publish
ctx.http_get(url)HTTP 请求network.http
ctx.log(level, msg)日志(默认)

3. 动态加载

引入 eneros-plugin-loader Crate,支持运行时动态加载与卸载插件,无需重启系统。

热加载

use eneros_plugin_loader::{Loader, LoadOptions};

let loader = Loader::new(&manager);

// 运行时加载
let plugin = loader.load("modbus-advanced-1.2.0.wasm")
    .options(LoadOptions {
        sandbox_level: SandboxLevel::Strict,
        auto_start: true,
    })
    .await?;

// 运行时卸载
loader.unload(&plugin.id).await?;
// 卸载会自动清理资源、断开连接

热更新

// 插件版本升级(零停机)
loader.upgrade(&plugin.id, "modbus-advanced-1.3.0.wasm")
    .migrate_state(true)  // 迁移运行状态
    .await?;

加载性能

操作耗时说明
编译 WASM35msCranelift 后端
实例化8ms含内存分配
启动5msinit 函数
卸载3ms含资源清理

4. 插件市场

引入 eneros-plugin-market Crate,提供插件市场客户端。用户可搜索、安装、更新来自官方与社区的插件。

市场操作

use eneros_plugin_market::{Market, SearchQuery};

let market = Market::connect("https://market.eneros.io")?;

// 搜索插件
let results = market.search(SearchQuery::new("modbus"))
    .category("protocol")
    .sort_by(SortBy::Downloads)
    .top(10).await?;

for p in results {
    println!("{} v{} - 下载 {} 次, 评分 {:.1}",
        p.name, p.version, p.downloads, p.rating);
}

// 安装
market.install("modbus-advanced", "1.2.0").await?;

// 更新检查
let updates = market.check_updates().await?;

官方插件清单

插件名类别版本下载量
modbus-advanced协议1.2.012k
iec104-pro协议2.0.18.5k
dnp3-master协议1.5.03.2k
pq-analyzer分析0.9.25.1k
gridvis-uiUI1.1.09.8k

5. 沙箱隔离

引入 eneros-plugin-sandbox Crate,提供基于 WASM 的沙箱隔离。插件在独立实例中运行,无法直接访问宿主内存或文件系统。

沙箱配置

use eneros_plugin_sandbox::{Sandbox, SandboxLevel, ResourceLimit};

let sandbox = Sandbox::new()
    .level(SandboxLevel::Strict)
    .memory_limit(64 * 1024 * 1024)      // 64 MB
    .cpu_limit(Duration::milliseconds(100)) // 单次调用 100ms
    .fs_access(FsAccess::None)
    .network_access(NetworkAccess::Denied);

manager.set_sandbox(sandbox);

能力授权

// 默认无任何能力,需显式授予
plugin.grant(Capability::Network("modbus-tcp:502"))?;
plugin.grant(Capability::Timeseries("write:modbus.*"))?;
plugin.grant(Capability::Log("info"))?;

// 撤销能力
plugin.revoke(Capability::Network("modbus-tcp:502"))?;

沙箱安全模型

层级隔离机制适用场景
StrictWASM + 能力 + 资源限制不可信插件
StandardWASM + 能力社区插件
TrustedWASM官方插件
Native进程隔离内核模块

改进

  • WASM 引擎:升级至 Wasmtime 25,执行性能提升 18%
  • 能力粒度:能力授权从「类别级」细化至「资源级」
  • 插件审计:所有插件操作(加载/卸载/调用)均记录审计日志
  • 依赖管理:插件间依赖关系自动解析,避免冲突

Bug 修复

  • 修复 eneros-plugin-loader 热更新时状态迁移丢失的问题(#2508)
  • 修复 eneros-plugin-sandbox 在插件崩溃时宿主内存泄漏的问题(#2513)
  • 修复 eneros-plugin-sdk 在并发调用时 Context 死锁的问题(#2519)
  • 修复 eneros-plugin-market 校验签名时未检查证书链的问题(#2524)

破坏性变更

  • PluginManager::install:返回类型从 Result<()> 改为 Result<Plugin>,需保存返回值
  • Capability 枚举Network 变体从 Network 改为 Network(&str),需指定具体地址

升级指南

  1. 执行 cargo update -p eneros-plugin
  2. 更新 PluginManager::install 调用以保存返回的 Plugin
  3. 更新 Capability::Network 授权以指定具体地址
  4. 参考 docs/migration/v0.25.0.md 获取详细迁移步骤