|
@@ -13,14 +13,14 @@ extern crate url;
|
|
extern crate diesel;
|
|
extern crate diesel;
|
|
extern crate tokio_postgres;
|
|
extern crate tokio_postgres;
|
|
|
|
|
|
-use std::{mem, io};
|
|
|
|
use std::cell::RefCell;
|
|
use std::cell::RefCell;
|
|
-use std::rc::Rc;
|
|
|
|
use std::io::Write;
|
|
use std::io::Write;
|
|
|
|
+use std::rc::Rc;
|
|
|
|
+use std::{io, mem};
|
|
|
|
|
|
use actix::prelude::*;
|
|
use actix::prelude::*;
|
|
use actix_web::server::{
|
|
use actix_web::server::{
|
|
- self, HttpHandler, HttpHandlerTask, HttpServer, Request, Writer,
|
|
|
|
|
|
+ self, HttpHandler, HttpHandlerTask, HttpServer, KeepAlive, Request, Writer,
|
|
};
|
|
};
|
|
use actix_web::Error;
|
|
use actix_web::Error;
|
|
use futures::{Async, Future, Poll};
|
|
use futures::{Async, Future, Poll};
|
|
@@ -31,7 +31,7 @@ mod models;
|
|
mod utils;
|
|
mod utils;
|
|
|
|
|
|
use db_pg_direct::PgConnection;
|
|
use db_pg_direct::PgConnection;
|
|
-use utils::{Message, StackWriter, Writer as JsonWriter, escape};
|
|
|
|
|
|
+use utils::{escape, Message, StackWriter, Writer as JsonWriter};
|
|
|
|
|
|
const HTTPOK: &[u8] = b"HTTP/1.1 200 OK\r\n";
|
|
const HTTPOK: &[u8] = b"HTTP/1.1 200 OK\r\n";
|
|
const HDR_SERVER: &[u8] = b"Server: Actix\r\n";
|
|
const HDR_SERVER: &[u8] = b"Server: Actix\r\n";
|
|
@@ -42,6 +42,7 @@ const BODY: &[u8] = b"Hello, World!";
|
|
|
|
|
|
struct App {
|
|
struct App {
|
|
dbs: Rc<RefCell<Vec<PgConnection>>>,
|
|
dbs: Rc<RefCell<Vec<PgConnection>>>,
|
|
|
|
+ useall: bool,
|
|
}
|
|
}
|
|
|
|
|
|
impl HttpHandler for App {
|
|
impl HttpHandler for App {
|
|
@@ -54,25 +55,51 @@ impl HttpHandler for App {
|
|
10 if path == "/plaintext" => return Ok(Box::new(Plaintext)),
|
|
10 if path == "/plaintext" => return Ok(Box::new(Plaintext)),
|
|
5 if path == "/json" => return Ok(Box::new(Json)),
|
|
5 if path == "/json" => return Ok(Box::new(Json)),
|
|
3 if path == "/db" => {
|
|
3 if path == "/db" => {
|
|
- if let Some(db) = thread_rng().choose(&*self.dbs.borrow()) {
|
|
|
|
- return Ok(Box::new(World {fut: Box::new(db.get_world())}))
|
|
|
|
|
|
+ if self.useall {
|
|
|
|
+ if let Some(db) = thread_rng().choose(&*self.dbs.borrow()) {
|
|
|
|
+ return Ok(Box::new(World {
|
|
|
|
+ fut: db.get_world(),
|
|
|
|
+ }));
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ return Ok(Box::new(World {
|
|
|
|
+ fut: self.dbs.borrow()[0].get_world(),
|
|
|
|
+ }));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
8 if path == "/fortune" => {
|
|
8 if path == "/fortune" => {
|
|
if let Some(db) = thread_rng().choose(&*self.dbs.borrow()) {
|
|
if let Some(db) = thread_rng().choose(&*self.dbs.borrow()) {
|
|
- return Ok(Box::new(Fortune {fut: Box::new(db.tell_fortune())}));
|
|
|
|
|
|
+ return Ok(Box::new(Fortune {
|
|
|
|
+ fut: db.tell_fortune(),
|
|
|
|
+ }));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
8 if path == "/queries" => {
|
|
8 if path == "/queries" => {
|
|
let q = utils::get_query_param(req.uri());
|
|
let q = utils::get_query_param(req.uri());
|
|
- if let Some(db) = thread_rng().choose(&*self.dbs.borrow()) {
|
|
|
|
- return Ok(Box::new(Queries {fut: Box::new(db.get_worlds(q as usize))}));
|
|
|
|
|
|
+ if self.useall {
|
|
|
|
+ if let Some(db) = thread_rng().choose(&*self.dbs.borrow()) {
|
|
|
|
+ return Ok(Box::new(Queries {
|
|
|
|
+ fut: db.get_worlds(q as usize),
|
|
|
|
+ }));
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ return Ok(Box::new(Queries {
|
|
|
|
+ fut: self.dbs.borrow()[0].get_worlds(q as usize),
|
|
|
|
+ }));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
8 if path == "/updates" => {
|
|
8 if path == "/updates" => {
|
|
let q = utils::get_query_param(req.uri());
|
|
let q = utils::get_query_param(req.uri());
|
|
- if let Some(db) = thread_rng().choose(&*self.dbs.borrow()) {
|
|
|
|
- return Ok(Box::new(Updates {fut: Box::new(db.update(q as usize))}));
|
|
|
|
|
|
+ if self.useall {
|
|
|
|
+ if let Some(db) = thread_rng().choose(&*self.dbs.borrow()) {
|
|
|
|
+ return Ok(Box::new(Updates {
|
|
|
|
+ fut: db.update(q as usize),
|
|
|
|
+ }));
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ return Ok(Box::new(Updates {
|
|
|
|
+ fut: self.dbs.borrow()[0].update(q as usize),
|
|
|
|
+ }));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
_ => (),
|
|
_ => (),
|
|
@@ -122,8 +149,8 @@ impl HttpHandlerTask for Json {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-struct Fortune {
|
|
|
|
- fut: Box<Future<Item=Vec<models::Fortune>, Error=io::Error>>,
|
|
|
|
|
|
+struct Fortune<F> {
|
|
|
|
+ fut: F,
|
|
}
|
|
}
|
|
|
|
|
|
const FORTUNES_START: &[u8] = b"<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>";
|
|
const FORTUNES_START: &[u8] = b"<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>";
|
|
@@ -132,8 +159,10 @@ const FORTUNES_COLUMN: &[u8] = b"</td><td>";
|
|
const FORTUNES_ROW_END: &[u8] = b"</td></tr>";
|
|
const FORTUNES_ROW_END: &[u8] = b"</td></tr>";
|
|
const FORTUNES_END: &[u8] = b"</table></body></html>";
|
|
const FORTUNES_END: &[u8] = b"</table></body></html>";
|
|
|
|
|
|
-
|
|
|
|
-impl HttpHandlerTask for Fortune {
|
|
|
|
|
|
+impl<F> HttpHandlerTask for Fortune<F>
|
|
|
|
+where
|
|
|
|
+ F: Future<Item = Vec<models::Fortune>, Error = io::Error>,
|
|
|
|
+{
|
|
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
|
|
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
|
|
match self.fut.poll() {
|
|
match self.fut.poll() {
|
|
Ok(Async::Ready(rows)) => {
|
|
Ok(Async::Ready(rows)) => {
|
|
@@ -170,11 +199,14 @@ impl HttpHandlerTask for Fortune {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-struct World {
|
|
|
|
- fut: Box<Future<Item=models::World, Error=io::Error>>,
|
|
|
|
|
|
+struct World<F> {
|
|
|
|
+ fut: F,
|
|
}
|
|
}
|
|
|
|
|
|
-impl HttpHandlerTask for World {
|
|
|
|
|
|
+impl<F> HttpHandlerTask for World<F>
|
|
|
|
+where
|
|
|
|
+ F: Future<Item = models::World, Error = io::Error>,
|
|
|
|
+{
|
|
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
|
|
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
|
|
match self.fut.poll() {
|
|
match self.fut.poll() {
|
|
Ok(Async::Ready(row)) => {
|
|
Ok(Async::Ready(row)) => {
|
|
@@ -203,11 +235,14 @@ impl HttpHandlerTask for World {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-struct Queries {
|
|
|
|
- fut: Box<Future<Item=Vec<models::World>, Error=io::Error>>,
|
|
|
|
|
|
+struct Queries<F> {
|
|
|
|
+ fut: F,
|
|
}
|
|
}
|
|
|
|
|
|
-impl HttpHandlerTask for Queries {
|
|
|
|
|
|
+impl<F> HttpHandlerTask for Queries<F>
|
|
|
|
+where
|
|
|
|
+ F: Future<Item = Vec<models::World>, Error = io::Error>,
|
|
|
|
+{
|
|
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
|
|
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
|
|
match self.fut.poll() {
|
|
match self.fut.poll() {
|
|
Ok(Async::Ready(worlds)) => {
|
|
Ok(Async::Ready(worlds)) => {
|
|
@@ -236,11 +271,14 @@ impl HttpHandlerTask for Queries {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-struct Updates {
|
|
|
|
- fut: Box<Future<Item=Vec<models::World>, Error=io::Error>>,
|
|
|
|
|
|
+struct Updates<F> {
|
|
|
|
+ fut: F,
|
|
}
|
|
}
|
|
|
|
|
|
-impl HttpHandlerTask for Updates {
|
|
|
|
|
|
+impl<F> HttpHandlerTask for Updates<F>
|
|
|
|
+where
|
|
|
|
+ F: Future<Item = Vec<models::World>, Error = io::Error>,
|
|
|
|
+{
|
|
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
|
|
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
|
|
match self.fut.poll() {
|
|
match self.fut.poll() {
|
|
Ok(Async::Ready(worlds)) => {
|
|
Ok(Async::Ready(worlds)) => {
|
|
@@ -277,19 +315,23 @@ fn main() {
|
|
HttpServer::new(move || {
|
|
HttpServer::new(move || {
|
|
let dbs = Rc::new(RefCell::new(Vec::new()));
|
|
let dbs = Rc::new(RefCell::new(Vec::new()));
|
|
|
|
|
|
- let db = dbs.clone();
|
|
|
|
- Arbiter::spawn(
|
|
|
|
- PgConnection::connect(db_url)
|
|
|
|
- .and_then(move |conn| {
|
|
|
|
- db.borrow_mut().push(conn);
|
|
|
|
- Ok(())
|
|
|
|
- }));
|
|
|
|
|
|
+ for _ in 0..3 {
|
|
|
|
+ let db = dbs.clone();
|
|
|
|
+ Arbiter::spawn(PgConnection::connect(db_url).and_then(move |conn| {
|
|
|
|
+ db.borrow_mut().push(conn);
|
|
|
|
+ Ok(())
|
|
|
|
+ }));
|
|
|
|
+ }
|
|
|
|
|
|
- vec![App { dbs }]
|
|
|
|
|
|
+ vec![App {
|
|
|
|
+ dbs,
|
|
|
|
+ useall: num_cpus::get() > 4,
|
|
|
|
+ }]
|
|
}).backlog(8192)
|
|
}).backlog(8192)
|
|
- .bind("0.0.0.0:8080")
|
|
|
|
- .unwrap()
|
|
|
|
- .start();
|
|
|
|
|
|
+ .keep_alive(KeepAlive::Os)
|
|
|
|
+ .bind("0.0.0.0:8080")
|
|
|
|
+ .unwrap()
|
|
|
|
+ .start();
|
|
|
|
|
|
println!("Started http server: 127.0.0.1:8080");
|
|
println!("Started http server: 127.0.0.1:8080");
|
|
let _ = sys.run();
|
|
let _ = sys.run();
|