diff options
Diffstat (limited to 'src/utils')
-rw-r--r-- | src/utils/mod.rs | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/src/utils/mod.rs b/src/utils/mod.rs new file mode 100644 index 0000000..1d697fe --- /dev/null +++ b/src/utils/mod.rs @@ -0,0 +1,71 @@ +use diesel::pg::PgConnection; +use r2d2; +use r2d2_diesel::ConnectionManager; +use dotenv::dotenv; +use std::env; + +// An alias to the type for a pool of Diesel PostgreSql connections. +type Pool = r2d2::Pool<ConnectionManager<PgConnection>>; + +/// Initializes a database pool. +pub fn init_db_pool() -> Pool { + dotenv().ok(); + + let config = r2d2::Config::default(); + let dburl = env::var("DATABASE_URL") + .expect("DATABASE_URL environment variable must be set"); + + let manager = ConnectionManager::<PgConnection>::new(dburl); + r2d2::Pool::new(config, manager).expect("db pool") +} + +use std::ops::Deref; +use rocket::http::Status; +use rocket::request::{self, FromRequest}; +use rocket::{Request, State, Outcome}; + +// Connection request guard type: a wrapper around an r2d2 pooled connection. +pub struct DbConn(pub r2d2::PooledConnection<ConnectionManager<PgConnection>>); + +/// Attempts to retrieve a single connection from the managed database pool. If +/// no pool is currently managed, fails with an `InternalServerError` status. If +/// no connections are available, fails with a `ServiceUnavailable` status. +impl<'a, 'r> FromRequest<'a, 'r> for DbConn { + type Error = (); + + fn from_request(request: &'a Request<'r>) -> request::Outcome<DbConn, ()> { + let pool = request.guard::<State<Pool>>()?; + match pool.get() { + Ok(conn) => Outcome::Success(DbConn(conn)), + Err(_) => Outcome::Failure((Status::ServiceUnavailable, ())) + } + } +} + +// For the convenience of using an &DbConn as an &SqliteConnection. +impl Deref for DbConn { + type Target = PgConnection; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +macro_rules! implement_responder_for { + // Implement a responder for the given template type + // + // Seems I can't add the lifetime after the matcher, + // like this: `$template_type<'a>` + // So it will have to be passed in to the argument at + // the macro incovation instead. + ($template_type:ty) => ( + impl<'a> ::rocket::response::Responder<'a> for $template_type { + fn respond_to(self, _: &::rocket::Request) -> Result<::rocket::Response<'static>, ::rocket::http::Status> { + ::rocket::Response::build() + .header(::rocket::http::ContentType::HTML) + .sized_body(::std::io::Cursor::new(format!("{}", &self))) + .ok() + } + } + ) +} |