Initial commit
Basic POST and GET callback have been implemented
This commit is contained in:
39
src/bin/callmeback.rs
Normal file
39
src/bin/callmeback.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
//extern crate callmeback;
|
||||
extern crate dotenv;
|
||||
extern crate env_logger;
|
||||
extern crate listenfd;
|
||||
|
||||
use actix::prelude::*;
|
||||
use actix_web::{server::HttpServer, App};
|
||||
use callmeback::db::DbExecutor;
|
||||
use dotenv::dotenv;
|
||||
use listenfd::ListenFd;
|
||||
use std::env;
|
||||
|
||||
pub fn main() {
|
||||
::std::env::set_var("RUST_LOG", "actix_web=info");
|
||||
env_logger::init();
|
||||
|
||||
dotenv().ok();
|
||||
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
|
||||
|
||||
let mut listenfd = ListenFd::from_env();
|
||||
let sys = actix::System::new("callmeback");
|
||||
|
||||
let addr = SyncArbiter::start(3, move || DbExecutor::new(&database_url));
|
||||
|
||||
let mut server = HttpServer::new(move || {
|
||||
callmeback::configure_app(App::with_state(callmeback::AppState { db: addr.clone() }))
|
||||
})
|
||||
.keep_alive(60)
|
||||
.shutdown_timeout(60);
|
||||
|
||||
server = if let Some(l) = listenfd.take_tcp_listener(0).unwrap() {
|
||||
server.listen(l)
|
||||
} else {
|
||||
server.bind("127.0.0.1:3000").unwrap()
|
||||
};
|
||||
server.start();
|
||||
|
||||
let _ = sys.run();
|
||||
}
|
||||
50
src/controller.rs
Normal file
50
src/controller.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
pub mod callback {
|
||||
use super::super::db::callback::{CreateCallback, GetCallback};
|
||||
use super::super::AppState;
|
||||
use actix_web::{
|
||||
error, AsyncResponder, Error, FutureResponse, HttpResponse, Json, Path, State,
|
||||
};
|
||||
use chrono::prelude::*;
|
||||
use futures::Future;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CallbackCall {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
pub fn create(
|
||||
(params, callback, state): (Path<(String,)>, Json<CallbackCall>, State<AppState>),
|
||||
) -> impl Future<Item = HttpResponse, Error = Error> {
|
||||
let date_param = params
|
||||
.0
|
||||
.parse::<DateTime<Utc>>()
|
||||
.map_err(|_e| error::ErrorBadRequest("Bad date"))
|
||||
.unwrap();
|
||||
|
||||
state
|
||||
.db
|
||||
.send(CreateCallback {
|
||||
url: callback.url.to_owned(),
|
||||
scheduled_date: date_param,
|
||||
})
|
||||
.from_err()
|
||||
.and_then(|res| match res {
|
||||
Ok(callback) => Ok(HttpResponse::Ok().json(callback)),
|
||||
Err(_) => Ok(HttpResponse::InternalServerError().into()),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get((id, state): (Path<i32>, State<AppState>)) -> FutureResponse<HttpResponse> {
|
||||
state
|
||||
.db
|
||||
.send(GetCallback {
|
||||
id: id.into_inner(),
|
||||
})
|
||||
.from_err()
|
||||
.and_then(|res| match res {
|
||||
Ok(callback) => Ok(HttpResponse::Ok().json(callback)),
|
||||
Err(_) => Ok(HttpResponse::InternalServerError().into()),
|
||||
})
|
||||
.responder()
|
||||
}
|
||||
}
|
||||
76
src/db.rs
Normal file
76
src/db.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
use actix::prelude::*;
|
||||
use diesel::pg::PgConnection;
|
||||
use diesel::prelude::*;
|
||||
|
||||
pub struct DbExecutor(PgConnection);
|
||||
|
||||
impl Actor for DbExecutor {
|
||||
type Context = SyncContext<Self>;
|
||||
}
|
||||
|
||||
impl DbExecutor {
|
||||
pub fn new(database_url: &str) -> Self {
|
||||
DbExecutor(
|
||||
PgConnection::establish(database_url)
|
||||
.unwrap_or_else(|_| panic!("Error connecting to {}", database_url)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod callback {
|
||||
use super::super::db::DbExecutor;
|
||||
use super::super::models;
|
||||
use super::super::schema::*;
|
||||
use actix::prelude::*;
|
||||
use chrono::prelude::*;
|
||||
use diesel::prelude::*;
|
||||
|
||||
use actix_web::Error;
|
||||
|
||||
pub struct CreateCallback {
|
||||
pub url: String,
|
||||
pub scheduled_date: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl Message for CreateCallback {
|
||||
type Result = Result<models::Callback, Error>;
|
||||
}
|
||||
|
||||
impl Handler<CreateCallback> for DbExecutor {
|
||||
type Result = Result<models::Callback, Error>;
|
||||
|
||||
fn handle(&mut self, msg: CreateCallback, _: &mut Self::Context) -> Self::Result {
|
||||
let new_callback = models::NewCallback {
|
||||
url: &msg.url,
|
||||
scheduled_date: &msg.scheduled_date,
|
||||
};
|
||||
|
||||
Ok(diesel::insert_into(callbacks::table)
|
||||
.values(&new_callback)
|
||||
.get_result(&self.0)
|
||||
.expect("Error inserting callback"))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GetCallback {
|
||||
pub id: i32,
|
||||
}
|
||||
|
||||
impl Message for GetCallback {
|
||||
type Result = Result<models::Callback, Error>;
|
||||
}
|
||||
|
||||
impl Handler<GetCallback> for DbExecutor {
|
||||
type Result = Result<models::Callback, Error>;
|
||||
|
||||
fn handle(&mut self, msg: GetCallback, _: &mut Self::Context) -> Self::Result {
|
||||
Ok(callbacks::table
|
||||
.filter(callbacks::id.eq(msg.id))
|
||||
.limit(1)
|
||||
.load::<models::Callback>(&self.0)
|
||||
.expect("Error loading callbacks")
|
||||
.pop()
|
||||
.unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
41
src/lib.rs
Normal file
41
src/lib.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
#[macro_use]
|
||||
extern crate diesel;
|
||||
extern crate actix;
|
||||
extern crate actix_web;
|
||||
extern crate actix_web_requestid;
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate chrono;
|
||||
|
||||
mod controller;
|
||||
pub mod db;
|
||||
mod models;
|
||||
mod schema;
|
||||
|
||||
use self::db::DbExecutor;
|
||||
use actix::prelude::*;
|
||||
use actix_web::middleware::Logger;
|
||||
use actix_web::{http, App};
|
||||
use actix_web_requestid::RequestIDHeader;
|
||||
|
||||
pub struct AppState {
|
||||
pub db: Addr<DbExecutor>,
|
||||
}
|
||||
|
||||
pub fn configure_app(app: App<AppState>) -> App<AppState> {
|
||||
app.middleware(RequestIDHeader)
|
||||
.middleware(Logger::default())
|
||||
.resource("/{datetime}", |r| {
|
||||
r.method(http::Method::POST).with_async_config(
|
||||
controller::callback::create,
|
||||
|(json_cfg,)| {
|
||||
json_cfg.1.limit(4096);
|
||||
},
|
||||
);
|
||||
})
|
||||
.resource("/callback/{id}", |r| {
|
||||
r.method(http::Method::GET).with(controller::callback::get)
|
||||
})
|
||||
}
|
||||
16
src/models.rs
Normal file
16
src/models.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
use super::schema::callbacks;
|
||||
use chrono::prelude::*;
|
||||
|
||||
#[derive(Queryable, Serialize)]
|
||||
pub struct Callback {
|
||||
id: i32,
|
||||
url: String,
|
||||
scheduled_date: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[table_name = "callbacks"]
|
||||
pub struct NewCallback<'a> {
|
||||
pub url: &'a str,
|
||||
pub scheduled_date: &'a DateTime<Utc>,
|
||||
}
|
||||
7
src/schema.rs
Normal file
7
src/schema.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
table! {
|
||||
callbacks (id) {
|
||||
id -> Int4,
|
||||
url -> Varchar,
|
||||
scheduled_date -> Timestamptz,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user