Use tokio-diesel

This commit is contained in:
Konrad Borowski 2019-08-08 10:28:36 +02:00
parent 2f5b513e6e
commit 5e57221a51
11 changed files with 241 additions and 90 deletions

97
Cargo.lock generated
View File

@ -265,6 +265,20 @@ name = "futures"
version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures-channel-preview"
version = "0.3.0-alpha.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures-core-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "futures-core-preview"
version = "0.3.0-alpha.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures-cpupool"
version = "0.1.8"
@ -274,6 +288,58 @@ dependencies = [
"num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "futures-executor-preview"
version = "0.3.0-alpha.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures-channel-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "futures-io-preview"
version = "0.3.0-alpha.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures-preview"
version = "0.3.0-alpha.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures-channel-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-executor-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-io-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "futures-sink-preview"
version = "0.3.0-alpha.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures-core-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "futures-util-preview"
version = "0.3.0-alpha.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-channel-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-io-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "generic-array"
version = "0.12.3"
@ -840,6 +906,8 @@ dependencies = [
"diesel 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"diesel_migrations 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
@ -847,6 +915,7 @@ dependencies = [
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"ructe 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-diesel 0.1.1 (git+https://github.com/xfix/tokio-diesel.git?branch=stable-compatibility)",
"warp 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -895,6 +964,11 @@ dependencies = [
"unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pin-utils"
version = "0.1.0-alpha.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ppv-lite86"
version = "0.2.5"
@ -1410,6 +1484,20 @@ dependencies = [
"tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-diesel"
version = "0.1.1"
source = "git+https://github.com/xfix/tokio-diesel.git?branch=stable-compatibility#d6e8603fec356f4cf2075d798ef890da1234d5cb"
dependencies = [
"diesel 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"r2d2 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-executor"
version = "0.1.8"
@ -1768,7 +1856,14 @@ dependencies = [
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b"
"checksum futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869"
"checksum futures-channel-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "21c71ed547606de08e9ae744bb3c6d80f5627527ef31ecf2a7210d0e67bc8fae"
"checksum futures-core-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4b141ccf9b7601ef987f36f1c0d9522f76df3bba1cf2e63bfacccc044c4558f5"
"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
"checksum futures-executor-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "87ba260fe51080ba37f063ad5b0732c4ff1f737ea18dcb67833d282cdc2c6f14"
"checksum futures-io-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "082e402605fcb8b1ae1e5ba7d7fdfd3e31ef510e2a8367dd92927bb41ae41b3a"
"checksum futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "bf25f91c8a9a1f64c451e91b43ba269ed359b9f52d35ed4b3ce3f9c842435867"
"checksum futures-sink-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4309a25a1069a1f3c10647b227b9afe6722b67a030d3f00a9cbdc171fc038de4"
"checksum futures-util-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "af8198c48b222f02326940ce2b3aa9e6e91a32886eeaad7ca3b8e4c70daa3f4e"
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
"checksum getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "72327b15c228bfe31f1390f93dd5e9279587f0463836393c9df719ce62a3e450"
"checksum getrandom 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8e190892c840661957ba9f32dacfb3eb405e657f9f9f60485605f0bb37d6f8"
@ -1834,6 +1929,7 @@ dependencies = [
"checksum phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e"
"checksum phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662"
"checksum phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0"
"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587"
"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
"checksum pq-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac25eee5a0582f45a67e837e350d784e7003bd29a5f460796772061ca49ffda"
"checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
@ -1894,6 +1990,7 @@ dependencies = [
"checksum tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46"
"checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f"
"checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443"
"checksum tokio-diesel 0.1.1 (git+https://github.com/xfix/tokio-diesel.git?branch=stable-compatibility)" = "<none>"
"checksum tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f27ee0e6db01c5f0b2973824547ce7e637b2ed79b891a9677b0de9bd532b6ac"
"checksum tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe6dc22b08d6993916647d108a1a7d15b9cd29c4f4496c62b92c45b5041b7af"
"checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926"

View File

@ -12,12 +12,15 @@ chrono = "0.4.6"
diesel = { version = "1.4.1", features = ["chrono", "postgres", "r2d2"] }
diesel_migrations = "1.4.0"
env_logger = { version = "0.6.0", default-features = false }
futures = "0.1.28"
futures03 = { version = "=0.3.0-alpha.17", package = "futures-preview", features = ["compat"] }
lazy_static = "1.3.0"
log = "0.4.6"
mime = "0.3.13"
pulldown-cmark = "0.5.0"
rand = "0.6.5"
serde = { version = "1.0.88", features = ["derive"] }
tokio-diesel = { git = "https://github.com/xfix/tokio-diesel.git", branch = "stable-compatibility" }
warp = "0.1.15"
[build-dependencies]

View File

@ -6,12 +6,11 @@ mod routes;
mod schema;
use diesel::prelude::*;
use diesel::r2d2::{ConnectionManager, PooledConnection};
use diesel::Connection as _;
use diesel::r2d2::{ConnectionManager, Pool};
use std::env;
use std::error::Error;
type Connection = PooledConnection<ConnectionManager<PgConnection>>;
type PgPool = Pool<ConnectionManager<PgConnection>>;
fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();

View File

@ -1,6 +1,9 @@
use crate::schema::languages::dsl::*;
use crate::PgConnection;
use crate::PgPool;
use diesel::prelude::*;
use futures::Future;
use futures03::TryFutureExt;
use tokio_diesel::{AsyncError, AsyncRunQueryDsl};
#[derive(Queryable)]
pub struct Language {
@ -9,12 +12,12 @@ pub struct Language {
}
impl Language {
pub fn fetch(db: &PgConnection) -> Vec<Language> {
pub fn fetch(pool: &'static PgPool) -> impl Future<Item = Vec<Language>, Error = AsyncError> {
languages
.select((language_id, name))
.order((priority.asc(), name.asc()))
.load(db)
.unwrap()
.load_async(pool)
.compat()
}
}

View File

@ -1,10 +1,14 @@
use crate::schema::pastes;
use crate::PgPool;
use ammonia::Builder;
use chrono::{DateTime, Utc};
use diesel::prelude::*;
use futures::Future;
use futures03::TryFutureExt;
use lazy_static::lazy_static;
use log::info;
use pulldown_cmark::{Options, Parser};
use tokio_diesel::{AsyncError, AsyncRunQueryDsl};
#[derive(Queryable)]
pub struct Paste {
@ -16,14 +20,16 @@ pub struct Paste {
}
impl Paste {
pub fn delete_old(db: &PgConnection) {
let pastes = diesel::delete(pastes::table)
pub fn delete_old(pool: &'static PgPool) -> impl Future<Item = (), Error = AsyncError> {
diesel::delete(pastes::table)
.filter(pastes::delete_at.lt(Utc::now()))
.execute(db)
.unwrap();
if pastes > 0 {
info!("Deleted {} paste(s)", pastes);
}
.execute_async(pool)
.compat()
.map(|pastes| {
if pastes > 0 {
info!("Deleted {} paste(s)", pastes);
}
})
}
}

View File

@ -1,7 +1,10 @@
use crate::schema::languages::dsl::*;
use crate::Connection;
use crate::PgPool;
use diesel::prelude::*;
use futures::Future;
use futures03::TryFutureExt;
use serde::Serialize;
use tokio_diesel::{AsyncRunQueryDsl, OptionalExtension};
use warp::http::header::CACHE_CONTROL;
use warp::{Rejection, Reply};
@ -12,14 +15,19 @@ struct ApiLanguage {
mime: String,
}
pub fn api_language(id: i32, db: Connection) -> Result<impl Reply, Rejection> {
pub fn api_language(
id: i32,
pool: &'static PgPool,
) -> impl Future<Item = impl Reply, Error = Rejection> {
languages
.find(id)
.select((highlighter_mode, mime))
.get_result(&db)
.optional()
.unwrap()
.ok_or_else(warp::reject::not_found)
.get_result_async(pool)
.compat()
.then(|result| result.optional())
.map(|paste_contents| paste_contents.ok_or_else(warp::reject::not_found))
.map_err(warp::reject::custom)
.flatten()
.map(|json: ApiLanguage| {
warp::reply::with_header(warp::reply::json(&json), CACHE_CONTROL, "max-age=14400")
})

View File

@ -2,43 +2,52 @@ use crate::models::language::{Language, Selection};
use crate::models::paste::{ExternPaste, Paste};
use crate::schema::{languages, pastes};
use crate::templates::RenderRucte;
use crate::{templates, Connection};
use crate::{templates, PgPool};
use diesel::prelude::*;
use futures::future::*;
use futures03::TryFutureExt;
use tokio_diesel::{AsyncRunQueryDsl, OptionalExtension};
use warp::http::Response;
use warp::{Rejection, Reply};
pub fn display_paste(
requested_identifier: String,
db: Connection,
) -> Result<impl Reply, Rejection> {
Paste::delete_old(&db);
let languages = Language::fetch(&db);
let paste = pastes::table
.inner_join(languages::table)
.select((
pastes::paste,
pastes::language_id,
pastes::delete_at,
languages::is_markdown,
pastes::no_follow,
))
.filter(pastes::identifier.eq(requested_identifier))
.get_result(&db)
.optional()
.unwrap();
paste
.ok_or_else(warp::reject::not_found)
.and_then(|paste: Paste| {
let selected_language = Some(paste.language_id);
Response::builder().html(|o| {
templates::display_paste(
o,
ExternPaste::from_paste(paste),
Selection {
languages,
selected_language,
},
)
})
pool: &'static PgPool,
) -> impl Future<Item = impl Reply, Error = Rejection> {
Paste::delete_old(pool)
.and_then(move |()| Language::fetch(pool))
.and_then(move |languages| {
pastes::table
.inner_join(languages::table)
.select((
pastes::paste,
pastes::language_id,
pastes::delete_at,
languages::is_markdown,
pastes::no_follow,
))
.filter(pastes::identifier.eq(requested_identifier))
.get_result_async(pool)
.compat()
.then(|result| result.optional())
.map(|paste| {
paste
.ok_or_else(warp::reject::not_found)
.and_then(|paste: Paste| {
let selected_language = Some(paste.language_id);
Response::builder().html(|o| {
templates::display_paste(
o,
ExternPaste::from_paste(paste),
Selection {
languages,
selected_language,
},
)
})
})
})
})
.map_err(warp::reject::custom)
.flatten()
}

View File

@ -1,18 +1,22 @@
use crate::models::language::{Language, Selection};
use crate::templates::RenderRucte;
use crate::{templates, Connection};
use crate::{templates, PgPool};
use futures::Future;
use warp::http::Response;
use warp::{Rejection, Reply};
pub fn index(connection: Connection) -> Result<impl Reply, Rejection> {
let languages = Language::fetch(&connection);
Response::builder().html(|o| {
templates::index(
o,
Selection {
languages,
selected_language: None,
},
)
})
pub fn index(pool: &'static PgPool) -> impl Future<Item = impl Reply, Error = Rejection> {
Language::fetch(pool)
.map_err(warp::reject::custom)
.and_then(|languages| {
Response::builder().html(|o| {
templates::index(
o,
Selection {
languages,
selected_language: None,
},
)
})
})
}

View File

@ -1,12 +1,14 @@
use crate::schema::pastes;
use crate::Connection;
use crate::PgPool;
use chrono::{DateTime, Duration, Utc};
use diesel::prelude::*;
use futures::Future;
use futures03::TryFutureExt;
use rand::prelude::*;
use serde::de::IgnoredAny;
use serde::Deserialize;
use tokio_diesel::AsyncRunQueryDsl;
use warp::http::Uri;
use warp::Reply;
use warp::{Rejection, Reply};
const CHARACTERS: &[u8] = b"23456789bcdfghjkmnpqrstvwxzBCDFGHJKLMNPQRSTVWX-";
@ -26,7 +28,10 @@ struct NewPaste {
paste: String,
}
pub fn insert_paste(form: PasteForm, db: Connection) -> impl Reply {
pub fn insert_paste(
form: PasteForm,
pool: &'static PgPool,
) -> impl Future<Item = impl Reply, Error = Rejection> {
let mut rng = thread_rng();
let identifier: String = (0..10)
.map(|_| char::from(*CHARACTERS.choose(&mut rng).expect("a random character")))
@ -40,7 +45,13 @@ pub fn insert_paste(form: PasteForm, db: Connection) -> impl Reply {
language_id: form.language,
paste: form.code,
})
.execute(&db)
.unwrap();
warp::redirect(format!("/{}", cloned_identifier).parse::<Uri>().unwrap())
.execute_async(&pool)
.compat()
.map_err(warp::reject::custom)
.and_then(move |_| {
format!("/{}", cloned_identifier)
.parse::<Uri>()
.map_err(warp::reject::custom)
})
.map(warp::redirect)
}

View File

@ -16,32 +16,33 @@ use warp::http::{Response, StatusCode};
use warp::{path, Filter, Rejection, Reply};
pub fn routes(database_url: &str) -> impl Filter<Extract = (impl Reply,)> {
let pool =
Pool::new(ConnectionManager::new(database_url)).expect("Couldn't create a connection pool");
let db = warp::any().map(move || pool.get().unwrap());
let pool = &*Box::leak(Box::new(
Pool::new(ConnectionManager::new(database_url)).expect("Couldn't create a connection pool"),
));
let pool = warp::any().map(move || pool);
let index = warp::path::end()
.and(warp::get2())
.and(db.clone())
.and(pool)
.and_then(index::index);
let display_paste = warp::path::param()
.and(warp::path::end())
.and(warp::get2())
.and(db.clone())
.and(pool)
.and_then(display_paste::display_paste);
let raw_paste = with_ext("txt")
.and(warp::get2())
.and(db.clone())
.and(pool)
.and_then(raw_paste::raw_paste);
let insert_paste = warp::path::end()
.and(warp::post2())
.and(warp::body::content_length_limit(1_000_000))
.and(warp::body::form())
.and(db.clone())
.map(insert_paste::insert_paste);
.and(pool)
.and_then(insert_paste::insert_paste);
let api_language = path!("api" / "v0" / "language" / i32)
.and(warp::path::end())
.and(warp::get2())
.and(db)
.and(pool)
.and_then(api_language::api_language);
let static_dir = warp::path("static").and(warp::fs::dir("static"));
let favicon = warp::path("favicon.ico")

View File

@ -1,16 +1,26 @@
use crate::models::paste::Paste;
use crate::schema::pastes::dsl::*;
use crate::Connection;
use crate::PgPool;
use diesel::prelude::*;
use futures::Future;
use futures03::TryFutureExt;
use tokio_diesel::{AsyncRunQueryDsl, OptionalExtension};
use warp::Rejection;
pub fn raw_paste(requested_identifier: String, db: Connection) -> Result<String, Rejection> {
Paste::delete_old(&db);
pastes
.select(paste)
.filter(identifier.eq(requested_identifier))
.get_result(&db)
.optional()
.unwrap()
.ok_or_else(warp::reject::not_found)
pub fn raw_paste(
requested_identifier: String,
pool: &'static PgPool,
) -> impl Future<Item = String, Error = Rejection> {
Paste::delete_old(pool)
.and_then(move |()| {
pastes
.select(paste)
.filter(identifier.eq(requested_identifier))
.get_result_async(pool)
.compat()
.then(|result| result.optional())
.map(|paste_contents| paste_contents.ok_or_else(warp::reject::not_found))
})
.map_err(warp::reject::custom)
.flatten()
}