Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions crates/driver-abi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "driver-abi"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true

[dependencies]
observation-model = { path = "../observation-model" }
driver-contract = { path = "../driver-contract" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
use observation_model::{DriverErrorInfo, RawReadResult};
use serde::{Deserialize, Deserializer, Serialize};

use crate::items::DriverCommand;
use crate::results::{
use driver_contract::items::DriverCommand;
use driver_contract::results::{
AddressMetadata, DriverBrowseNode, RawCommandResult, RawEvent, RawHistoryPage, RawWriteResult,
SubscriptionRequest,
};
use crate::{HistoryRequest, ProtocolCapabilities};
use driver_contract::{HistoryRequest, ProtocolCapabilities};

/// 本 SDK 实现的 ABI 版本对应的 Envelope schema 版本(ABI 1.0)。
pub const SCHEMA_VERSION: &str = "1.0";
Expand Down Expand Up @@ -268,7 +268,7 @@ mod tests {
use observation_model::{RawValue, TimestampNs};

use super::*;
use crate::results::RawEventKind;
use driver_contract::results::RawEventKind;

#[test]
fn read_envelope_exact_json() {
Expand Down
23 changes: 23 additions & 0 deletions crates/driver-abi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//! driver-abi:跨动态库边界的稳定 C ABI 类型(Runtime V2 方案 §6.2 Normative)。
//!
//! 本 crate 是原 `driver-sdk::abi` 的目标归属,专门保存 C ABI 类型:
//! `FfiStr` / `FfiSlice` / `FfiOwnedBuffer`、`DriverHandle`、`DriverApiV1`、
//! ABI tag / envelope 与 entry symbol 常量。
//!
//! # 规则(§6.2)
//!
//! - 所有跨 ABI 类型必须 `#[repr(C)]` 或显式 `ptr + len`;
//! - `driver-contract` 不依赖本 crate(§36 依赖方向约束);envelope JSON 中
//! 内嵌的语义类型(`DriverCommand` 等)引用自 `driver-contract`,
//! 不在此复制第二份定义;
//! - `native-driver-loader` 和 Native Driver 可以依赖本 crate;
//! - ABI v1/v2 在同一 crate 内按模块版本化,但不得把 loader 行为混进 ABI 定义。

pub mod envelope;
pub mod tag;
pub mod v1;

pub use v1::{
ABI_MAJOR, ABI_MINOR, DriverApiV1, DriverHandle, ENTRY_SYMBOL, FfiEventCallback,
FfiOwnedBuffer, FfiReadItem, FfiSlice, FfiStr, FfiWriteItem,
};
File renamed without changes.
3 changes: 0 additions & 3 deletions crates/driver-sdk/src/abi.rs → crates/driver-abi/src/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@
//! 谁分配,谁释放:Plugin 返回的 owned buffer 必须通过 `free_buffer` 释放;
//! 请求参数默认由 Core 持有,Plugin 只能在调用期内借用。

pub mod envelope;
pub mod tag;

use std::ffi::c_void;

/// ABI 主版本(§18):`Core 1.x 可加载 Plugin 1.0 ~ 1.x,不能加载 2.x`。
Expand Down
13 changes: 13 additions & 0 deletions crates/driver-contract/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "driver-contract"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true

[dependencies]
observation-model = { path = "../observation-model" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
async-trait = "0.1"
tokio = { version = "1", features = ["sync"] }
File renamed without changes.
129 changes: 129 additions & 0 deletions crates/driver-contract/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
//! 调用级错误模型 V2(Runtime V2 方案 §28 Normative)。
//!
//! 保持现有 `observation_model::DriverErrorInfo` 的公开语义不变;本模块新增
//! Runtime 内部使用的调用级分类包装 [`DriverCallError`]:
//!
//! - `RawReadResult.error` 等现有逐项错误仍保持 `DriverErrorInfo` 语义;
//! - Host/Session 级失败使用 `DriverCallError`,到 Profile/Domain 映射前
//! 再落回既有 Quality 规则(方案 §6.1)。
//!
//! # 北向边界(§28.1)
//!
//! `DriverErrorCategory` 是 Runtime 内部分类,**不得直接成为 REST v1 / MQTT
//! 的新公开枚举**:`DriverCallError.info.code` 经 control-engine 现有稳定码
//! 白名单映射(未知码归一 `driver_error`);MVP 的 `HostUnavailable` 不新增
//! REST code——调用级失败复用 `driver_call_failed`,连接 CircuitOpen 复用
//! `connection_failed`。

use serde::{Deserialize, Serialize};

/// Driver 调用失败的 Runtime 内部分类(§28)。
///
/// 跨 C ABI 时由 `driver-abi` 层映射为稳定 `u32` category code;
/// 禁止把 Rust enum 默认布局直接暴露给插件(§28)。
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum DriverErrorCategory {
/// 配置非法(连接参数等)。
Config,
/// 地址无法被 Driver 解析或校验失败。
InvalidAddress,
/// 能力未声明(capability 为 false 时的标准拒绝,§15)。
Unsupported,

/// 连接建立失败。
ConnectionFailed,
/// 已建立连接意外中断。
ConnectionLost,
/// 调用超时。
Timeout,

/// 协议帧/序列违反协议规范。
ProtocolViolation,
/// 设备显式拒绝(协议异常码等)。
DeviceRejected,

/// Driver 实现内部 panic(进程内可观测)。
DriverPanic,
/// Driver 进程崩溃(Host 场景)。
DriverCrashed,
/// Driver Host 不可达/不可用。
HostUnavailable,

/// 取消(未开始或可证明未生效)。
Cancelled,
/// 截止时间已过(含队列等待期过期)。
DeadlineExceeded,
}

/// Host/Session 级调用错误包装(§28)。
///
/// `info` 携带稳定码与消息(北向白名单映射的输入),`category` 供 Runtime
/// 做故障恢复决策与指标分类(内部使用,不北向透传)。
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct DriverCallError {
pub info: crate::DriverErrorInfo,
pub category: DriverErrorCategory,
}

impl DriverCallError {
/// 以稳定码 + 分类构造(message 由调用方补足)。
pub fn new(
code: impl Into<String>,
message: impl Into<String>,
category: DriverErrorCategory,
) -> Self {
Self {
info: crate::DriverErrorInfo {
code: code.into(),
message: message.into(),
protocol_code: None,
retryable: false,
},
category,
}
}
}

impl std::fmt::Display for DriverCallError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{} (category={:?}): {}",
self.info.code, self.category, self.info.message
)
}
}

impl std::error::Error for DriverCallError {}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn call_error_round_trips_through_json() {
let err = DriverCallError {
info: crate::DriverErrorInfo {
code: "timeout".to_owned(),
message: "读取超时".to_owned(),
protocol_code: None,
retryable: true,
},
category: DriverErrorCategory::Timeout,
};
let json = serde_json::to_string(&err).expect("序列化失败");
let back: DriverCallError = serde_json::from_str(&json).expect("反序列化失败");
assert_eq!(err, back);
}

#[test]
fn category_is_internal_not_northbound() {
// §28.1:分类是 Runtime 内部概念,serde 表示仅供内部日志/metrics 使用;
// 稳定码经 info.code 进入既有白名单,此处固化 snake_case 形状防漂移。
assert_eq!(
serde_json::to_string(&DriverErrorCategory::HostUnavailable).expect("序列化失败"),
r#""host_unavailable""#
);
}
}
File renamed without changes.
39 changes: 39 additions & 0 deletions crates/driver-contract/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//! driver-contract:Core、Driver Runtime 与 Driver Host 共用的 Rust Driver 语义契约
//! (Runtime V2 方案 §6.1 Normative)。
//!
//! 本 crate 拥有 Driver 调用 payload / result 类型与 Rust `Driver` trait;
//! 不包含 `libloading`、Native C ABI(见 `driver-abi`)、具体协议逻辑和
//! Tokio 调度类型。Raw/Quality 数据类型仍以 `observation-model` 为唯一事实来源,
//! 此处仅 re-export,不复制定义。
//!
//! # 依赖方向(§6.1)
//!
//! ```text
//! observation-model
//! ↑
//! driver-contract
//! ↑
//! device-manager / driver-runtime / driver-host adapters
//! ```
//!
//! 本 crate **不依赖** `driver-abi`;跨动态库边界的 C ABI 类型属于
//! `driver-abi` crate(Runtime V2 方案 §6.2)。

pub mod capabilities;
pub mod driver;
pub mod error;
pub mod items;
pub mod results;

pub use capabilities::ProtocolCapabilities;
pub use driver::Driver;
pub use error::{DriverCallError, DriverErrorCategory};
pub use items::{DriverCommand, DriverReadItem, DriverWriteItem};
pub use results::{
AddressMetadata, DriverBrowseNode, HistoryRequest, RawCommandResult, RawEvent, RawEventKind,
RawHistoryPage, RawWriteResult, SubscriptionId, SubscriptionRequest,
};

// 原始结果边界类型由 observation-model 定义(§7),在此转发以方便使用方。
// Runtime V2 不重写 observation-model,避免同名 Raw 类型出现两份事实来源(§6.1)。
pub use observation_model::{DataType, DriverErrorInfo, RawFieldValue, RawReadResult, RawValue};
File renamed without changes.
4 changes: 3 additions & 1 deletion crates/driver-sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ license.workspace = true

[dependencies]
observation-model = { path = "../observation-model" }
driver-contract = { path = "../driver-contract" }
driver-abi = { path = "../driver-abi" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
async-trait = "0.1"
tokio = { version = "1", features = ["sync"] }
tokio = { version = "1", features = ["sync"] }
Loading
Loading