Skip to main content

lenso_app_authoring/
selection_authority.rs

1use std::{fmt, path::Path};
2
3use lenso_app_plan::authoring::ResolvedApp;
4
5use super::{
6    LocalPluginRootAuthority, PluginConfigurationAuthoritySource, PluginRootRevision,
7    set_instance_disabled_inner,
8};
9
10/// Host-side port for enabling or disabling one Plugin Instance.
11///
12/// Implementations own the visible selection state and compare-and-swap mutation. They do not
13/// own App Generation staging, routing, or Kernel execution.
14pub trait PluginSelectionAuthority: fmt::Debug + Send + Sync {
15    fn source(&self) -> PluginConfigurationAuthoritySource;
16
17    fn set_enabled(
18        &self,
19        expected_revision: &PluginRootRevision,
20        plugin_id: &str,
21        instance: &str,
22        enabled: bool,
23    ) -> anyhow::Result<PluginSelectionPublication>;
24}
25
26/// One committed Plugin Instance selection change.
27#[derive(Debug)]
28pub struct PluginSelectionPublication {
29    base_revision: PluginRootRevision,
30    enabled: bool,
31    instance: String,
32    plugin_id: String,
33    revision: PluginRootRevision,
34    resolved: ResolvedApp,
35}
36
37impl PluginSelectionPublication {
38    pub const fn base_revision(&self) -> &PluginRootRevision {
39        &self.base_revision
40    }
41
42    pub const fn enabled(&self) -> bool {
43        self.enabled
44    }
45
46    pub fn instance(&self) -> &str {
47        &self.instance
48    }
49
50    pub fn plugin_id(&self) -> &str {
51        &self.plugin_id
52    }
53
54    pub const fn revision(&self) -> &PluginRootRevision {
55        &self.revision
56    }
57
58    pub const fn resolved(&self) -> &ResolvedApp {
59        &self.resolved
60    }
61
62    pub fn into_resolved(self) -> ResolvedApp {
63        self.resolved
64    }
65}
66
67/// Atomically changes one Instance selection after checking the exact current revision.
68pub fn set_instance_enabled_fenced(
69    root: &Path,
70    expected_revision: &PluginRootRevision,
71    plugin_id: &str,
72    instance: &str,
73    enabled: bool,
74) -> anyhow::Result<PluginSelectionPublication> {
75    let (base_revision, revision, resolved) =
76        set_instance_disabled_inner(root, plugin_id, instance, !enabled, Some(expected_revision))?;
77    Ok(PluginSelectionPublication {
78        base_revision,
79        enabled,
80        instance: instance.to_owned(),
81        plugin_id: plugin_id.to_owned(),
82        revision,
83        resolved,
84    })
85}
86
87impl PluginSelectionAuthority for LocalPluginRootAuthority {
88    fn source(&self) -> PluginConfigurationAuthoritySource {
89        PluginConfigurationAuthoritySource::new("local_plugin_root", "app")
90            .expect("built-in Plugin selection authority source is valid")
91    }
92
93    fn set_enabled(
94        &self,
95        expected_revision: &PluginRootRevision,
96        plugin_id: &str,
97        instance: &str,
98        enabled: bool,
99    ) -> anyhow::Result<PluginSelectionPublication> {
100        let _guard = self.lock()?;
101        set_instance_enabled_fenced(self.root(), expected_revision, plugin_id, instance, enabled)
102    }
103}