harmos_runtime/operations/manager/
construction.rs1use super::*;
22
23impl OperationManager {
38 pub(crate) fn new(
39 instances: Arc<Instances>, settings: &crate::operations::Settings, reserved: std::collections::BTreeSet<String>, identity: Arc<()>,
40 ) -> Self {
41 Self {
42 resident: crate::operations::resident::Registry::new(&instances, reserved, identity),
43 context: Arc::new(std::sync::OnceLock::from(crate::operations::CallContext::default())),
44 instances,
45 preparation: settings.preparation_bytes.map(|bytes| Arc::new(Semaphore::new(bytes.get()))),
46 lanes: Arc::new(Lanes::default()),
47 registry: Arc::new(Registry {
48 middleware: crate::operations::middleware::Configuration::default(),
49 state: Mutex::new(State {
50 closing: false,
51 entries: BTreeMap::new(),
52 #[cfg(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar"))]
53 staging: Vec::new(),
54 #[cfg(feature = "grpc")]
55 grpc: BTreeMap::new(),
56 #[cfg(feature = "grpc")]
57 grpc_services: std::collections::BTreeSet::new(),
58 cache: VecDeque::new(),
59 cache_capacity: DEFAULT_CACHE_CAPACITY,
60 }),
61 }),
62 }
63 }
64
65 pub fn register_middleware(&self, middleware: Arc<dyn crate::operations::middleware::Middleware>) -> Result<()> {
66 self.registry.middleware.register(middleware)
67 }
68
69 pub fn register_authorizer(&self, authorizer: Arc<dyn crate::operations::authorization::Authorizer>) -> Result<()> {
70 self.registry.middleware.register_authorizer(authorizer)
71 }
72
73 #[cfg(feature = "grpc")]
74 pub(crate) fn submit_external_charged<O: OperationDeclaration, P: Send + 'static>(
75 &self, request: crate::operations::StreamItem<O>, endpoints: P,
76 ) -> Result<OperationInstance<O>> {
77 self.admit::<O, P>((crate::operations::binding::Request::charged(request)?, endpoints), None, &[], &Source::Host.external()?, None)
78 }
79
80 pub(in crate::operations) fn authorize_external(
81 &self, entry: &Entry, origin: &Origin,
82 ) -> Result<Option<crate::operations::authorization::Authorization>> {
83 #[cfg(feature = "grpc")]
84 if matches!(origin.identity, crate::operations::caller::Identity::External(_)) {
85 let Some(authorizer) = self.registry.middleware.authorizer() else {
86 return Ok(None);
88 };
89 let denied = || Error::OperationUnauthorized {
90 caller: "external".to_owned(),
91 owner: entry.owner.to_string(),
92 operation: entry.id().to_owned(),
93 };
94 let contract = entry.contract.as_ref().ok_or_else(denied)?;
95 #[cfg(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar"))]
96 let plugin = entry.plugin.is_some();
97 #[cfg(not(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar")))]
98 let plugin = false;
99 let selected = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
100 authorizer.authorize(
101 self.call_context(),
102 crate::operations::authorization::Provider {
103 owner: &entry.owner,
104 plugin,
105 generation: entry.generation,
106 definition: &entry.definition,
107 contract,
108 },
109 )
110 }))
111 .map_err(|_| Error::InvalidInput { field: "operation authorizer", reason: "authorization callback panicked" })??
112 .ok_or_else(denied)?;
113 let selected_contract = match &selected {
114 crate::operations::authorization::Authorization::Full(contract) => contract,
115 crate::operations::authorization::Authorization::Restricted(required) => &required.contract,
116 };
117 if !contract.compatible(selected_contract) {
118 return Err(denied());
119 }
120 return Ok(Some(selected));
121 }
122 #[cfg(not(feature = "grpc"))]
123 let _ = (entry, origin);
124 Ok(None)
125 }
126
127 pub fn with_context(&self, context: crate::operations::CallContext) -> Self {
128 let mut handle = self.clone();
129 handle.context = Arc::new(std::sync::OnceLock::from(context));
130 handle
131 }
132
133 pub(in crate::operations) fn call_context(&self) -> &crate::operations::CallContext {
134 self.context.get().expect("context freezes before operation execution")
135 }
136
137 pub fn status(&self, id: OperationInstanceId) -> Option<crate::operations::OperationStatus> {
138 self.instances.status(id)
139 }
140
141 pub(in crate::operations) fn claim_preparation(&self, bytes: std::num::NonZeroUsize) -> Result<OwnedSemaphorePermit> {
142 let count = u32::try_from(bytes.get()).map_err(|_| Error::ResourceExhausted { resource: "operation preparation bytes" })?;
143 self.preparation
144 .as_ref()
145 .ok_or(Error::InvalidInput {
146 field: "operation preparation bytes",
147 reason: "encoded preparation requires an explicit preparation budget",
148 })?
149 .clone()
150 .try_acquire_many_owned(count)
151 .map_err(|_| Error::ResourceExhausted { resource: "operation preparation bytes" })
152 }
153}
154
155