Skip to main content

balls/plugin/
mod.rs

1mod limits;
2mod runner;
3mod types;
4
5pub use runner::Plugin;
6pub use types::{PushResponse, SyncCreate, SyncDelete, SyncReport, SyncUpdate};
7
8use crate::config::Config;
9use crate::error::Result;
10use crate::store::{task_lock, Store};
11use crate::task::Task;
12use serde_json::Value;
13use std::collections::BTreeMap;
14
15/// Run plugin push for all active plugins. Returns a map of
16/// plugin_name -> PushResponse for plugins that returned data.
17pub fn run_plugin_push(store: &Store, task: &Task) -> Result<BTreeMap<String, PushResponse>> {
18    let cfg = store.load_config()?;
19    let mut results = BTreeMap::new();
20    for (name, entry) in active_plugins(&cfg) {
21        if entry.sync_on_change {
22            let plugin = Plugin::resolve(store, name, entry);
23            if !plugin.auth_check() {
24                continue;
25            }
26            if let Ok(Some(result)) = plugin.push(task) {
27                results.insert(name.clone(), result);
28            }
29        }
30    }
31    Ok(results)
32}
33
34/// Run plugin sync for all active plugins. Returns (plugin_name, SyncReport) pairs.
35pub fn run_plugin_sync(
36    store: &Store,
37    filter: Option<&str>,
38) -> Result<Vec<(String, SyncReport)>> {
39    let cfg = store.load_config()?;
40    let tasks = store.all_tasks()?;
41    let mut reports = Vec::new();
42    for (name, entry) in active_plugins(&cfg) {
43        let plugin = Plugin::resolve(store, name, entry);
44        if !plugin.auth_check() {
45            continue;
46        }
47        if let Ok(Some(report)) = plugin.sync(&tasks, filter) {
48            reports.push((name.clone(), report));
49        }
50    }
51    Ok(reports)
52}
53
54/// Merge push results into task.external and save+commit.
55pub fn apply_push_response(
56    store: &Store,
57    task_id: &str,
58    results: &BTreeMap<String, PushResponse>,
59) -> Result<()> {
60    if results.is_empty() {
61        return Ok(());
62    }
63    let _g = task_lock(store, task_id)?;
64    let mut task = store.load_task(task_id)?;
65    for (plugin_name, response) in results {
66        let ext_value = Value::Object(response.0.clone());
67        task.external.insert(plugin_name.clone(), ext_value);
68    }
69    task.touch();
70    store.save_task(&task)?;
71    store.commit_task(task_id, &format!("balls: update external for {task_id}"))?;
72    Ok(())
73}
74
75fn active_plugins(cfg: &Config) -> impl Iterator<Item = (&String, &crate::config::PluginEntry)> {
76    cfg.plugins.iter().filter(|(_, e)| e.enabled)
77}