use async_trait::async_trait;
use serde::Serialize;
use std::collections::HashMap;
use std::sync::Arc;
pub struct ConnectorPlugin {
pub feature_flag: Option<&'static str>,
pub factory: fn() -> Box<dyn Connector>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum ConnectorType {
OAuth,
ApiKey,
}
#[async_trait]
pub trait Connector: Send + Sync {
fn provider_id(&self) -> &str;
fn display_name(&self) -> &str;
fn description(&self) -> &str;
fn icon(&self) -> &str;
fn connection_type(&self) -> ConnectorType;
fn form_schema(&self) -> Option<ConnectorFormSchema>;
fn capabilities(&self) -> &'static [&'static str] {
&[]
}
async fn validate(&self, credential: &str) -> Result<ConnectorValidation, String>;
async fn validate_fields(
&self,
fields: &HashMap<String, String>,
) -> Result<ConnectorValidation, String> {
let api_key = fields.get("api_key").map(|s| s.as_str()).unwrap_or("");
self.validate(api_key).await
}
}
#[derive(Clone, Default)]
pub struct ConnectorRegistry {
providers: HashMap<String, Arc<dyn Connector>>,
}
impl ConnectorRegistry {
pub fn new() -> Self {
Self {
providers: HashMap::new(),
}
}
pub fn register(&mut self, provider: impl Connector + 'static) {
self.providers
.insert(provider.provider_id().to_string(), Arc::new(provider));
}
pub fn register_boxed(&mut self, provider: Box<dyn Connector>) {
self.providers
.insert(provider.provider_id().to_string(), Arc::from(provider));
}
pub fn register_arc(&mut self, provider: Arc<dyn Connector>) {
self.providers
.insert(provider.provider_id().to_string(), provider);
}
pub fn unregister(&mut self, provider_id: &str) -> Option<Arc<dyn Connector>> {
self.providers.remove(provider_id)
}
pub fn get(&self, provider_id: &str) -> Option<&Arc<dyn Connector>> {
self.providers.get(provider_id)
}
pub fn has(&self, provider_id: &str) -> bool {
self.providers.contains_key(provider_id)
}
pub fn list(&self) -> Vec<&Arc<dyn Connector>> {
self.providers.values().collect()
}
pub fn len(&self) -> usize {
self.providers.len()
}
pub fn is_empty(&self) -> bool {
self.providers.is_empty()
}
pub fn builder() -> ConnectorRegistryBuilder {
ConnectorRegistryBuilder::new()
}
}
impl std::fmt::Debug for ConnectorRegistry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let ids: Vec<_> = self.providers.keys().collect();
f.debug_struct("ConnectorRegistry")
.field("providers", &ids)
.finish()
}
}
pub struct ConnectorRegistryBuilder {
registry: ConnectorRegistry,
}
impl ConnectorRegistryBuilder {
pub fn new() -> Self {
Self {
registry: ConnectorRegistry::new(),
}
}
pub fn provider(mut self, provider: impl Connector + 'static) -> Self {
self.registry.register(provider);
self
}
pub fn build(self) -> ConnectorRegistry {
self.registry
}
}
impl Default for ConnectorRegistryBuilder {
fn default() -> Self {
Self::new()
}
}
pub use crate::credential_schema::{FieldType, FormField};
pub type ConnectorFormSchema = crate::credential_schema::CredentialFormSchema;
#[derive(Debug, Clone)]
pub struct ConnectorValidation {
pub provider_username: Option<String>,
pub provider_metadata: Option<serde_json::Value>,
}