bb8_arangodb/
lib.rs

1//! ArangoDB support for [bb8] based on the [arangors] crate.
2//!
3//! The library supports all authentication methods supported by `arangors`,
4//! defined by `AuthenticationMethod`.
5//!
6//! [bb8]: https://crates.io/crates/bb8
7//! [arangors]: https://crates.io/crates/arangors
8//!
9//! # Example
10//!
11//! Get all accessible databases using JWT authentication:
12//!
13//! ```
14//! use bb8::Pool;
15//! use bb8_arangodb::{ArangoConnectionManager, AuthenticationMethod};
16//! use arangors::uclient::reqwest::ReqwestClient;
17//!
18//! tokio_test::block_on(async {
19//!     let manager = ArangoConnectionManager::<ReqwestClient>::new(
20//!         "http://localhost:8529".to_string(),
21//!         AuthenticationMethod::JWTAuth("root".to_string(), "openSesame".to_string())
22//!     );
23//!
24//!     let pool = Pool::builder().max_size(5).build(manager).await.unwrap();
25//!
26//!     let conn = pool.get().await.unwrap();
27//!     let dbs = conn.accessible_databases().await.unwrap();
28//!
29//!     assert!(!dbs.is_empty());
30//! });
31//! ```
32//!
33//! Use basic authentication method:
34//!
35//! ```
36//! use bb8::Pool;
37//! use bb8_arangodb::{ArangoConnectionManager, AuthenticationMethod};
38//! use arangors::uclient::reqwest::ReqwestClient;
39//!
40//! tokio_test::block_on(async {
41//!     let manager = ArangoConnectionManager::<ReqwestClient>::new(
42//!         "http://localhost:8529".to_string(),
43//!         AuthenticationMethod::BasicAuth("root".to_string(), "openSesame".to_string())
44//!     );
45//!
46//!     let pool = Pool::builder().max_size(5).build(manager).await.unwrap();
47//!
48//!     let conn = pool.get().await.unwrap();
49//!     let dbs = conn.accessible_databases().await.unwrap();
50//!
51//!     assert!(!dbs.is_empty());
52//! });
53//! ```
54//!
55//! Using no authentication method (not recommended):
56//!
57//! ```no_run
58//! use bb8::Pool;
59//! use bb8_arangodb::{ArangoConnectionManager, AuthenticationMethod};
60//! use arangors::uclient::reqwest::ReqwestClient;
61//!
62//! tokio_test::block_on(async {
63//!     let manager = ArangoConnectionManager::<ReqwestClient>::new(
64//!         "http://localhost:8529".to_string(),
65//!         AuthenticationMethod::NoAuth
66//!     );
67//!
68//!     let pool = Pool::builder().max_size(5).build(manager).await.unwrap();
69//!
70//!     // ...
71//! });
72//! ```
73
74#![deny(missing_docs, missing_debug_implementations)]
75
76use std::marker::PhantomData;
77
78pub use arangors;
79pub use bb8;
80
81use arangors::{uclient, ClientError, GenericConnection};
82use async_trait::async_trait;
83
84/// Kind of the authentication method to use when establishing a connection.
85#[derive(Debug)]
86pub enum AuthenticationMethod {
87    /// Use basic authentication with a username and password for API calls.
88    BasicAuth(String, String),
89    /// Use JWT authentication with a token for API calls after authenticating
90    /// with username and password.
91    JWTAuth(String, String),
92    /// Use no authentication for API calls. This is only recommended for local
93    /// development.
94    NoAuth,
95}
96
97/// A connection manager for ArangoDB.
98#[derive(Debug)]
99pub struct ArangoConnectionManager<C: uclient::ClientExt> {
100    url: String,
101    method: AuthenticationMethod,
102    phantom: PhantomData<C>,
103}
104
105impl<C: uclient::ClientExt> ArangoConnectionManager<C> {
106    /// Create a new ArangoConnectionManager..
107    pub fn new(url: String, method: AuthenticationMethod) -> Self {
108        Self {
109            url,
110            method,
111            phantom: PhantomData,
112        }
113    }
114}
115
116#[async_trait]
117impl<C: uclient::ClientExt + Send + 'static> bb8::ManageConnection for ArangoConnectionManager<C> {
118    type Connection = GenericConnection<C>;
119    type Error = ClientError;
120
121    async fn connect(&self) -> Result<Self::Connection, Self::Error> {
122        match &self.method {
123            AuthenticationMethod::BasicAuth(username, password) => {
124                Self::Connection::establish_basic_auth(&self.url, username, password).await
125            }
126            AuthenticationMethod::JWTAuth(username, password) => {
127                Self::Connection::establish_jwt(&self.url, username, password).await
128            }
129            AuthenticationMethod::NoAuth => {
130                Self::Connection::establish_without_auth(&self.url).await
131            }
132        }
133    }
134
135    async fn is_valid(&self, conn: &mut Self::Connection) -> Result<(), Self::Error> {
136        match conn.accessible_databases().await {
137            Ok(_) => Ok(()),
138            Err(e) => Err(e),
139        }
140    }
141
142    fn has_broken(&self, _conn: &mut Self::Connection) -> bool {
143        false
144    }
145}