matrix-bridge-teams 0.1.0

A bridge between Matrix and Microsoft Teams written in Rust
use anyhow::Result;
use async_trait::async_trait;

use crate::config::DatabaseConfig;
use crate::db::{DatabaseError, MessageMapping, RoomMapping, UserMapping};
#[cfg(feature = "mysql")]
use super::mysql::MysqlBackend;
#[cfg(feature = "postgres")]
use super::postgres::PostgresBackend;
#[cfg(feature = "sqlite")]
use super::sqlite::SqliteBackend;

pub struct DatabaseManager {
    inner: DatabaseBackend,
}

enum DatabaseBackend {
    #[cfg(feature = "postgres")]
    Postgres(PostgresBackend),
    #[cfg(feature = "sqlite")]
    Sqlite(SqliteBackend),
    #[cfg(feature = "mysql")]
    Mysql(MysqlBackend),
}

impl DatabaseManager {
    pub async fn new(config: &DatabaseConfig) -> Result<Self> {
        let url = config.url.as_ref().or(config.filename.as_ref())
            .ok_or_else(|| anyhow::anyhow!("database url or filename required"))?;

        let inner = if url.starts_with("postgres://") || url.starts_with("postgresql://") {
            #[cfg(feature = "postgres")]
            {
                DatabaseBackend::Postgres(PostgresBackend::new(url).await?)
            }
            #[cfg(not(feature = "postgres"))]
            {
                anyhow::bail!("postgres feature not enabled");
            }
        } else if url.starts_with("sqlite://") {
            #[cfg(feature = "sqlite")]
            {
                DatabaseBackend::Sqlite(SqliteBackend::new(url).await?)
            }
            #[cfg(not(feature = "sqlite"))]
            {
                anyhow::bail!("sqlite feature not enabled");
            }
        } else if url.starts_with("mysql://") || url.starts_with("mariadb://") {
            #[cfg(feature = "mysql")]
            {
                DatabaseBackend::Mysql(MysqlBackend::new(url).await?)
            }
            #[cfg(not(feature = "mysql"))]
            {
                anyhow::bail!("mysql feature not enabled");
            }
        } else {
            #[cfg(feature = "postgres")]
            {
                DatabaseBackend::Postgres(PostgresBackend::new(url).await?)
            }
            #[cfg(not(feature = "postgres"))]
            {
                anyhow::bail!("default postgres feature not enabled");
            }
        };

        Ok(Self { inner })
    }

    pub async fn migrate(&self) -> Result<()> {
        match &self.inner {
            #[cfg(feature = "postgres")]
            DatabaseBackend::Postgres(db) => db.migrate().await,
            #[cfg(feature = "sqlite")]
            DatabaseBackend::Sqlite(db) => db.migrate().await,
            #[cfg(feature = "mysql")]
            DatabaseBackend::Mysql(db) => db.migrate().await,
        }
    }
}

#[async_trait]
pub trait DatabaseBackendTrait: Send + Sync {
    async fn migrate(&self) -> Result<()>;
    async fn get_room_mapping(&self, channel_id: &str) -> Result<Option<RoomMapping>>;
    async fn create_room_mapping(&self, mapping: &RoomMapping) -> Result<()>;
    async fn get_user_mapping(&self, teams_user_id: &str) -> Result<Option<UserMapping>>;
    async fn create_user_mapping(&self, mapping: &UserMapping) -> Result<()>;
    async fn get_message_mapping(&self, teams_message_id: &str) -> Result<Option<MessageMapping>>;
    async fn create_message_mapping(&self, mapping: &MessageMapping) -> Result<()>;
}