blob: e9733f46d380ba82f57b8f36bb2b60e8697925da [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
use futures_util::future::BoxFuture;
use maka_capabilities::call::Resources;
use maka_capabilities::credentials;
use maka_capabilities::credentials::Record;
use maka_capabilities::credentials::Write;
use maka_capabilities::credentials::WriteResult;
use maka_capabilities::storage::Namespace;
use maka_capabilities::storage::StoreError;
use maka_capabilities::storage::validate_key;
use maka_config::ConfigurationStore;
use std::sync::Arc;
use tokio_util::sync::CancellationToken;
#[derive(Clone)]
pub struct Credentials {
pub configuration: Arc<ConfigurationStore>,
pub namespace: Namespace,
pub prefix: String,
pub resources: Arc<Resources>,
pub stopping: CancellationToken,
}
fn error(error: maka_config::ConfigError) -> StoreError {
match error {
maka_config::ConfigError::CommitUnknown => StoreError::OutcomeUnknown(error.to_string()),
error => StoreError::Unavailable(error.to_string()),
}
}
impl credentials::Credentials for Credentials {
fn read(&self, key: String) -> BoxFuture<'_, Result<Option<Record>, StoreError>> {
Box::pin(async move {
if self.stopping.is_cancelled() {
return Err(StoreError::Retired);
}
validate_key(&key).map_err(|e| StoreError::Unavailable(e.to_string()))?;
self.configuration
.plugin_credential(self.namespace.clone(), format!("{}{key}", self.prefix))
.await
.map_err(error)
})
}
fn write(&self, mut input: Write) -> BoxFuture<'_, Result<WriteResult, StoreError>> {
Box::pin(async move {
if self.stopping.is_cancelled() {
return Err(StoreError::Retired);
}
input
.validate()
.map_err(|e| StoreError::Unavailable(e.to_string()))?;
input.key = format!("{}{}", self.prefix, input.key);
let mut ticket = self.resources.reserve().map_err(|_| StoreError::Retired)?;
let owner = self.clone();
tokio::spawn(async move {
ticket.start();
let result = owner
.configuration
.write_plugin_credential(owner.namespace, input)
.await
.map_err(error);
if matches!(result, Err(StoreError::OutcomeUnknown(_))) {
owner.stopping.cancel();
}
ticket.complete(Ok(()));
result
})
.await
.map_err(|_| StoreError::OutcomeUnknown("Credential worker disappeared".into()))?
})
}
}