Repository: libsql/libsql
File: libsql-server/src/namespace/mod.rs (Rust)

Code before:
    pub async fn shutdown(self) -> crate::Result<()> {
        self.inner.has_shutdown.store(true, Ordering::Relaxed);
        for (_name, entry) in self.inner.store.iter() {
            let mut lock = entry.write().await;
            if let Some(ns) = lock.take() {
                ns.shutdown(self.inner.snapshot_at_shutdown).await?;
            }
        }
        self.inner.metadata.shutdown().await?;
        self.inner.store.invalidate_all();
        self.inner.store.run_pending_tasks().await;
        Ok(())
    }

    pub(crate) async fn stats(&self, namespace: NamespaceName) -> crate::Result<Arc<Stats>> {
        self.with(namespace, |ns| ns.stats.clone()).await
    }

    pub(crate) async fn config_store(
        &self,
        namespace: NamespaceName,
    ) -> crate::Result<MetaStoreHandle> {
        self.with(namespace, |ns| ns.db_config_store.clone()).await
    }

    pub async fn jwt_key(
        &self,
        namespace: NamespaceName,
    ) -> crate::Result<Option<jsonwebtoken::DecodingKey>> {
        let config_store = self.config_store(namespace).await?;
        let config = config_store.get();
        if let Some(jwt_key) = config.jwt_key.as_deref() {
            Ok(Some(
                parse_jwt_key(jwt_key).context("Could not parse JWT decoding key")?,
            ))
        } else {
            Ok(None)
        }
    }
}

/// A namespace isolates the resources pertaining to a database of type T
#[derive(Debug)]
pub struct Namespace<T> {
    pub db: T,
    name: NamespaceName,
    /// The set of tasks associated with this namespace
    tasks: JoinSet<anyhow::Result<()>>,
    stats: Arc<Stats>,
    db_config_store: MetaStoreHandle,
}

Review comment (suggestion):
So I actually don't really like this approach, to me I envisioned that this would exist on the `Namespace` struct itself and you would get access to it via `with`. So once you have parsed the namespace out of the http header, you check the store for it, it then gives you a `Namespace<T>`  and on that namespace you can then access the config. There is no need to have a separate function that threads through namespaces since its all type checked via the store/namespace struct. This imo provides a really nice encapsulation where you can only access the config from the `Namespace` struct that is tied to that namespace.

We can keep this for now but its quite leaky imo and we should fix this in the future and track that.

Code after:

    pub async fn shutdown(self) -> crate::Result<()> {
        self.inner.has_shutdown.store(true, Ordering::Relaxed);
        for (_name, entry) in self.inner.store.iter() {
            let mut lock = entry.write().await;
            if let Some(ns) = lock.take() {
                ns.shutdown(self.inner.snapshot_at_shutdown).await?;
            }
        }
        self.inner.metadata.shutdown().await?;
        self.inner.store.invalidate_all();
        self.inner.store.run_pending_tasks().await;
        Ok(())
    }

    pub(crate) async fn stats(&self, namespace: NamespaceName) -> crate::Result<Arc<Stats>> {
        self.with(namespace, |ns| ns.stats.clone()).await
    }

    pub(crate) async fn config_store(
        &self,
        namespace: NamespaceName,
    ) -> crate::Result<MetaStoreHandle> {
        self.with(namespace, |ns| ns.db_config_store.clone()).await
    }
}

/// A namespace isolates the resources pertaining to a database of type T
#[derive(Debug)]
pub struct Namespace<T> {
    pub db: T,
    name: NamespaceName,
    /// The set of tasks associated with this namespace
    tasks: JoinSet<anyhow::Result<()>>,
    stats: Arc<Stats>,
    db_config_store: MetaStoreHandle,
}

impl<T: Database> Namespace<T> {
    pub(crate) fn name(&self) -> &NamespaceName {
        &self.name
    }

    async fn destroy(mut self) -> anyhow::Result<()> {
        self.tasks.shutdown().await;
        self.db.destroy();
        Ok(())
    }

    async fn checkpoint(&self) -> anyhow::Result<()> {
        let conn = self.db.connection_maker().create().await?;