use std::path::PathBuf;
use actix_web::{web, HttpResponse, Responder};
use bamboo_plugin::{InstallDisposition, PluginInstaller, PluginSource};
use crate::app_state::AppState;
use crate::plugin_installer::ServerPluginInstaller;
use crate::plugin_source::{
install_server_plugin_from_source_with_event_sink_grants, PluginSourceInput,
};
use super::api_types::{to_view, InstallPluginRequest, PluginListResponse};
use super::errors::plugin_error_response;
fn plugins_root(state: &AppState) -> PathBuf {
state.app_data_dir.join("plugins")
}
fn to_source_input(source: PluginSource) -> PluginSourceInput {
match source {
PluginSource::LocalDir { path } => PluginSourceInput::LocalDir(path),
PluginSource::LocalArchive { path } => PluginSourceInput::LocalArchive(path),
PluginSource::Url {
url,
sha256,
allow_unverified,
allow_untrusted_host,
allow_unsigned,
signed_by: _,
insecure,
} => PluginSourceInput::Url {
url,
sha256,
allow_unverified,
allow_untrusted_host,
allow_unsigned,
insecure,
},
}
}
pub async fn list_plugins(state: web::Data<AppState>) -> impl Responder {
let installer = ServerPluginInstaller::new(state.clone());
match installer.list().await {
Ok(entries) => {
let mut plugins = Vec::with_capacity(entries.len());
for entry in entries {
plugins
.push(to_view(entry, &state.service_manager, &state.tool_event_router).await);
}
HttpResponse::Ok().json(PluginListResponse { plugins })
}
Err(error) => plugin_error_response(&error),
}
}
pub async fn install_plugin(
state: web::Data<AppState>,
body: web::Json<InstallPluginRequest>,
) -> impl Responder {
let installer = ServerPluginInstaller::new(state.clone());
let root = plugins_root(&state);
let request = body.into_inner();
let grants = request.event_sink_grants;
let input = to_source_input(request.source);
let trust = state.config.read().await.plugin_trust.clone();
match install_server_plugin_from_source_with_event_sink_grants(
&installer,
input,
&root,
&trust,
InstallDisposition::FailIfInstalled,
None,
grants.as_deref(),
)
.await
{
Ok(entry) => HttpResponse::Created()
.json(to_view(entry, &state.service_manager, &state.tool_event_router).await),
Err(error) => plugin_error_response(&error),
}
}
pub async fn update_plugin(
state: web::Data<AppState>,
path: web::Path<String>,
body: web::Json<InstallPluginRequest>,
) -> impl Responder {
let path_id = path.into_inner();
let installer = ServerPluginInstaller::new(state.clone());
let root = plugins_root(&state);
let request = body.into_inner();
let grants = request.event_sink_grants;
let input = to_source_input(request.source);
let trust = state.config.read().await.plugin_trust.clone();
match install_server_plugin_from_source_with_event_sink_grants(
&installer,
input,
&root,
&trust,
InstallDisposition::Upgrade,
Some(&path_id),
grants.as_deref(),
)
.await
{
Ok(entry) => HttpResponse::Ok()
.json(to_view(entry, &state.service_manager, &state.tool_event_router).await),
Err(error) => plugin_error_response(&error),
}
}
pub async fn remove_plugin(state: web::Data<AppState>, path: web::Path<String>) -> impl Responder {
let id = path.into_inner();
let installer = ServerPluginInstaller::new(state.clone());
match installer.uninstall(&id).await {
Ok(()) => HttpResponse::Ok().json(serde_json::json!({ "id": id, "removed": true })),
Err(error) => plugin_error_response(&error),
}
}