changed database connection to use r2d2 and implemented subscription insert

This commit is contained in:
Gonçalo Valério 2019-07-07 22:54:21 +01:00
parent 6b3f200778
commit f65ae11463
7 changed files with 140 additions and 53 deletions

View File

@ -6,17 +6,12 @@ jobs:
working_directory: ~/repo
steps:
- checkout
- restore_cache:
keys:
- v1-dependencies-{{ checksum "Cargo.lock" }}
- run:
name: install dependencies
command: |
cargo build
- save_cache:
paths:
- ~/.cargo
key: v1-dependencies-{{ checksum "Cargo.lock" }}
cargo install diesel_cli
diesel migration run
- run:
name: run test suite
command: |

22
Cargo.lock generated
View File

@ -568,6 +568,7 @@ dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"diesel_derives 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libsqlite3-sys 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"r2d2 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1136,6 +1137,16 @@ dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "r2d2"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"scheduled-thread-pool 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.6.5"
@ -1315,6 +1326,7 @@ dependencies = [
"askama 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"diesel 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"r2d2 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
"slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slog-term 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1327,6 +1339,14 @@ name = "ryu"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "scheduled-thread-pool"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "scoped_threadpool"
version = "0.1.9"
@ -1992,6 +2012,7 @@ dependencies = [
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
"checksum r2d2 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bc42ce75d9f4447fb2a04bbe1ed5d18dd949104572850ec19b164e274919f81b"
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
@ -2012,6 +2033,7 @@ dependencies = [
"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
"checksum scheduled-thread-pool 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bbecfcb36d47e0d6a4aefb198d475b13aa06e326770c1271171d44893766ae1c"
"checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"

View File

@ -6,7 +6,8 @@ authors = ["Gonçalo Valério <gon@ovalerio.net>"]
[dependencies]
actix = "0.8.3"
actix-web = "1.0.2"
diesel = { version = "1.4.2", features = ["sqlite"] }
r2d2 = "0.8.5"
diesel = { version = "1.4.2", features = ["sqlite", "r2d2"] }
toml = "0.5.0"
clap = "2.32.0"
askama = "0.8"

View File

@ -1,3 +1,65 @@
use url::form_urlencoded::Parse;
use super::schema::subscriptions;
use diesel::prelude::*;
use models::NewSubscription;
use std::collections::HashMap;
use std::convert::TryFrom;
use std::time::{SystemTime, UNIX_EPOCH};
use utils::{setup_logging, Pool};
pub fn handle_subscription(data: Parse) {}
pub fn handle_subscription(db: &Pool, data: &HashMap<String, String>) -> bool {
let log = setup_logging();
let mode;
let callback;
let topic;
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Invalid Time")
.as_secs();
let now = i32::try_from(timestamp).ok().unwrap();
let conn = db.get().unwrap();
match data.get("hub.mode") {
Some(value) => mode = value,
None => return false,
}
match data.get("hub.callback") {
Some(value) => callback = value,
None => return false,
}
match data.get("hub.topic") {
Some(value) => topic = value,
None => return false,
}
debug!(
log,
"Mode: {}, Callback: {}, topic: {}", mode, callback, topic
);
if mode == &"subscribe" {
let subscription = NewSubscription {
callback: callback,
topic: topic,
sec: "",
created_at: &now,
expires_at: &now,
};
diesel::insert_into(subscriptions::table)
.values(&subscription)
.execute(&conn)
.expect("Error saving new subscription");
debug!(log, "Subscription created.");
return true;
} else if mode == &"unsubscribe" {
return true;
} else {
debug!(log, "Wrong method.");
return false;
}
}
#[cfg(test)]
mod tests {}

View File

@ -1,9 +1,9 @@
use actions::handle_subscription;
use actix_web::{http, web, HttpRequest, HttpResponse};
use askama::Template;
use std::collections::HashMap;
use url::form_urlencoded;
use utils::{validate_parsed_data, AppState};
use std::collections::HashMap;
#[derive(Template)]
#[template(path = "index.html")]
@ -17,6 +17,7 @@ pub fn index(_state: web::Data<AppState>, _req: HttpRequest) -> HttpResponse {
pub fn hub(state: web::Data<AppState>, _req: HttpRequest, params: String) -> HttpResponse {
let log = &state.log;
let db = &state.db;
info!(log, "Received Request");
debug!(log, "Content: {}", params);
@ -26,13 +27,14 @@ pub fn hub(state: web::Data<AppState>, _req: HttpRequest, params: String) -> Htt
parameters.insert(key.to_string(), value.to_string());
}
if !validate_parsed_data(parameters) {
if !validate_parsed_data(&parameters) {
return HttpResponse::Ok()
.status(http::StatusCode::BAD_REQUEST)
.finish();
}
handle_subscription(parsed_data);
let result = handle_subscription(db, &parameters);
debug!(log, "{}", result);
return HttpResponse::Ok()
.status(http::StatusCode::ACCEPTED)
.finish();
@ -41,21 +43,23 @@ pub fn hub(state: web::Data<AppState>, _req: HttpRequest, params: String) -> Htt
#[cfg(test)]
mod tests {
use super::*;
use actix::{SyncArbiter, System};
use actix::System;
use actix_web::{http, test, web};
use diesel::prelude::*;
use utils::{setup_logging, DbExecutor};
use diesel::r2d2::{self, ConnectionManager};
use utils::setup_logging;
#[test]
fn test_index() {
let _sys = System::new("rusty-hub-test");
let addr = SyncArbiter::start(1, || {
DbExecutor(SqliteConnection::establish("test.db").unwrap())
});
let manager = ConnectionManager::<SqliteConnection>::new("test.db");
let pool = r2d2::Pool::builder()
.build(manager)
.expect("Failed to create pool.");
let data = web::Data::new(AppState {
log: setup_logging(),
db: addr.clone(),
db: pool.clone(),
});
let resp = index(data, test::TestRequest::get().to_http_request());
@ -65,13 +69,14 @@ mod tests {
#[test]
fn test_hub_no_parameters() {
let _sys = System::new("rusty-hub-test");
let addr = SyncArbiter::start(1, || {
DbExecutor(SqliteConnection::establish("test.db").unwrap())
});
let manager = ConnectionManager::<SqliteConnection>::new("test.db");
let pool = r2d2::Pool::builder()
.build(manager)
.expect("Failed to create pool.");
let data = web::Data::new(AppState {
log: setup_logging(),
db: addr.clone(),
db: pool.clone(),
});
let resp = hub(
@ -85,13 +90,14 @@ mod tests {
#[test]
fn test_hub_invalid_callback() {
let _sys = System::new("rusty-hub-test");
let addr = SyncArbiter::start(1, || {
DbExecutor(SqliteConnection::establish("test.db").unwrap())
});
let manager = ConnectionManager::<SqliteConnection>::new("test.db");
let pool = r2d2::Pool::builder()
.build(manager)
.expect("Failed to create pool.");
let data = web::Data::new(AppState {
log: setup_logging(),
db: addr.clone(),
db: pool.clone(),
});
let resp = hub(
@ -105,13 +111,14 @@ mod tests {
#[test]
fn test_hub_invalid_topic() {
let _sys = System::new("rusty-hub-test");
let addr = SyncArbiter::start(1, || {
DbExecutor(SqliteConnection::establish("test.db").unwrap())
});
let manager = ConnectionManager::<SqliteConnection>::new("test.db");
let pool = r2d2::Pool::builder()
.build(manager)
.expect("Failed to create pool.");
let data = web::Data::new(AppState {
log: setup_logging(),
db: addr.clone(),
db: pool.clone(),
});
let resp = hub(
@ -125,13 +132,14 @@ mod tests {
#[test]
fn test_hub_invalid_mode() {
let _sys = System::new("rusty-hub-test");
let addr = SyncArbiter::start(1, || {
DbExecutor(SqliteConnection::establish("test.db").unwrap())
});
let manager = ConnectionManager::<SqliteConnection>::new("test.db");
let pool = r2d2::Pool::builder()
.build(manager)
.expect("Failed to create pool.");
let data = web::Data::new(AppState {
log: setup_logging(),
db: addr.clone(),
db: pool.clone(),
});
let resp = hub(
@ -145,13 +153,14 @@ mod tests {
#[test]
fn test_hub_subscribe_success() {
let _sys = System::new("rusty-hub-test");
let addr = SyncArbiter::start(1, || {
DbExecutor(SqliteConnection::establish("test.db").unwrap())
});
let manager = ConnectionManager::<SqliteConnection>::new("test.db");
let pool = r2d2::Pool::builder()
.build(manager)
.expect("Failed to create pool.");
let data = web::Data::new(AppState {
log: setup_logging(),
db: addr.clone(),
db: pool.clone(),
});
let resp = hub(

View File

@ -9,12 +9,13 @@ extern crate slog;
extern crate slog_async;
extern crate slog_term;
extern crate url;
use actix::{SyncArbiter, System};
use actix::{System};
use actix_web::{web, App, HttpServer};
use clap::Arg;
use controllers::{hub, index};
use diesel::prelude::*;
use utils::{setup_logging, AppState, DbExecutor};
use diesel::r2d2::{self, ConnectionManager};
use utils::{setup_logging, AppState};
mod actions;
mod controllers;
@ -50,13 +51,14 @@ fn main() {
}
let sys = System::new("rusty-hub");
let addr = SyncArbiter::start(3, || {
DbExecutor(SqliteConnection::establish("local.db").unwrap())
});
let manager = ConnectionManager::<SqliteConnection>::new("local.db");
let pool = r2d2::Pool::builder()
.build(manager)
.expect("Failed to create pool.");
let app_data = web::Data::new(AppState {
log: setup_logging(),
db: addr.clone(),
db: pool.clone(),
});
info!(log, "Starting server");

View File

@ -1,19 +1,15 @@
use actix::{Actor, Addr, SyncContext};
use diesel::prelude::*;
use diesel::r2d2::{self, ConnectionManager};
use slog::Drain;
use std::collections::HashMap;
use url::Url;
pub struct DbExecutor(pub SqliteConnection);
impl Actor for DbExecutor {
type Context = SyncContext<Self>;
}
pub type Pool = r2d2::Pool<ConnectionManager<SqliteConnection>>;
pub struct AppState {
pub log: slog::Logger,
pub db: Addr<DbExecutor>,
pub db: Pool,
}
pub fn setup_logging() -> slog::Logger {
@ -23,7 +19,7 @@ pub fn setup_logging() -> slog::Logger {
slog::Logger::root(drain, o!())
}
pub fn validate_parsed_data(parameters: HashMap<String,String>) -> bool {
pub fn validate_parsed_data(parameters: &HashMap<String,String>) -> bool {
let callback;
let mode;
let topic;