summaryrefslogtreecommitdiff
path: root/src/main.rs
blob: bb3c57e66d415fae6a1f1dc5ddb682bb92f959f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#![feature(test)]
#![feature(convert_id)]
#![feature(proc_macro_hygiene)]
#![feature(try_from)]
#![feature(duration_as_u128)]
#![feature(libc)]

use std::env;
use std::sync::Arc;
use std::thread;
use std::sync::atomic;
use std::net::SocketAddr;

extern crate ascii;
extern crate getopts;
#[macro_use]
extern crate log;
extern crate tokio;
extern crate tokio_threadpool;
extern crate tokio_executor;
extern crate time;
extern crate simple_logger;
extern crate oath;
extern crate evmap;
extern crate test;
#[macro_use]
extern crate horrorshow;
extern crate random;
extern crate http;
extern crate httparse;
extern crate bytes;
extern crate thread_local;
extern crate cookie;
extern crate url;

use getopts::Options;
use log::LogLevel::{Debug, Warn};
use time::Duration;

mod auth_handler;
mod cookie_store;
mod http_server;
mod router;
mod system;
mod totp;

extern crate libc;

use cookie_store::CookieStore;

#[derive(Clone)]
pub struct ApplicationState {
    cookie_store: CookieStore,
    cookie_max_age: Duration,
}

fn print_usage(program: &str, opts: &Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optopt("l", "port", "Listen address", "LISTEN-ADDR");
    opts.optflag("d", "debug", "Use loglevel Debug instead of Warn");
    opts.optflag("h", "help", "print this help menu");
    let matches = opts.parse(&args[1..]).unwrap_or_else(|f| panic!(f.to_string()));

    if matches.opt_present("h") {
        print_usage(&program, &opts);
        return;
    }

    simple_logger::init_with_level(if matches.opt_present("d") { Debug } else { Warn })
        .unwrap_or_else(|_| panic!("Failed to initialize logger"));


    let addr = matches.opt_str("l").unwrap_or_else(||"127.0.0.1:8080".to_string());
    let addr = addr.parse::<SocketAddr>()
        .unwrap_or_else(|_| panic!("Failed to parse LISTEN-ADDRESS"));


    // concurrent eventual consistent hashmap with <cookie-id, timeout>
    let state = ApplicationState { cookie_store: CookieStore::new(), cookie_max_age: Duration::days(1) };

    let server_shutdown_condvar = Arc::new(atomic::AtomicBool::new(false));

    let cookie_clean_thread_condvar = server_shutdown_condvar.clone();
    let cookie_clean_state = state.clone();
    let cookie_clean_thread = thread::spawn(move || {
        while !cookie_clean_thread_condvar.load(atomic::Ordering::Relaxed) {
            thread::sleep(std::time::Duration::from_secs(60));
            debug!("Clean cookie cache");
            cookie_clean_state.cookie_store.clean_outdated_cookies();
        }
    });

    let auth_handler = auth_handler::AuthHandler::make();
    http_server::serve(addr, state, auth_handler);

    server_shutdown_condvar.store(true, atomic::Ordering::Relaxed);
    debug!("Waiting for cleanup thread to shutdown");
    cookie_clean_thread.join().unwrap();
}