Skip to main content

stynx_code_plugins/application/
loader.rs

1use std::path::Path;
2
3use async_trait::async_trait;
4use serde::Deserialize;
5
6use crate::domain::plugin::{PluginId, PluginInfo, PluginStatus};
7use stynx_code_errors::{AppError, AppResult};
8
9#[async_trait]
10pub trait PluginLoader {
11    async fn load(&self, path: &Path) -> AppResult<PluginInfo>;
12    async fn unload(&self, id: &PluginId) -> AppResult<()>;
13}
14
15#[derive(Debug, Deserialize)]
16struct PluginManifest {
17    id: String,
18    name: String,
19    version: String,
20    description: String,
21}
22
23pub struct SubprocessPluginLoader;
24
25#[async_trait]
26impl PluginLoader for SubprocessPluginLoader {
27    async fn load(&self, path: &Path) -> AppResult<PluginInfo> {
28        let manifest_path = path.join("plugin.json");
29        let contents = tokio::fs::read_to_string(&manifest_path).await.map_err(|e| {
30            AppError::BadRequest(format!(
31                "Failed to read plugin manifest at {}: {e}",
32                manifest_path.display()
33            ))
34        })?;
35
36        let manifest: PluginManifest = serde_json::from_str(&contents).map_err(|e| {
37            AppError::BadRequest(format!("Invalid plugin manifest: {e}"))
38        })?;
39
40        if manifest.id.is_empty() {
41            return Err(AppError::BadRequest("Plugin id must not be empty".into()));
42        }
43        if manifest.name.is_empty() {
44            return Err(AppError::BadRequest("Plugin name must not be empty".into()));
45        }
46        if manifest.version.is_empty() {
47            return Err(AppError::BadRequest("Plugin version must not be empty".into()));
48        }
49
50        Ok(PluginInfo {
51            id: PluginId::new(manifest.id),
52            name: manifest.name,
53            version: manifest.version,
54            description: manifest.description,
55            path: path.to_path_buf(),
56            status: PluginStatus::Installed,
57        })
58    }
59
60    async fn unload(&self, _id: &PluginId) -> AppResult<()> {
61        Ok(())
62    }
63}