#![warn(missing_docs)]
#![warn(clippy::all)]
#[cfg(feature = "axum")]
pub mod axum_integration;
#[cfg(feature = "axum")]
pub use axum_integration as axum;
#[cfg(feature = "tower")]
pub mod tower_integration;
#[cfg(feature = "tower")]
pub use tower_integration as tower;
#[cfg(feature = "grpc")]
pub mod grpc_integration;
#[cfg(feature = "grpc")]
pub use grpc_integration as grpc;
#[cfg(feature = "actix")]
pub mod actix_integration;
#[cfg(feature = "actix")]
pub use actix_integration as actix;
mod common;
pub use common::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, thiserror::Error)]
pub enum EcosystemError {
#[error("Kernel not found: {0}")]
KernelNotFound(String),
#[error("Kernel execution failed: {0}")]
ExecutionFailed(String),
#[error("Serialization error: {0}")]
SerializationError(String),
#[error("Invalid request: {0}")]
InvalidRequest(String),
#[error("Authentication required")]
AuthenticationRequired,
#[error("Permission denied: {0}")]
PermissionDenied(String),
#[error("Rate limit exceeded")]
RateLimitExceeded,
#[error("Service unavailable: {0}")]
ServiceUnavailable(String),
#[error("Internal error: {0}")]
InternalError(String),
}
impl From<rustkernel_core::error::KernelError> for EcosystemError {
fn from(err: rustkernel_core::error::KernelError) -> Self {
match err {
rustkernel_core::error::KernelError::KernelNotFound(id) => {
EcosystemError::KernelNotFound(id)
}
rustkernel_core::error::KernelError::Unauthorized(msg) => {
EcosystemError::PermissionDenied(msg)
}
rustkernel_core::error::KernelError::ServiceUnavailable(msg) => {
EcosystemError::ServiceUnavailable(msg)
}
_ => EcosystemError::ExecutionFailed(err.to_string()),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KernelRequest {
pub kernel_id: String,
pub input: serde_json::Value,
#[serde(default)]
pub metadata: RequestMetadata,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct RequestMetadata {
pub trace_id: Option<String>,
pub span_id: Option<String>,
pub tenant_id: Option<String>,
pub priority: Option<u8>,
pub timeout_ms: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KernelResponse {
pub request_id: String,
pub kernel_id: String,
pub output: serde_json::Value,
pub metadata: ResponseMetadata,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ResponseMetadata {
pub duration_us: u64,
pub backend: String,
pub gpu_memory_bytes: Option<u64>,
pub trace_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ErrorResponse {
pub code: String,
pub message: String,
pub request_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub details: Option<serde_json::Value>,
}
impl ErrorResponse {
pub fn from_error(err: &EcosystemError, request_id: Option<String>) -> Self {
let (code, message) = match err {
EcosystemError::KernelNotFound(id) => {
("KERNEL_NOT_FOUND", format!("Kernel not found: {}", id))
}
EcosystemError::ExecutionFailed(msg) => ("EXECUTION_FAILED", msg.clone()),
EcosystemError::SerializationError(msg) => ("SERIALIZATION_ERROR", msg.clone()),
EcosystemError::InvalidRequest(msg) => ("INVALID_REQUEST", msg.clone()),
EcosystemError::AuthenticationRequired => (
"AUTHENTICATION_REQUIRED",
"Authentication required".to_string(),
),
EcosystemError::PermissionDenied(msg) => ("PERMISSION_DENIED", msg.clone()),
EcosystemError::RateLimitExceeded => {
("RATE_LIMIT_EXCEEDED", "Rate limit exceeded".to_string())
}
EcosystemError::ServiceUnavailable(msg) => ("SERVICE_UNAVAILABLE", msg.clone()),
EcosystemError::InternalError(msg) => ("INTERNAL_ERROR", msg.clone()),
};
Self {
code: code.to_string(),
message,
request_id,
details: None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthResponse {
pub status: HealthStatus,
pub version: String,
pub uptime_secs: u64,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub components: Vec<ComponentHealth>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum HealthStatus {
Healthy,
Degraded,
Unhealthy,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComponentHealth {
pub name: String,
pub status: HealthStatus,
#[serde(skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_response() {
let err = EcosystemError::KernelNotFound("test-kernel".to_string());
let response = ErrorResponse::from_error(&err, Some("req-123".to_string()));
assert_eq!(response.code, "KERNEL_NOT_FOUND");
assert!(response.message.contains("test-kernel"));
assert_eq!(response.request_id, Some("req-123".to_string()));
}
#[test]
fn test_health_response() {
let response = HealthResponse {
status: HealthStatus::Healthy,
version: "0.1.0".to_string(),
uptime_secs: 3600,
components: vec![],
};
let json = serde_json::to_string(&response).unwrap();
assert!(json.contains("healthy"));
}
}