<commit_before>use chrono::{NaiveDateTime, Utc};
use diesel::data_types::PgInterval;
use diesel::prelude::*;
use std::time::Duration;

use crate::schema::{publish_limit_buckets, publish_rate_overrides};
use crate::util::errors::{AppResult, TooManyRequests};

#[derive(Debug, Clone, Copy)]
pub struct PublishRateLimit {
    pub rate: Duration,
    pub burst: i32,
}

impl Default for PublishRateLimit {
    fn default() -> Self {
        Self {
            rate: Duration::from_secs(60) * 10,
            burst: 30,
        }
    }
}

#[derive(Queryable, Insertable, Debug, PartialEq, Clone, Copy)]
#[table_name = "publish_limit_buckets"]
#[allow(dead_code)] // Most fields only read in tests
struct Bucket {
    user_id: i32,
    tokens: i32,
    last_refill: NaiveDateTime,
}

impl PublishRateLimit {
    pub fn check_rate_limit(&self, uploader: i32, conn: &PgConnection) -> AppResult<()> {
        let bucket = self.take_token(uploader, Utc::now().naive_utc(), conn)?;
        if bucket.tokens >= 1 {
            Ok(())
        } else {
            Err(Box::new(TooManyRequests {
                retry_after: bucket.last_refill + chrono::Duration::from_std(self.rate).unwrap(),
            }))
        }
    }

    /// Refill a user's bucket as needed, take a token from it,
    /// and returns the result.
    ///
    /// The number of tokens remaining will always be between 0 and self.burst.
    /// If the number is 0, the request should be rejected, as the user doesn't
    /// have a token to take. Technically a "full" bucket would have
    /// `self.burst + 1` tokens in it, but that value would never be returned
    /// since we only refill buckets when trying to take a token from it.
    fn take_token(
        &self,
        uploader: i32,
        now: NaiveDateTime,
        conn: &PgConnection,
    ) -> QueryResult<Bucket> {
        use self::publish_limit_buckets::dsl::*;
        use diesel::sql_types::{Double, Interval, Text, Timestamp};

        sql_function!(fn date_part(x: Text, y: Timestamp) -> Double);
        sql_function! {
            #[sql_name = "date_part"]
            fn interval_part(x: Text, y: Interval) -> Double;
        }
        sql_function!(fn floor(x: Double) -> Integer);
        sql_function!(fn greatest<T>(x: T, y: T) -> T);
        sql_function!(fn least<T>(x: T, y: T) -> T);

        let burst: i32 = publish_rate_overrides::table
            .find(uploader)
            .select(publish_rate_overrides::burst)
            .first(conn)
            .optional()?
            .unwrap_or(self.burst);

        // Interval division is poorly defined in general (what is 1 month / 30 days?)
        // However, for the intervals we're dealing with, it is always well
        // defined, so we convert to an f64 of seconds to represent this.
        let tokens_to_add = floor(
            (date_part("epoch", now) - date_part("epoch", last_refill))
                / interval_part("epoch", self.refill_rate()),
        );

        diesel::insert_into(publish_limit_buckets)
            .values((user_id.eq(uploader), tokens.eq(burst), last_refill.eq(now)))
            .on_conflict(user_id)
            .do_update()
            .set((
                tokens.eq(least(burst, greatest(0, tokens - 1) + tokens_to_add)),
                last_refill
                    .eq(last_refill + self.refill_rate().into_sql::<Interval>() * tokens_to_add),
            ))
            .get_result(conn)
    }

    fn refill_rate(&self) -> PgInterval {
        use diesel::dsl::*;
        (self.rate.as_millis() as i64).milliseconds()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::email::Emails;
    use crate::test_util::*;

    #[test]
    fn take_token_with_no_bucket_creates_new_one() -> QueryResult<()> {
        let conn = pg_connection();
        let now = now();

        let rate = PublishRateLimit {
            rate: Duration::from_secs(1),
            burst: 10,
        };
        let bucket = rate.take_token(new_user(&conn, "user1")?, now, &conn)?;
        let expected = Bucket {
            user_id: bucket.user_id,
            tokens: 10,
            last_refill: now,
        };
        assert_eq!(expected, bucket);

        let rate = PublishRateLimit {
            rate: Duration::from_millis(50),
            burst: 20,
        };
        let bucket = rate.take_token(new_user(&conn, "user2")?, now, &conn)?;
        let expected = Bucket {
            user_id: bucket.user_id,
            tokens: 20,
            last_refill: now,
        };
        assert_eq!(expected, bucket);
        Ok(())
    }

    #[test]
    fn take_token_with_existing_bucket_modifies_existing_bucket() -> QueryResult<()> {
        let conn = pg_connection();
        let now = now();

        let rate = PublishRateLimit {
            rate: Duration::from_secs(1),
            burst: 10,
        };
        let user_id = new_user_bucket(&conn, 5, now)?.user_id;
        let bucket = rate.take_token(user_id, now, &conn)?;
        let expected = Bucket {
            user_id,
            tokens: 4,
            last_refill: now,
        };
        assert_eq!(expected, bucket);
        Ok(())
    }

    #[test]
    fn take_token_after_delay_refills() -> QueryResult<()> {
        let conn = pg_connection();
        let now = now();

        let rate = PublishRateLimit {
            rate: Duration::from_secs(1),
            burst: 10,
        };
        let user_id = new_user_bucket(&conn, 5, now)?.user_id;
        let refill_time = now + chrono::Duration::seconds(2);
        let bucket = rate.take_token(user_id, refill_time, &conn)?;
        let expected = Bucket {
            user_id,
            tokens: 6,
            last_refill: refill_time,
        };
        assert_eq!(expected, bucket);
        Ok(())
    }

    #[test]
    fn refill_subsecond_rate() -> QueryResult<()> {
        let conn = pg_connection();
        // Subsecond rates have floating point rounding issues, so use a known
        // timestamp that rounds fine
        let now =
            NaiveDateTime::parse_from_str("2019-03-19T21:11:24.620401", "%Y-%m-%dT%H:%M:%S%.f")
                .unwrap();

        let rate = PublishRateLimit {
            rate: Duration::from_millis(100),
            burst: 10,
        };
        let user_id = new_user_bucket(&conn, 5, now)?.user_id;
        let refill_time = now + chrono::Duration::milliseconds(300);
        let bucket = rate.take_token(user_id, refill_time, &conn)?;
        let expected = Bucket {
            user_id,
            tokens: 7,
            last_refill: refill_time,
        };
        assert_eq!(expected, bucket);
        Ok(())
    }

    #[test]
    fn last_refill_always_advanced_by_multiple_of_rate() -> QueryResult<()> {
        let conn = pg_connection();
        let now = now();

        let rate = PublishRateLimit {
            rate: Duration::from_millis(100),
            burst: 10,
        };
        let user_id = new_user_bucket(&conn, 5, now)?.user_id;
        let bucket = rate.take_token(user_id, now + chrono::Duration::milliseconds(250), &conn)?;
        let expected_refill_time = now + chrono::Duration::milliseconds(200);
        let expected = Bucket {
            user_id,
            tokens: 6,
            last_refill: expected_refill_time,
        };
        assert_eq!(expected, bucket);
        Ok(())
    }

    #[test]
    fn zero_tokens_returned_when_user_has_no_tokens_left() -> QueryResult<()> {
        let conn = pg_connection();
        let now = now();

        let rate = PublishRateLimit {
            rate: Duration::from_secs(1),
            burst: 10,
        };
        let user_id = new_user_bucket(&conn, 1, now)?.user_id;
        let bucket = rate.take_token(user_id, now, &conn)?;
        let expected = Bucket {
            user_id,
            tokens: 0,
            last_refill: now,
        };
        assert_eq!(expected, bucket);

        let bucket = rate.take_token(user_id, now, &conn)?;
        assert_eq!(expected, bucket);
        Ok(())
    }

    #[test]
    fn a_user_with_no_tokens_gets_a_token_after_exactly_rate() -> QueryResult<()> {
        let conn = pg_connection();
        let now = now();

        let rate = PublishRateLimit {
            rate: Duration::from_secs(1),
            burst: 10,
        };
        let user_id = new_user_bucket(&conn, 0, now)?.user_id;
        let refill_time = now + chrono::Duration::seconds(1);
        let bucket = rate.take_token(user_id, refill_time, &conn)?;
        let expected = Bucket {
            user_id,
            tokens: 1,
            last_refill: refill_time,
        };
        assert_eq!(expected, bucket);

        Ok(())
    }

    #[test]
    fn tokens_never_refill_past_burst() -> QueryResult<()> {
        let conn = pg_connection();
        let now = now();

        let rate = PublishRateLimit {
            rate: Duration::from_secs(1),
            burst: 10,
        };
        let user_id = new_user_bucket(&conn, 8, now)?.user_id;
        let refill_time = now + chrono::Duration::seconds(4);
        let bucket = rate.take_token(user_id, refill_time, &conn)?;
        let expected = Bucket {
            user_id,
            tokens: 10,
            last_refill: refill_time,
        };
        assert_eq!(expected, bucket);

        Ok(())
    }

    #[test]
    fn override_is_used_instead_of_global_burst_if_present() -> QueryResult<()> {
        let conn = pg_connection();
        let now = now();

        let rate = PublishRateLimit {
            rate: Duration::from_secs(1),
            burst: 10,
        };
        let user_id = new_user(&conn, "user1")?;
        let other_user_id = new_user(&conn, "user2")?;

        diesel::insert_into(publish_rate_overrides::table)
            .values((
                publish_rate_overrides::user_id.eq(user_id),
                publish_rate_overrides::burst.eq(20),
            ))
            .execute(&conn)?;

        let bucket = rate.take_token(user_id, now, &conn)?;
        let other_bucket = rate.take_token(other_user_id, now, &conn)?;

        assert_eq!(20, bucket.tokens);
        assert_eq!(10, other_bucket.tokens);
        Ok(())
    }

    fn new_user(conn: &PgConnection, gh_login: &str) -> QueryResult<i32> {
        use crate::models::NewUser;

        let user = NewUser {
            gh_login,
            ..NewUser::default()
        }
        .create_or_update(None, &Emails::new_in_memory(), conn)?;
        Ok(user.id)
    }

    fn new_user_bucket(
        conn: &PgConnection,
        tokens: i32,
        now: NaiveDateTime,
    ) -> QueryResult<Bucket> {
        diesel::insert_into(publish_limit_buckets::table)
            .values(Bucket {
                user_id: new_user(conn, "new_user")?,
                tokens,
                last_refill: now,
            })
            .get_result(conn)
    }

    /// Strips ns precision from `Utc::now`. PostgreSQL only has microsecond
    /// precision, but some platforms (notably Linux) provide nanosecond
    /// precision, meaning that round tripping through the database would
    /// change the value.
    fn now() -> NaiveDateTime {
        let now = Utc::now().naive_utc();
        let nanos = now.timestamp_subsec_nanos();
        now - chrono::Duration::nanoseconds(nanos.into())
    }
}
<commit_msg>More aggressively rate limit reserving new package names<commit_after>use chrono::{NaiveDateTime, Utc};
use diesel::data_types::PgInterval;
use diesel::prelude::*;
use std::time::Duration;

use crate::schema::{publish_limit_buckets, publish_rate_overrides};
use crate::util::errors::{AppResult, TooManyRequests};

#[derive(Debug, Clone, Copy)]
pub struct PublishRateLimit {
    pub rate: Duration,
    pub burst: i32,
}

impl Default for PublishRateLimit {
    fn default() -> Self {
        let minutes = dotenv::var("WEB_NEW_PKG_RATE_LIMIT_RATE_MINUTES")
            .unwrap_or_default()
            .parse()
            .ok()
            .unwrap_or(10);
        let burst = dotenv::var("WEB_NEW_PKG_RATE_LIMIT_BURST")
            .unwrap_or_default()
            .parse()
            .ok()
            .unwrap_or(5);
        Self {
            rate: Duration::from_secs(60) * minutes,
            burst,
        }
    }
}

#[derive(Queryable, Insertable, Debug, PartialEq, Clone, Copy)]
#[table_name = "publish_limit_buckets"]
#[allow(dead_code)] // Most fields only read in tests
struct Bucket {
    user_id: i32,
    tokens: i32,
    last_refill: NaiveDateTime,
}

impl PublishRateLimit {
    pub fn check_rate_limit(&self, uploader: i32, conn: &PgConnection) -> AppResult<()> {
        let bucket = self.take_token(uploader, Utc::now().naive_utc(), conn)?;
        if bucket.tokens >= 1 {
            Ok(())
        } else {
            Err(Box::new(TooManyRequests {
                retry_after: bucket.last_refill + chrono::Duration::from_std(self.rate).unwrap(),
            }))
        }
    }

    /// Refill a user's bucket as needed, take a token from it,
    /// and returns the result.
    ///
    /// The number of tokens remaining will always be between 0 and self.burst.
    /// If the number is 0, the request should be rejected, as the user doesn't
    /// have a token to take. Technically a "full" bucket would have
    /// `self.burst + 1` tokens in it, but that value would never be returned
    /// since we only refill buckets when trying to take a token from it.
    fn take_token(
        &self,
        uploader: i32,
        now: NaiveDateTime,
        conn: &PgConnection,
    ) -> QueryResult<Bucket> {
        use self::publish_limit_buckets::dsl::*;
        use diesel::sql_types::{Double, Interval, Text, Timestamp};

        sql_function!(fn date_part(x: Text, y: Timestamp) -> Double);
        sql_function! {
            #[sql_name = "date_part"]
            fn interval_part(x: Text, y: Interval) -> Double;
        }
        sql_function!(fn floor(x: Double) -> Integer);
        sql_function!(fn greatest<T>(x: T, y: T) -> T);
        sql_function!(fn least<T>(x: T, y: T) -> T);

        let burst: i32 = publish_rate_overrides::table
            .find(uploader)
            .select(publish_rate_overrides::burst)
            .first(conn)
            .optional()?
            .unwrap_or(self.burst);

        // Interval division is poorly defined in general (what is 1 month / 30 days?)
        // However, for the intervals we're dealing with, it is always well
        // defined, so we convert to an f64 of seconds to represent this.
        let tokens_to_add = floor(
            (date_part("epoch", now) - date_part("epoch", last_refill))
                / interval_part("epoch", self.refill_rate()),
        );

        diesel::insert_into(publish_limit_buckets)
            .values((user_id.eq(uploader), tokens.eq(burst), last_refill.eq(now)))
            .on_conflict(user_id)
            .do_update()
            .set((
                tokens.eq(least(burst, greatest(0, tokens - 1) + tokens_to_add)),
                last_refill
                    .eq(last_refill + self.refill_rate().into_sql::<Interval>() * tokens_to_add),
            ))
            .get_result(conn)
    }

    fn refill_rate(&self) -> PgInterval {
        use diesel::dsl::*;
        (self.rate.as_millis() as i64).milliseconds()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::email::Emails;
    use crate::test_util::*;

    #[test]
    fn take_token_with_no_bucket_creates_new_one() -> QueryResult<()> {
        let conn = pg_connection();
        let now = now();

        let rate = PublishRateLimit {
            rate: Duration::from_secs(1),
            burst: 10,
        };
        let bucket = rate.take_token(new_user(&conn, "user1")?, now, &conn)?;
        let expected = Bucket {
            user_id: bucket.user_id,
            tokens: 10,
            last_refill: now,
        };
        assert_eq!(expected, bucket);

        let rate = PublishRateLimit {
            rate: Duration::from_millis(50),
            burst: 20,
        };
        let bucket = rate.take_token(new_user(&conn, "user2")?, now, &conn)?;
        let expected = Bucket {
            user_id: bucket.user_id,
            tokens: 20,
            last_refill: now,
        };
        assert_eq!(expected, bucket);
        Ok(())
    }

    #[test]
    fn take_token_with_existing_bucket_modifies_existing_bucket() -> QueryResult<()> {
        let conn = pg_connection();
        let now = now();

        let rate = PublishRateLimit {
            rate: Duration::from_secs(1),
            burst: 10,
        };
        let user_id = new_user_bucket(&conn, 5, now)?.user_id;
        let bucket = rate.take_token(user_id, now, &conn)?;
        let expected = Bucket {
            user_id,
            tokens: 4,
            last_refill: now,
        };
        assert_eq!(expected, bucket);
        Ok(())
    }

    #[test]
    fn take_token_after_delay_refills() -> QueryResult<()> {
        let conn = pg_connection();
        let now = now();

        let rate = PublishRateLimit {
            rate: Duration::from_secs(1),
            burst: 10,
        };
        let user_id = new_user_bucket(&conn, 5, now)?.user_id;
        let refill_time = now + chrono::Duration::seconds(2);
        let bucket = rate.take_token(user_id, refill_time, &conn)?;
        let expected = Bucket {
            user_id,
            tokens: 6,
            last_refill: refill_time,
        };
        assert_eq!(expected, bucket);
        Ok(())
    }

    #[test]
    fn refill_subsecond_rate() -> QueryResult<()> {
        let conn = pg_connection();
        // Subsecond rates have floating point rounding issues, so use a known
        // timestamp that rounds fine
        let now =
            NaiveDateTime::parse_from_str("2019-03-19T21:11:24.620401", "%Y-%m-%dT%H:%M:%S%.f")
                .unwrap();

        let rate = PublishRateLimit {
            rate: Duration::from_millis(100),
            burst: 10,
        };
        let user_id = new_user_bucket(&conn, 5, now)?.user_id;
        let refill_time = now + chrono::Duration::milliseconds(300);
        let bucket = rate.take_token(user_id, refill_time, &conn)?;
        let expected = Bucket {
            user_id,
            tokens: 7,
            last_refill: refill_time,
        };
        assert_eq!(expected, bucket);
        Ok(())
    }

    #[test]
    fn last_refill_always_advanced_by_multiple_of_rate() -> QueryResult<()> {
        let conn = pg_connection();
        let now = now();

        let rate = PublishRateLimit {
            rate: Duration::from_millis(100),
            burst: 10,
        };
        let user_id = new_user_bucket(&conn, 5, now)?.user_id;
        let bucket = rate.take_token(user_id, now + chrono::Duration::milliseconds(250), &conn)?;
        let expected_refill_time = now + chrono::Duration::milliseconds(200);
        let expected = Bucket {
            user_id,
            tokens: 6,
            last_refill: expected_refill_time,
        };
        assert_eq!(expected, bucket);
        Ok(())
    }

    #[test]
    fn zero_tokens_returned_when_user_has_no_tokens_left() -> QueryResult<()> {
        let conn = pg_connection();
        let now = now();

        let rate = PublishRateLimit {
            rate: Duration::from_secs(1),
            burst: 10,
        };
        let user_id = new_user_bucket(&conn, 1, now)?.user_id;
        let bucket = rate.take_token(user_id, now, &conn)?;
        let expected = Bucket {
            user_id,
            tokens: 0,
            last_refill: now,
        };
        assert_eq!(expected, bucket);

        let bucket = rate.take_token(user_id, now, &conn)?;
        assert_eq!(expected, bucket);
        Ok(())
    }

    #[test]
    fn a_user_with_no_tokens_gets_a_token_after_exactly_rate() -> QueryResult<()> {
        let conn = pg_connection();
        let now = now();

        let rate = PublishRateLimit {
            rate: Duration::from_secs(1),
            burst: 10,
        };
        let user_id = new_user_bucket(&conn, 0, now)?.user_id;
        let refill_time = now + chrono::Duration::seconds(1);
        let bucket = rate.take_token(user_id, refill_time, &conn)?;
        let expected = Bucket {
            user_id,
            tokens: 1,
            last_refill: refill_time,
        };
        assert_eq!(expected, bucket);

        Ok(())
    }

    #[test]
    fn tokens_never_refill_past_burst() -> QueryResult<()> {
        let conn = pg_connection();
        let now = now();

        let rate = PublishRateLimit {
            rate: Duration::from_secs(1),
            burst: 10,
        };
        let user_id = new_user_bucket(&conn, 8, now)?.user_id;
        let refill_time = now + chrono::Duration::seconds(4);
        let bucket = rate.take_token(user_id, refill_time, &conn)?;
        let expected = Bucket {
            user_id,
            tokens: 10,
            last_refill: refill_time,
        };
        assert_eq!(expected, bucket);

        Ok(())
    }

    #[test]
    fn override_is_used_instead_of_global_burst_if_present() -> QueryResult<()> {
        let conn = pg_connection();
        let now = now();

        let rate = PublishRateLimit {
            rate: Duration::from_secs(1),
            burst: 10,
        };
        let user_id = new_user(&conn, "user1")?;
        let other_user_id = new_user(&conn, "user2")?;

        diesel::insert_into(publish_rate_overrides::table)
            .values((
                publish_rate_overrides::user_id.eq(user_id),
                publish_rate_overrides::burst.eq(20),
            ))
            .execute(&conn)?;

        let bucket = rate.take_token(user_id, now, &conn)?;
        let other_bucket = rate.take_token(other_user_id, now, &conn)?;

        assert_eq!(20, bucket.tokens);
        assert_eq!(10, other_bucket.tokens);
        Ok(())
    }

    fn new_user(conn: &PgConnection, gh_login: &str) -> QueryResult<i32> {
        use crate::models::NewUser;

        let user = NewUser {
            gh_login,
            ..NewUser::default()
        }
        .create_or_update(None, &Emails::new_in_memory(), conn)?;
        Ok(user.id)
    }

    fn new_user_bucket(
        conn: &PgConnection,
        tokens: i32,
        now: NaiveDateTime,
    ) -> QueryResult<Bucket> {
        diesel::insert_into(publish_limit_buckets::table)
            .values(Bucket {
                user_id: new_user(conn, "new_user")?,
                tokens,
                last_refill: now,
            })
            .get_result(conn)
    }

    /// Strips ns precision from `Utc::now`. PostgreSQL only has microsecond
    /// precision, but some platforms (notably Linux) provide nanosecond
    /// precision, meaning that round tripping through the database would
    /// change the value.
    fn now() -> NaiveDateTime {
        let now = Utc::now().naive_utc();
        let nanos = now.timestamp_subsec_nanos();
        now - chrono::Duration::nanoseconds(nanos.into())
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate orbtk;

use orbtk::{Action, Button, Menu, Placeable, Point, Rect, TextBox, Window};
use orbtk::callback::Click;

use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::sync::Arc;

fn main(){
    let path_option = Arc::new(env::args().nth(1));

    let title = if let Some(ref path) = *path_option {
        format!("{} - Editor", path)
    } else {
        format!("Editor")
    };

    let window = Arc::new(Window::new(Rect::new(100, 100, 576, 420), &title));

    let text_box = TextBox::new()
        .position(0, 16)
        .size(576, 404)
        .place(&window);

    if let Some(ref path) = *path_option {
        match File::open(path) {
            Ok(mut file) => {
                let mut text = String::new();
                match file.read_to_string(&mut text) {
                    Ok(_) => text_box.text.set(text),
                    Err(err) => println!("Failed to read {}: {}", path, err)
                }
            },
            Err(err) => println!("Failed to open {}: {}", path, err)
        }
    }

    let mut menu = Menu::new("File").position(0, 0).size(32, 16);

    menu.add_action(Action::new("Open").on_click(|_action: &Action, _point: Point| {
        println!("Open");
    }));

    menu.add_separator();

    let save_path_option = path_option.clone();
    menu.add_action(Action::new("Save").on_click(move |_action: &Action, _point: Point| {
        println!("Save");
        if let Some(ref path) = *save_path_option {
            match File::create(path) {
                Ok(mut file) => {
                    let text = text_box.text.get();
                    match file.write(&mut text.as_bytes()) {
                        Ok(_) => match file.set_len(text.len() as u64) {
                            Ok(_) => println!("Successfully saved {}", path),
                            Err(err) => println!("Failed to truncate {}: {}", path, err)
                        },
                        Err(err) => println!("Failed to write {}: {}", path, err)
                    }
                },
                Err(err) => println!("Failed to open {}: {}", path, err)
            }
        } else {
            println!("Need to create file!");
        }
    }));

    let save_as_path_option = path_option.clone();
    menu.add_action(Action::new("Save As").on_click(move |_action: &Action, _point: Point| {
        println!("Save As");
        let window = Arc::new(Window::new(Rect::new(100, 100, 576, 32), "Save As"));

        let text_box = TextBox::new()
            .position(0, 0)
            .size(576, 16)
            .place(&window);

        if let Some(ref path) = *save_as_path_option {
            text_box.text.set(path.clone());
        }

        let window_cancel = window.clone();
        Button::new()
            .position(0, 16)
            .size(576/2, 16)
            .text("Cancel")
            .on_click(move |_button: &Button, _point: Point| {
                window_cancel.close();
            })
            .place(&window);

        let window_save_as = window.clone();
        Button::new()
            .position(576/2, 16)
            .size(576/2, 16)
            .text("Save As")
            .on_click(move |_button: &Button, _point: Point| {
                println!("Save {}", text_box.text.get());
                window_save_as.close();
            })
            .place(&window);

        window.exec();
    }));

    menu.add_separator();

    let window_close = window.clone();
    menu.add_action(Action::new("Close").on_click(move |_action: &Action, _point: Point| {
        println!("Close");
        window_close.close();
    }));

    menu.place(&window);

    window.exec();
}
<commit_msg>Fix compile on newest Rust<commit_after>#![deny(warnings)]

extern crate orbtk;

use orbtk::{Action, Button, Menu, Placeable, Point, Rect, TextBox, Window};
use orbtk::callback::Click;

use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::sync::Arc;

fn main(){
    let path_option = env::args().nth(1);

    let title = if let Some(ref path) = path_option {
        format!("{} - Editor", path)
    } else {
        format!("Editor")
    };

    let window = Arc::new(Window::new(Rect::new(100, 100, 576, 420), &title));

    let text_box = TextBox::new()
        .position(0, 16)
        .size(576, 404)
        .place(&window);

    if let Some(ref path) = path_option {
        match File::open(path) {
            Ok(mut file) => {
                let mut text = String::new();
                match file.read_to_string(&mut text) {
                    Ok(_) => text_box.text.set(text),
                    Err(err) => println!("Failed to read {}: {}", path, err)
                }
            },
            Err(err) => println!("Failed to open {}: {}", path, err)
        }
    }

    let mut menu = Menu::new("File").position(0, 0).size(32, 16);

    menu.add_action(Action::new("Open").on_click(|_action: &Action, _point: Point| {
        println!("Open");
    }));

    menu.add_separator();

    let save_path_option = path_option.clone();
    let save_text_box = text_box.clone();
    menu.add_action(Action::new("Save").on_click(move |_action: &Action, _point: Point| {
        println!("Save");
        if let Some(ref path) = save_path_option {
            println!("Create {}", path);
            match File::create(path) {
                Ok(mut file) => {
                    let text = save_text_box.text.borrow();
                    match file.write(&text.as_bytes()) {
                        Ok(_) => match file.set_len(text.len() as u64) {
                            Ok(_) => println!("Successfully saved {}", path),
                            Err(err) => println!("Failed to truncate {}: {}", path, err)
                        },
                        Err(err) => println!("Failed to write {}: {}", path, err)
                    }
                },
                Err(err) => println!("Failed to open {}: {}", path, err)
            }
        } else {
            println!("Need to create file!");
        }
    }));

    let save_as_path_option = path_option.clone();
    menu.add_action(Action::new("Save As").on_click(move |_action: &Action, _point: Point| {
        println!("Save As");
        let window = Arc::new(Window::new(Rect::new(100, 100, 576, 32), "Save As"));

        let text_box = TextBox::new()
            .position(0, 0)
            .size(576, 16)
            .place(&window);

        if let Some(ref path) = save_as_path_option {
            text_box.text.set(path.clone());
        }

        let window_cancel = window.clone();
        Button::new()
            .position(0, 16)
            .size(576/2, 16)
            .text("Cancel")
            .on_click(move |_button: &Button, _point: Point| {
                window_cancel.close();
            })
            .place(&window);

        let window_save_as = window.clone();
        Button::new()
            .position(576/2, 16)
            .size(576/2, 16)
            .text("Save As")
            .on_click(move |_button: &Button, _point: Point| {
                println!("Save {}", text_box.text.get());
                window_save_as.close();
            })
            .place(&window);

        window.exec();
    }));

    menu.add_separator();

    let window_close = window.clone();
    menu.add_action(Action::new("Close").on_click(move |_action: &Action, _point: Point| {
        println!("Close");
        window_close.close();
    }));

    menu.place(&window);

    window.exec();
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2014 J.C. Moyer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// corresponds to luaconf.h
pub use super::glue::LUAL_BUFFERSIZE;
pub use super::glue::LUA_NUMBER;
pub use super::glue::LUA_INTEGER;
pub use super::glue::LUA_UNSIGNED;

pub use super::glue::{LUA_IDSIZE};
pub use super::glue::{LUA_MININTEGER, LUA_MAXINTEGER};

pub use super::glue::LUAI_MAXSTACK;
pub use super::glue::LUAL_NUMSIZES;
pub use super::glue::LUAI_FIRSTPSEUDOIDX;

pub use super::glue::LUA_CTXT;

<commit_msg>Add lua_numtointeger<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2014 J.C. Moyer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// corresponds to luaconf.h
pub use super::glue::LUAL_BUFFERSIZE;
pub use super::glue::LUA_NUMBER;
pub use super::glue::LUA_INTEGER;
pub use super::glue::LUA_UNSIGNED;

pub use super::glue::{LUA_IDSIZE};
pub use super::glue::{LUA_MININTEGER, LUA_MAXINTEGER};

pub use super::glue::LUAI_MAXSTACK;
pub use super::glue::LUAL_NUMSIZES;
pub use super::glue::LUAI_FIRSTPSEUDOIDX;

pub use super::glue::LUA_CTXT;

use super::lua::{lua_Number, lua_Integer};
use libc::c_int;

#[inline(always)]
pub unsafe fn lua_numtointeger(n: lua_Number, p: *mut lua_Integer) -> c_int {
  if n >= (LUA_MININTEGER as LUA_NUMBER) && n < -(LUA_MININTEGER as LUA_NUMBER) {
    *p = n as LUA_INTEGER;
    1
  } else {
    0
  }
}

<|endoftext|>


<commit_before>use std::cmp::Ordering;
use super::eq;
use super::mat::Mat;
use super::bonus::compute_bonus;
use super::consts::*;

#[derive(Copy, Clone, Debug)]
pub struct Score {
    /// The computed score value
    pub value: f32
}

impl Score {
    /// Creates a new Score with the provided value
    ///
    /// # Examples
    ///
    /// ```
    /// let score = rff::fuzzy::Score::new(1.0);
    /// assert_eq!(score.value, 1.0);
    /// ```
    pub fn new(value: f32) -> Score {
        Score {
            value: value
        }
    }

    /// Creates a new Score, with value derived from provided needle / haystack
    pub fn calculate(needle: &str, haystack: &str) -> Score {
        let len_n = needle.len();
        let len_h = haystack.len();

        if len_n == 0 {
            return Score::new(SCORE_MIN);
        }

        if len_n == len_h {
            return Score::new(SCORE_MAX);
        }

        let bonus = compute_bonus(haystack);

        let mut d = Mat::new(len_n, len_h);
        let mut m = Mat::new(len_n, len_h);

        for (i, n) in needle.chars().enumerate() {
            let mut prev_score = SCORE_MIN;
            let gap_score = if i == len_n - 1 { SCORE_GAP_TRAILING } else { SCORE_GAP_INNER };

            for (j, h) in haystack.chars().enumerate() {
                if eq(n, h) {
                    let mut score = SCORE_MIN;

                    let bonus_score = bonus[j];

                    if i == 0 {
                        score = ((j as f32) * SCORE_GAP_LEADING) + bonus_score;
                    } else if j > 0 {
                        let m = m.get(i - 1, j - 1).unwrap();
                        let d = d.get(i - 1, j - 1).unwrap();

                        score = (m + bonus_score).max(d + SCORE_MATCH_CONSECUTIVE);
                    }

                    prev_score = score.max(prev_score + gap_score);

                    d.set(i, j, score).unwrap();
                    m.set(i, j, prev_score).unwrap();
                } else {
                    d.set(i, j, SCORE_MIN).unwrap();
                    m.set(i, j, prev_score + gap_score).unwrap();
                    prev_score += gap_score;
                }
            }
        }

        let score = m.get(len_n - 1, len_h - 1).unwrap_or(SCORE_MIN);
        Score::new(score)
    }
}

impl PartialOrd for Score {
    fn partial_cmp(&self, other: &Score) -> Option<Ordering> {
        self.value.partial_cmp(&other.value)
    }
}

impl PartialEq for Score {
    fn eq(&self, other: &Score) -> bool {
        self.value == other.value
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;

    fn score(needle: &str, haystack: &str) -> Score {
        Score::calculate(needle, haystack)
    }

    #[test]
    fn test_eq() {
        let a = Score::new(1.0);
        let b = Score::new(1.0);
        assert_eq!(a, b);
    }

    #[test]
    fn test_cmp() {
        let a = Score::new(2.0);
        let b = Score::new(1.0);
        assert!(a > b);
        assert!(b < a);

        let b = Score::new(2.0);
        assert!(a == b);
    }

    #[test]
    fn relative_scores() {
        // App/Models/Order is better than App/MOdels/zRder
        assert!(score("amor", "app/models/order") > score("amor", "app/models/zrder"));

        // App/MOdels/foo is better than App/M/fOo
        assert!(score("amo", "app/m/foo") < score("amo", "app/models/foo"));

        // GEMFIle.Lock < GEMFILe
        assert!(score("gemfil", "Gemfile.lock") < score("gemfil", "Gemfile"));

        // GEMFIle.Lock < GEMFILe
        assert!(score("gemfil", "Gemfile.lock") < score("gemfil", "Gemfile"));

        // Prefer shorter scorees
        assert!(score("abce", "abcdef") > score("abce", "abc de"));

        // Prefer shorter candidates
        assert!(score("test", "tests") > score("test", "testing"));

        // Scores first letter highly
        assert!(score("test", "testing") > score("test", "/testing"));

        // Prefer shorter scorees
        assert!(score("abc", "    a b c ") > score("abc", " a  b  c "));
        assert!(score("abc", " a b c    ") > score("abc", " a  b  c "));
    }

    #[bench]
    fn bench_score(b: &mut Bencher) {
        b.iter(|| Score::calculate("amor", "app/models/order.rb"))
    }

    #[bench]
    fn bench_score_multiple(b: &mut Bencher) {
        b.iter(|| {
            Score::calculate("amor", "app/models/order.rb");
            Score::calculate("amor", "spec/models/order_spec.rb");
            Score::calculate("amor", "other_garbage.rb");
            Score::calculate("amor", "Gemfile");
            Score::calculate("amor", "node_modules/test/a/thing.js");
            Score::calculate("amor", "vendor/bundle/ruby/gem.rb")
        })
    }

}
<commit_msg>Add copyright notice for ported algorithm<commit_after>// A port of selecta's scoring algorithm parsing.
// selecta (c) 2014 John Hawthorn
// Licensed under the MIT license

use std::cmp::Ordering;
use super::eq;
use super::mat::Mat;
use super::bonus::compute_bonus;
use super::consts::*;

#[derive(Copy, Clone, Debug)]
pub struct Score {
    /// The computed score value
    pub value: f32
}

impl Score {
    /// Creates a new Score with the provided value
    ///
    /// # Examples
    ///
    /// ```
    /// let score = rff::fuzzy::Score::new(1.0);
    /// assert_eq!(score.value, 1.0);
    /// ```
    pub fn new(value: f32) -> Score {
        Score {
            value: value
        }
    }

    /// Creates a new Score, with value derived from provided needle / haystack
    pub fn calculate(needle: &str, haystack: &str) -> Score {
        let len_n = needle.len();
        let len_h = haystack.len();

        if len_n == 0 {
            return Score::new(SCORE_MIN);
        }

        if len_n == len_h {
            return Score::new(SCORE_MAX);
        }

        let bonus = compute_bonus(haystack);

        let mut d = Mat::new(len_n, len_h);
        let mut m = Mat::new(len_n, len_h);

        for (i, n) in needle.chars().enumerate() {
            let mut prev_score = SCORE_MIN;
            let gap_score = if i == len_n - 1 { SCORE_GAP_TRAILING } else { SCORE_GAP_INNER };

            for (j, h) in haystack.chars().enumerate() {
                if eq(n, h) {
                    let mut score = SCORE_MIN;

                    let bonus_score = bonus[j];

                    if i == 0 {
                        score = ((j as f32) * SCORE_GAP_LEADING) + bonus_score;
                    } else if j > 0 {
                        let m = m.get(i - 1, j - 1).unwrap();
                        let d = d.get(i - 1, j - 1).unwrap();

                        score = (m + bonus_score).max(d + SCORE_MATCH_CONSECUTIVE);
                    }

                    prev_score = score.max(prev_score + gap_score);

                    d.set(i, j, score).unwrap();
                    m.set(i, j, prev_score).unwrap();
                } else {
                    d.set(i, j, SCORE_MIN).unwrap();
                    m.set(i, j, prev_score + gap_score).unwrap();
                    prev_score += gap_score;
                }
            }
        }

        let score = m.get(len_n - 1, len_h - 1).unwrap_or(SCORE_MIN);
        Score::new(score)
    }
}

impl PartialOrd for Score {
    fn partial_cmp(&self, other: &Score) -> Option<Ordering> {
        self.value.partial_cmp(&other.value)
    }
}

impl PartialEq for Score {
    fn eq(&self, other: &Score) -> bool {
        self.value == other.value
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;

    fn score(needle: &str, haystack: &str) -> Score {
        Score::calculate(needle, haystack)
    }

    #[test]
    fn test_eq() {
        let a = Score::new(1.0);
        let b = Score::new(1.0);
        assert_eq!(a, b);
    }

    #[test]
    fn test_cmp() {
        let a = Score::new(2.0);
        let b = Score::new(1.0);
        assert!(a > b);
        assert!(b < a);

        let b = Score::new(2.0);
        assert!(a == b);
    }

    #[test]
    fn relative_scores() {
        // App/Models/Order is better than App/MOdels/zRder
        assert!(score("amor", "app/models/order") > score("amor", "app/models/zrder"));

        // App/MOdels/foo is better than App/M/fOo
        assert!(score("amo", "app/m/foo") < score("amo", "app/models/foo"));

        // GEMFIle.Lock < GEMFILe
        assert!(score("gemfil", "Gemfile.lock") < score("gemfil", "Gemfile"));

        // GEMFIle.Lock < GEMFILe
        assert!(score("gemfil", "Gemfile.lock") < score("gemfil", "Gemfile"));

        // Prefer shorter scorees
        assert!(score("abce", "abcdef") > score("abce", "abc de"));

        // Prefer shorter candidates
        assert!(score("test", "tests") > score("test", "testing"));

        // Scores first letter highly
        assert!(score("test", "testing") > score("test", "/testing"));

        // Prefer shorter scorees
        assert!(score("abc", "    a b c ") > score("abc", " a  b  c "));
        assert!(score("abc", " a b c    ") > score("abc", " a  b  c "));
    }

    #[bench]
    fn bench_score(b: &mut Bencher) {
        b.iter(|| Score::calculate("amor", "app/models/order.rb"))
    }

    #[bench]
    fn bench_score_multiple(b: &mut Bencher) {
        b.iter(|| {
            Score::calculate("amor", "app/models/order.rb");
            Score::calculate("amor", "spec/models/order_spec.rb");
            Score::calculate("amor", "other_garbage.rb");
            Score::calculate("amor", "Gemfile");
            Score::calculate("amor", "node_modules/test/a/thing.js");
            Score::calculate("amor", "vendor/bundle/ruby/gem.rb")
        })
    }

}
<|endoftext|>


<commit_before>// Rust JSON-RPC Library
// Written in 2014 by
//   Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # JSON RPC-Server Support
//!

use http::server;
use http::headers::content_type::MediaType;

use std::io::net::ip::{SocketAddr, Ipv4Addr};

use serialize::json;
use time;

use error::{Error, result_to_response};
use {Request, json_decode_field, json_decode_field_list, json_decode_field_string};

/// A Server which reacts to JSONRPC requests by passing the request,
/// along with a response channel, across a channel.
#[deriving(Clone)]
pub struct JsonRpcServer {
  req_tx: Sender<(Request, Sender<Result<json::Json, Error>>)>,
}

impl JsonRpcServer {
  /// Constructor: returns a new `JsonRpcServer` along with a `Receiver`
  /// which should be listened on for new requests from peers
  pub fn new() -> (JsonRpcServer, Receiver<(Request, Sender<Result<json::Json, Error>>)>) {
    let (tx, rx) = channel();
    (JsonRpcServer { req_tx: tx }, rx)
  }
}

impl server::Server for JsonRpcServer {
  fn get_config (&self) -> server::Config {
    server::Config { bind_address: SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 8001 } }
  }

  fn handle_request (&self, r: server::Request, w: &mut server::ResponseWriter) {
    w.headers.date = Some (time::now_utc());
    w.headers.content_type = Some (MediaType {
      type_: "application".to_string(),
      subtype: "json".to_string(),
      parameters: vec![("charset".to_string(), "UTF-8".to_string())]
    });
    w.headers.server = Some("rust-bitcoin-rpc".to_string());

    // Decode the request
    let js = json::from_str(r.body.as_slice());
    if js.is_err() { return; }
    let js = js.unwrap();
    let id = json_decode_field(&js, "id");
    let method = json_decode_field_string(&js, "method");
    let params = json_decode_field_list(&js, "params");

    // If it was a valid request, pass it to the main thread to get a response
    let response = if id.is_ok() && method.is_ok() && params.is_ok() {
      let (resp_tx, resp_rx) = channel();
      let request = Request {
        id: id.clone().unwrap(),
        method: method.unwrap(),
        params: params.unwrap()
      };
      // Request response from main thread
      self.req_tx.send((request, resp_tx));
      result_to_response(resp_rx.recv(), id.unwrap())
    // Otherwise use the error as a response
    } else if id.is_err() {
      result_to_response(id, json::Null)
    } else if method.is_err() {
      result_to_response(method.map(|meth| json::String(meth)), id.unwrap())
    } else if params.is_err() {
      result_to_response(params.map(|parms| json::List(parms)), id.unwrap())
    // Romy says, `else` as code for `else if [last thing i can think of]` is a
    // subtle bug waiting to happen. So actually use `else if` and add an unreachable
    // clause to satisfy the code-path checker
    } else {
      unreachable!()
    };

    // Pass the response to the peer
    let reply_str = json::encode(&response);
    let reply_bytes = reply_str.as_bytes();
println!("returning <<<< {} >>>>", reply_str);

    w.headers.content_length = Some(reply_bytes.len());
    if w.write(reply_bytes).is_err() {
      return;
    }
  }
}

<commit_msg>Remove stray trace code<commit_after>// Rust JSON-RPC Library
// Written in 2014 by
//   Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # JSON RPC-Server Support
//!

use http::server;
use http::headers::content_type::MediaType;

use std::io::net::ip::{SocketAddr, Ipv4Addr};

use serialize::json;
use time;

use error::{Error, result_to_response};
use {Request, json_decode_field, json_decode_field_list, json_decode_field_string};

/// A Server which reacts to JSONRPC requests by passing the request,
/// along with a response channel, across a channel.
#[deriving(Clone)]
pub struct JsonRpcServer {
  req_tx: Sender<(Request, Sender<Result<json::Json, Error>>)>,
}

impl JsonRpcServer {
  /// Constructor: returns a new `JsonRpcServer` along with a `Receiver`
  /// which should be listened on for new requests from peers
  pub fn new() -> (JsonRpcServer, Receiver<(Request, Sender<Result<json::Json, Error>>)>) {
    let (tx, rx) = channel();
    (JsonRpcServer { req_tx: tx }, rx)
  }
}

impl server::Server for JsonRpcServer {
  fn get_config (&self) -> server::Config {
    server::Config { bind_address: SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 8001 } }
  }

  fn handle_request (&self, r: server::Request, w: &mut server::ResponseWriter) {
    w.headers.date = Some (time::now_utc());
    w.headers.content_type = Some (MediaType {
      type_: "application".to_string(),
      subtype: "json".to_string(),
      parameters: vec![("charset".to_string(), "UTF-8".to_string())]
    });
    w.headers.server = Some("rust-bitcoin-rpc".to_string());

    // Decode the request
    let js = json::from_str(r.body.as_slice());
    if js.is_err() { return; }
    let js = js.unwrap();
    let id = json_decode_field(&js, "id");
    let method = json_decode_field_string(&js, "method");
    let params = json_decode_field_list(&js, "params");

    // If it was a valid request, pass it to the main thread to get a response
    let response = if id.is_ok() && method.is_ok() && params.is_ok() {
      let (resp_tx, resp_rx) = channel();
      let request = Request {
        id: id.clone().unwrap(),
        method: method.unwrap(),
        params: params.unwrap()
      };
      // Request response from main thread
      self.req_tx.send((request, resp_tx));
      result_to_response(resp_rx.recv(), id.unwrap())
    // Otherwise use the error as a response
    } else if id.is_err() {
      result_to_response(id, json::Null)
    } else if method.is_err() {
      result_to_response(method.map(|meth| json::String(meth)), id.unwrap())
    } else if params.is_err() {
      result_to_response(params.map(|parms| json::List(parms)), id.unwrap())
    // Romy says, `else` as code for `else if [last thing i can think of]` is a
    // subtle bug waiting to happen. So actually use `else if` and add an unreachable
    // clause to satisfy the code-path checker
    } else {
      unreachable!()
    };

    // Pass the response to the peer
    let reply_str = json::encode(&response);
    let reply_bytes = reply_str.as_bytes();

    w.headers.content_length = Some(reply_bytes.len());
    if w.write(reply_bytes).is_err() {
      return;
    }
  }
}

<|endoftext|>


<commit_before>use std;
use std::thread;
use std::thread::JoinHandle;
use std::time::Duration;
use rand;

use websocket::{WebSocketStream, Server};
use websocket::Message as WebMessage;
use websocket::Sender as WebSender;
use websocket::client::Sender as WebClientSender;
use websocket::Receiver as WebReceiver;
use websocket::message::Type as WebMessageType;
use websocket::server::Connection;
use websocket::header::WebSocketProtocol;

use payload;
use state::State;

extern crate fsevent;
use self::fsevent::ITEM_MODIFIED;
use self::fsevent::Event as FsEvent;
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;

use serde_xml as xml;

#[derive(Debug)]
enum NotifierMessage<'a> {
    WebMessage(WebMessage<'a>),
    FsEvent(FsEvent)
}

pub fn start(port: Option<i32>) -> Result<Server<'static>, std::io::Error> {
    let port = port.unwrap_or(2794);
    let host = format!("127.0.0.1:{}", port);
    Server::bind(host)
}

pub fn connect(connection: Connection<WebSocketStream, WebSocketStream>) {
    let request = connection.read_request().unwrap();
    let headers = request.headers.clone();
    request.validate().unwrap();

    let mut response = request.accept();
    println!("Connected");

    if let Some(&WebSocketProtocol(ref protocols)) = headers.get() {
        if protocols.contains(&("superconductor".to_string())) {
            response.headers.set(WebSocketProtocol(vec!["superconductor".to_string()]));
        }
    }

    let mut client = response.send().unwrap();
    let message = WebMessage::text(payload::generate(None));
    client.send_message(&message).unwrap();

    let (tx, rx) = channel::<NotifierMessage>();
    let (mut sender, mut receiver) = client.split();
    let notifier = thread::spawn(move || start_notifier(rx, sender));
    let txc = tx.clone();
    let monitor = thread::spawn(move || start_monitor(txc));
    for message in receiver.incoming_messages() {
        let message: WebMessage = message.unwrap_or(WebMessage::close());
        match message.opcode {
            WebMessageType::Close => {
                tx.send(NotifierMessage::WebMessage(message));
                break;
            },
            _ => tx.send(NotifierMessage::WebMessage(message))
        };
    }
    monitor.join();
    notifier.join();
}

fn start_monitor(tx: Sender<NotifierMessage>) {
    let (ftx, rx) = channel();
    let observer = thread::spawn(move || {
        println!("Monitoring");
        let fsevent = fsevent::FsEvent::new(ftx);
        fsevent.append_path(".");
        fsevent.observe();
    });
    loop {
        let event = rx.recv().unwrap();
        thread::sleep(Duration::from_millis(500));
        let mut changes = vec![];
        loop {
            if let Ok(event) = rx.try_recv() {
                if event.flag.contains(ITEM_MODIFIED) && (!event.path.contains(".git") || !event.path.contains(".lock")) {
                    println!("Registered {:?}", event);
                    changes.push(event);
                } else {
                    println!("Ignored {:?}", event);
                }
            } else {
                break;
            }
        }
        if !changes.is_empty() {
            tx.send(NotifierMessage::FsEvent(changes.pop().unwrap()));
        }
    }
    observer.join();
}

fn start_notifier(rx: Receiver<NotifierMessage>, mut sender: WebClientSender<WebSocketStream>) {
    let mut last_state: Option<State> = None;
    let mut rng = rand::thread_rng();
    loop {
        let event = rx.recv().unwrap();
        match event {
            NotifierMessage::WebMessage(message) => {
                match message.opcode {
                    WebMessageType::Close => {
                        break;
                    },
                    WebMessageType::Ping => {
                        let message = WebMessage::pong(message.payload);
                        sender.send_message(&message).unwrap();
                    },
                    _ => {
                        let payload = String::from_utf8_lossy(message.payload.as_ref());
                        let mut state: State = xml::from_str(&payload).unwrap();

                        last_state = state.apply(last_state, &mut rng).ok();

                        let message = WebMessage::text(payload::generate(Some(state)));
                        sender.send_message(&message).unwrap();
                    }
                }
            },
            NotifierMessage::FsEvent(event) => {
                let message = WebMessage::text(payload::generate(last_state.clone()));
                sender.send_message(&message).unwrap();
            }
        }
    }
}
<commit_msg>Should also listen for created events. --- master:    Description: ""   Developer: Jaden Carver   Estimate: ""   Status: Sprint<commit_after>use std;
use std::thread;
use std::thread::JoinHandle;
use std::time::Duration;
use rand;

use websocket::{WebSocketStream, Server};
use websocket::Message as WebMessage;
use websocket::Sender as WebSender;
use websocket::client::Sender as WebClientSender;
use websocket::Receiver as WebReceiver;
use websocket::message::Type as WebMessageType;
use websocket::server::Connection;
use websocket::header::WebSocketProtocol;

use payload;
use state::State;

extern crate fsevent;
use self::fsevent::{ITEM_MODIFIED, ITEM_CREATED};
use self::fsevent::Event as FsEvent;
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;

use serde_xml as xml;

#[derive(Debug)]
enum NotifierMessage<'a> {
    WebMessage(WebMessage<'a>),
    FsEvent(FsEvent)
}

pub fn start(port: Option<i32>) -> Result<Server<'static>, std::io::Error> {
    let port = port.unwrap_or(2794);
    let host = format!("127.0.0.1:{}", port);
    Server::bind(host)
}

pub fn connect(connection: Connection<WebSocketStream, WebSocketStream>) {
    let request = connection.read_request().unwrap();
    let headers = request.headers.clone();
    request.validate().unwrap();

    let mut response = request.accept();
    println!("Connected");

    if let Some(&WebSocketProtocol(ref protocols)) = headers.get() {
        if protocols.contains(&("superconductor".to_string())) {
            response.headers.set(WebSocketProtocol(vec!["superconductor".to_string()]));
        }
    }

    let mut client = response.send().unwrap();
    let message = WebMessage::text(payload::generate(None));
    client.send_message(&message).unwrap();

    let (tx, rx) = channel::<NotifierMessage>();
    let (mut sender, mut receiver) = client.split();
    let notifier = thread::spawn(move || start_notifier(rx, sender));
    let txc = tx.clone();
    let monitor = thread::spawn(move || start_monitor(txc));
    for message in receiver.incoming_messages() {
        let message: WebMessage = message.unwrap_or(WebMessage::close());
        match message.opcode {
            WebMessageType::Close => {
                tx.send(NotifierMessage::WebMessage(message));
                break;
            },
            _ => tx.send(NotifierMessage::WebMessage(message))
        };
    }
    monitor.join();
    notifier.join();
}

fn start_monitor(tx: Sender<NotifierMessage>) {
    let (ftx, rx) = channel();
    let observer = thread::spawn(move || {
        println!("Monitoring");
        let fsevent = fsevent::FsEvent::new(ftx);
        fsevent.append_path(".");
        fsevent.observe();
    });
    loop {
        let event = rx.recv().unwrap();
        thread::sleep(Duration::from_millis(500));
        let mut changes = vec![];
        loop {
            if let Ok(event) = rx.try_recv() {
                if (event.flag.contains(ITEM_MODIFIED) || event.flag.contains(ITEM_CREATED)) && (!event.path.contains(".git") || !event.path.contains(".lock")) {
                    println!("Registered {:?}", event);
                    changes.push(event);
                } else {
                    println!("Ignored {:?}", event);
                }
            } else {
                break;
            }
        }
        if !changes.is_empty() {
            tx.send(NotifierMessage::FsEvent(changes.pop().unwrap()));
        }
    }
    observer.join();
}

fn start_notifier(rx: Receiver<NotifierMessage>, mut sender: WebClientSender<WebSocketStream>) {
    let mut last_state: Option<State> = None;
    let mut rng = rand::thread_rng();
    loop {
        let event = rx.recv().unwrap();
        match event {
            NotifierMessage::WebMessage(message) => {
                match message.opcode {
                    WebMessageType::Close => {
                        break;
                    },
                    WebMessageType::Ping => {
                        let message = WebMessage::pong(message.payload);
                        sender.send_message(&message).unwrap();
                    },
                    _ => {
                        let payload = String::from_utf8_lossy(message.payload.as_ref());
                        let mut state: State = xml::from_str(&payload).unwrap();

                        last_state = state.apply(last_state, &mut rng).ok();

                        let message = WebMessage::text(payload::generate(Some(state)));
                        sender.send_message(&message).unwrap();
                    }
                }
            },
            NotifierMessage::FsEvent(event) => {
                let message = WebMessage::text(payload::generate(last_state.clone()));
                sender.send_message(&message).unwrap();
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::str;
use std::io::Read;
use std::fs::File;
use std::path::Path;
use std::sync::Arc;
use std::clone::Clone;

use hyper::status::StatusCode;
use hyper::server::{Handler, Server, Request, Response};
use mime_types::Types as MimeTypes;

pub use typemap::Key;
pub use hyper::header::Headers;
pub use hyper::header;
pub use hyper::mime;
pub use request::SapperRequest;
pub use response::SapperResponse;
pub use router_m::Router;
pub use router::SapperRouter;
pub use handler::SapperHandler;

#[derive(Clone)]
pub struct PathParams;

/// Status Codes
pub mod status {
    pub use hyper::status::StatusCode as Status;
    pub use hyper::status::StatusCode::*;
}

#[derive(Debug, PartialEq, Clone)]
pub enum Error {
    InvalidConfig,
    InvalidRouterConfig,
    FileNotExist,
    NotFound,
    Break,          // 400
    Unauthorized,   // 401
    Forbidden,      // 403
    TemporaryRedirect(String),     // 307
    Custom(String),
    CustomHtml(String),
    CustomJson(String),
}

pub type Result<T> = ::std::result::Result<T, Error>;

pub trait SapperModule: Sync + Send {
    fn before(&self, req: &mut SapperRequest) -> Result<()> {
        Ok(())
    }

    fn after(&self, req: &SapperRequest, res: &mut SapperResponse) -> Result<()> {
        Ok(())
    }

    fn router(&self, &mut SapperRouter) -> Result<()>;

}

pub trait SapperAppShell {
    fn before(&self, &mut SapperRequest) -> Result<()>;
    fn after(&self, &SapperRequest, &mut SapperResponse) -> Result<()>;
}

pub type GlobalInitClosure = Box<Fn(&mut SapperRequest) -> Result<()> + 'static + Send + Sync>;
pub type SapperAppShellType = Box<SapperAppShell + 'static + Send + Sync>;

pub struct SapperApp {
    pub address:        String,
    pub port:           u32,
    // for app entry, global middeware
    pub shell:          Option<Arc<SapperAppShellType>>,
    // for actually use to recognize
    pub routers:        Router,
    // do simple static file service
    pub static_service: bool,

    pub init_closure:   Option<Arc<GlobalInitClosure>>,

    pub not_found:      Option<String>
}

impl SapperApp {
    pub fn new() -> SapperApp {
        SapperApp {
            address: String::new(),
            port: 0,
            shell: None,
            routers: Router::new(),
            static_service: true,
            init_closure: None,
            not_found: None
        }
    }

    pub fn address(&mut self, address: &str) -> &mut Self {
        self.address = address.to_owned();
        self
    }

    pub fn port(&mut self, port: u32) -> &mut Self {
        self.port = port;
        self
    }

    pub fn static_service(&mut self, open: bool) -> &mut Self {
        self.static_service = open;
        self
    }

    pub fn with_shell(&mut self, w: SapperAppShellType) -> &mut Self {
        self.shell = Some(Arc::new(w));
        self
    }

    pub fn init_global(&mut self, clos: GlobalInitClosure) -> &mut Self {
        self.init_closure = Some(Arc::new(clos));
        self
    }

    pub fn not_found_page(&mut self, page: String) -> &mut Self {
        self.not_found = Some(page);
        self
    }

    // add methods of this sapper module
    pub fn add_module(&mut self, sm: Box<SapperModule>) -> &mut Self {

        let mut router = SapperRouter::new();
        // get the sm router
        sm.router(&mut router).unwrap();
        let sm = Arc::new(sm);

        for (method, handler_vec) in router.into_router() {
            // add to wrapped router
            for &(glob, ref handler) in handler_vec.iter() {
                let method = method.clone();
                let glob = glob.clone();
                let handler = handler.clone();
                let sm = sm.clone();
                let shell = self.shell.clone();
                let init_closure = self.init_closure.clone();

                self.routers.route(method, glob, Arc::new(Box::new(move |req: &mut SapperRequest| -> Result<SapperResponse> {
                    if let Some(ref c) = init_closure {
                        c(req)?;
                    }
                    if let Some(ref shell) = shell {
                        shell.before(req)?;
                    }
                    sm.before(req)?;
                    let mut response: SapperResponse = handler.handle(req)?;
                    sm.after(req, &mut response)?;
                    if let Some(ref shell) = shell {
                        shell.after(req, &mut response)?;
                    }
                    Ok(response)
                })));
            }
        }

        self
    }

    pub fn run_http(self) {

        let addr = self.address.clone() + ":" + &self.port.to_string();
        //let self_box = Arc::new(Box::new(self));

        Server::http(&addr[..]).unwrap()
                .handle(self).unwrap();

    }
}

impl Handler for SapperApp {

    fn handle(&self, req: Request, mut res: Response) {

        let mut sreq = SapperRequest::new(Box::new(req));
        let (path, query) = sreq.uri();

        // pass req to routers, execute matched biz handler
        let response_w = self.routers.handle_method(&mut sreq, &path);
        match response_w {
            Ok(sres) => {
                *res.status_mut() = sres.status();
                match sres.body() {
                    &Some(ref vec) => {
                        for header in sres.headers().iter() {
                            res.headers_mut()
                                .set_raw(header.name().to_owned(),
                                         vec![header.value_string().as_bytes().to_vec()]);
                        }
                        return res.send(&vec[..]).unwrap();
                    },
                    &None => {
                        return res.send(&"".as_bytes()).unwrap();
                    }
                }
            },
            Err(Error::NotFound) => {
                if self.static_service {
                    match simple_file_get(&path) {
                        Ok((file_u8vec, file_mime)) => {
                            res.headers_mut().set_raw("Content-Type", vec![file_mime.as_bytes().to_vec()]);
                            return res.send(&file_u8vec[..]).unwrap();
                        },
                        Err(_) => {
                            *res.status_mut() = StatusCode::NotFound;
                            return res.send(self.not_found.to_owned().unwrap_or(String::from("404 Not Found")).as_bytes()).unwrap();
                        }
                    }
                }

                // return 404 NotFound now
                *res.status_mut() = StatusCode::NotFound;
                return res.send(self.not_found.to_owned().unwrap_or(String::from("404 Not Found")).as_bytes()).unwrap();
            },
            Err(Error::Break) => {
                *res.status_mut() = StatusCode::BadRequest;
                return res.send(&"Bad Request".as_bytes()).unwrap();
            },
            Err(Error::Unauthorized) => {
                *res.status_mut() = StatusCode::Unauthorized;
                return res.send(&"Unauthorized".as_bytes()).unwrap();
            },
            Err(Error::Forbidden) => {
                *res.status_mut() = StatusCode::Forbidden;
                return res.send(&"Forbidden".as_bytes()).unwrap();
            },
            Err(Error::TemporaryRedirect(new_uri)) => {
                *res.status_mut() = StatusCode::TemporaryRedirect;
                res.headers_mut().set_raw("Location", vec![new_uri.as_bytes().to_vec()]);
                return res.send(&"Temporary Redirect".as_bytes()).unwrap();
            },
            Err(Error::Custom(ustr)) => {
                *res.status_mut() = StatusCode::Ok;
                return res.send(&ustr.as_bytes()).unwrap();
            },
            Err(Error::CustomHtml(html_str)) => {
                *res.status_mut() = StatusCode::Ok;
                res.headers_mut().set_raw("Content-Type", vec!["text/html".as_bytes().to_vec()]);
                return res.send(&html_str.as_bytes()).unwrap();
            },
            Err(Error::CustomJson(json_str)) => {
                *res.status_mut() = StatusCode::Ok;
                res.headers_mut().set_raw("Content-Type", vec!["application/x-javascript".as_bytes().to_vec()]);
                return res.send(&json_str.as_bytes()).unwrap();
            },
            Err(_) => {
                *res.status_mut() = StatusCode::InternalServerError;
                return res.send(&"InternalServerError".as_bytes()).unwrap();
            }

        }
    }
}

// this is very expensive in time
// should make it as global
lazy_static! {
    static ref MTYPES: MimeTypes = { MimeTypes::new().unwrap() };
}

fn simple_file_get(path: &str) -> Result<(Vec<u8>, String)> {
    let new_path;
    if &path[(path.len()-1)..] == "/" {
        new_path = "static/".to_owned() + path + "index.html";
    }
    else {
        new_path = "static/".to_owned() + path;
    }
    //println!("file path: {}", new_path);
    match File::open(&new_path) {
        Ok(ref mut file) => {
            let mut s: Vec<u8> = vec![];
            file.read_to_end(&mut s).unwrap_or(0);

            let mt_str = MTYPES.mime_for_path(Path::new(&new_path));

            Ok((s, mt_str.to_owned()))
        },
        Err(_) => Err(Error::FileNotExist)
    }
}

<commit_msg>export hypper primitive client<commit_after>use std::str;
use std::io::Read;
use std::fs::File;
use std::path::Path;
use std::sync::Arc;
use std::clone::Clone;

use hyper::status::StatusCode;
use hyper::server::{Handler, Server, Request, Response};
use mime_types::Types as MimeTypes;

pub use typemap::Key;
pub use hyper::header::Headers;
pub use hyper::header;
pub use hyper::mime;
pub use hyper::client::Client;
pub use request::SapperRequest;
pub use response::SapperResponse;
pub use router_m::Router;
pub use router::SapperRouter;
pub use handler::SapperHandler;

#[derive(Clone)]
pub struct PathParams;

/// Status Codes
pub mod status {
    pub use hyper::status::StatusCode as Status;
    pub use hyper::status::StatusCode::*;
}

#[derive(Debug, PartialEq, Clone)]
pub enum Error {
    InvalidConfig,
    InvalidRouterConfig,
    FileNotExist,
    NotFound,
    Break,          // 400
    Unauthorized,   // 401
    Forbidden,      // 403
    TemporaryRedirect(String),     // 307
    Custom(String),
    CustomHtml(String),
    CustomJson(String),
}

pub type Result<T> = ::std::result::Result<T, Error>;

pub trait SapperModule: Sync + Send {
    fn before(&self, req: &mut SapperRequest) -> Result<()> {
        Ok(())
    }

    fn after(&self, req: &SapperRequest, res: &mut SapperResponse) -> Result<()> {
        Ok(())
    }

    fn router(&self, &mut SapperRouter) -> Result<()>;

}

pub trait SapperAppShell {
    fn before(&self, &mut SapperRequest) -> Result<()>;
    fn after(&self, &SapperRequest, &mut SapperResponse) -> Result<()>;
}

pub type GlobalInitClosure = Box<Fn(&mut SapperRequest) -> Result<()> + 'static + Send + Sync>;
pub type SapperAppShellType = Box<SapperAppShell + 'static + Send + Sync>;

pub struct SapperApp {
    pub address:        String,
    pub port:           u32,
    // for app entry, global middeware
    pub shell:          Option<Arc<SapperAppShellType>>,
    // for actually use to recognize
    pub routers:        Router,
    // do simple static file service
    pub static_service: bool,

    pub init_closure:   Option<Arc<GlobalInitClosure>>,

    pub not_found:      Option<String>
}

impl SapperApp {
    pub fn new() -> SapperApp {
        SapperApp {
            address: String::new(),
            port: 0,
            shell: None,
            routers: Router::new(),
            static_service: true,
            init_closure: None,
            not_found: None
        }
    }

    pub fn address(&mut self, address: &str) -> &mut Self {
        self.address = address.to_owned();
        self
    }

    pub fn port(&mut self, port: u32) -> &mut Self {
        self.port = port;
        self
    }

    pub fn static_service(&mut self, open: bool) -> &mut Self {
        self.static_service = open;
        self
    }

    pub fn with_shell(&mut self, w: SapperAppShellType) -> &mut Self {
        self.shell = Some(Arc::new(w));
        self
    }

    pub fn init_global(&mut self, clos: GlobalInitClosure) -> &mut Self {
        self.init_closure = Some(Arc::new(clos));
        self
    }

    pub fn not_found_page(&mut self, page: String) -> &mut Self {
        self.not_found = Some(page);
        self
    }

    // add methods of this sapper module
    pub fn add_module(&mut self, sm: Box<SapperModule>) -> &mut Self {

        let mut router = SapperRouter::new();
        // get the sm router
        sm.router(&mut router).unwrap();
        let sm = Arc::new(sm);

        for (method, handler_vec) in router.into_router() {
            // add to wrapped router
            for &(glob, ref handler) in handler_vec.iter() {
                let method = method.clone();
                let glob = glob.clone();
                let handler = handler.clone();
                let sm = sm.clone();
                let shell = self.shell.clone();
                let init_closure = self.init_closure.clone();

                self.routers.route(method, glob, Arc::new(Box::new(move |req: &mut SapperRequest| -> Result<SapperResponse> {
                    if let Some(ref c) = init_closure {
                        c(req)?;
                    }
                    if let Some(ref shell) = shell {
                        shell.before(req)?;
                    }
                    sm.before(req)?;
                    let mut response: SapperResponse = handler.handle(req)?;
                    sm.after(req, &mut response)?;
                    if let Some(ref shell) = shell {
                        shell.after(req, &mut response)?;
                    }
                    Ok(response)
                })));
            }
        }

        self
    }

    pub fn run_http(self) {

        let addr = self.address.clone() + ":" + &self.port.to_string();
        //let self_box = Arc::new(Box::new(self));

        Server::http(&addr[..]).unwrap()
                .handle(self).unwrap();

    }
}

impl Handler for SapperApp {

    fn handle(&self, req: Request, mut res: Response) {

        let mut sreq = SapperRequest::new(Box::new(req));
        let (path, query) = sreq.uri();

        // pass req to routers, execute matched biz handler
        let response_w = self.routers.handle_method(&mut sreq, &path);
        match response_w {
            Ok(sres) => {
                *res.status_mut() = sres.status();
                match sres.body() {
                    &Some(ref vec) => {
                        for header in sres.headers().iter() {
                            res.headers_mut()
                                .set_raw(header.name().to_owned(),
                                         vec![header.value_string().as_bytes().to_vec()]);
                        }
                        return res.send(&vec[..]).unwrap();
                    },
                    &None => {
                        return res.send(&"".as_bytes()).unwrap();
                    }
                }
            },
            Err(Error::NotFound) => {
                if self.static_service {
                    match simple_file_get(&path) {
                        Ok((file_u8vec, file_mime)) => {
                            res.headers_mut().set_raw("Content-Type", vec![file_mime.as_bytes().to_vec()]);
                            return res.send(&file_u8vec[..]).unwrap();
                        },
                        Err(_) => {
                            *res.status_mut() = StatusCode::NotFound;
                            return res.send(self.not_found.to_owned().unwrap_or(String::from("404 Not Found")).as_bytes()).unwrap();
                        }
                    }
                }

                // return 404 NotFound now
                *res.status_mut() = StatusCode::NotFound;
                return res.send(self.not_found.to_owned().unwrap_or(String::from("404 Not Found")).as_bytes()).unwrap();
            },
            Err(Error::Break) => {
                *res.status_mut() = StatusCode::BadRequest;
                return res.send(&"Bad Request".as_bytes()).unwrap();
            },
            Err(Error::Unauthorized) => {
                *res.status_mut() = StatusCode::Unauthorized;
                return res.send(&"Unauthorized".as_bytes()).unwrap();
            },
            Err(Error::Forbidden) => {
                *res.status_mut() = StatusCode::Forbidden;
                return res.send(&"Forbidden".as_bytes()).unwrap();
            },
            Err(Error::TemporaryRedirect(new_uri)) => {
                *res.status_mut() = StatusCode::TemporaryRedirect;
                res.headers_mut().set_raw("Location", vec![new_uri.as_bytes().to_vec()]);
                return res.send(&"Temporary Redirect".as_bytes()).unwrap();
            },
            Err(Error::Custom(ustr)) => {
                *res.status_mut() = StatusCode::Ok;
                return res.send(&ustr.as_bytes()).unwrap();
            },
            Err(Error::CustomHtml(html_str)) => {
                *res.status_mut() = StatusCode::Ok;
                res.headers_mut().set_raw("Content-Type", vec!["text/html".as_bytes().to_vec()]);
                return res.send(&html_str.as_bytes()).unwrap();
            },
            Err(Error::CustomJson(json_str)) => {
                *res.status_mut() = StatusCode::Ok;
                res.headers_mut().set_raw("Content-Type", vec!["application/x-javascript".as_bytes().to_vec()]);
                return res.send(&json_str.as_bytes()).unwrap();
            },
            Err(_) => {
                *res.status_mut() = StatusCode::InternalServerError;
                return res.send(&"InternalServerError".as_bytes()).unwrap();
            }

        }
    }
}

// this is very expensive in time
// should make it as global
lazy_static! {
    static ref MTYPES: MimeTypes = { MimeTypes::new().unwrap() };
}

fn simple_file_get(path: &str) -> Result<(Vec<u8>, String)> {
    let new_path;
    if &path[(path.len()-1)..] == "/" {
        new_path = "static/".to_owned() + path + "index.html";
    }
    else {
        new_path = "static/".to_owned() + path;
    }
    //println!("file path: {}", new_path);
    match File::open(&new_path) {
        Ok(ref mut file) => {
            let mut s: Vec<u8> = vec![];
            file.read_to_end(&mut s).unwrap_or(0);

            let mt_str = MTYPES.mime_for_path(Path::new(&new_path));

            Ok((s, mt_str.to_owned()))
        },
        Err(_) => Err(Error::FileNotExist)
    }
}

<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]

use std::ffi::CString;

use ffi;

use wrapper::{Wrapper, from_char_ptr};

pub enum HookOrder {
   REALLY_FIRST,  // run this hook first, before ANYTHING
   FIRST,         // run this hook first
   MIDDLE,        // run this hook somewhere
   LAST,          // run this hook after every other hook which is defined
   REALLY_LAST    // run this hook last, after EVERYTHING
}

impl Into<::libc::c_int> for HookOrder {
   fn into(self) -> ::libc::c_int {
      match self {
         HookOrder::REALLY_FIRST => ffi::APR_HOOK_REALLY_FIRST,
         HookOrder::FIRST => ffi::APR_HOOK_FIRST,
         HookOrder::MIDDLE => ffi::APR_HOOK_MIDDLE,
         HookOrder::LAST => ffi::APR_HOOK_LAST,
         HookOrder::REALLY_LAST => ffi::APR_HOOK_REALLY_LAST
      }
   }
}

pub type AprTable<'a> = Wrapper<'a, ffi::apr_table_t>;

impl<'a> AprTable<'a> {
   pub fn get<T: Into<Vec<u8>>>(&self, key: T) -> Result<&'a str, ()> {
      let key = match CString::new(key) {
         Ok(s) => s,
         Err(_) => return Err(())
      };

      from_char_ptr(
         unsafe { ffi::apr_table_get(self.raw, key.as_ptr()) }
      )
   }

   pub fn set<T: Into<Vec<u8>>, U: Into<Vec<u8>>>(&mut self, key: T, val: U) -> Result<(), ()> {
      let key = match CString::new(key) {
         Ok(s) => s,
         Err(_) => return Err(())
      };

      let val = match CString::new(val) {
         Ok(s) => s,
         Err(_) => return Err(())
      };

      unsafe {
         ffi::apr_table_set(
            self.raw,
            key.as_ptr(),
            val.as_ptr()
         )
      };

      Ok(())
   }

   pub fn add<T: Into<Vec<u8>>, U: Into<Vec<u8>>>(&mut self, key: T, val: U) -> Result<(), ()> {
      let key = match CString::new(key) {
         Ok(s) => s,
         Err(_) => return Err(())
      };

      let val = match CString::new(val) {
         Ok(s) => s,
         Err(_) => return Err(())
      };

      unsafe {
         ffi::apr_table_add(
            self.raw,
            key.as_ptr(),
            val.as_ptr()
         )
      };

      Ok(())
   }

   pub fn iter(&self) -> AprTableIter {
      let ptr = unsafe { ffi::apr_table_elts(self.raw) };
      let raw: &ffi::apr_array_header_t = unsafe { &*ptr };

      AprTableIter {
         array_header: raw,
         next_idx: 0
      }
   }
}

pub struct AprTableIter<'a> {
   array_header: &'a ffi::apr_array_header_t,
   next_idx: usize,
}

impl<'a> Iterator for AprTableIter<'a> {
   type Item = (&'a str, Result<&'a str, ()>);

   fn next(&mut self) -> Option<(&'a str, Result<&'a str, ()>)> {
      if self.next_idx != self.array_header.nelts as usize {
         let mut elts = self.array_header.elts as *const ffi::apr_table_entry_t;

         elts = unsafe { elts.offset(self.next_idx as isize) };
         self.next_idx += 1;

         let key = from_char_ptr(unsafe { (*elts).key }).unwrap();
         let val_result = from_char_ptr(unsafe { (*elts).val });

         Some((key, val_result))
      } else {
         None
      }
   }

   fn size_hint(&self) -> (usize, Option<usize>) {
      let rem = self.array_header.nelts as usize - self.next_idx;
      (rem, Some(rem))
   }
}

pub fn apr_version_string<'a>() -> Result<&'a str, ()> {
   from_char_ptr(
      unsafe { ffi::apr_version_string() }
   )
}

pub fn apu_version_string<'a>() -> Result<&'a str, ()> {
   from_char_ptr(
      unsafe { ffi::apu_version_string() }
   )
}

pub fn time_now() -> i64 {
   unsafe {
      ffi::apr_time_now()
   }
}
<commit_msg>apr_pool_t wrapper.<commit_after>#![allow(non_camel_case_types)]

use std::ffi::CString;

use ffi;

use wrapper::{Wrapper, from_char_ptr};

pub enum HookOrder {
   REALLY_FIRST,  // run this hook first, before ANYTHING
   FIRST,         // run this hook first
   MIDDLE,        // run this hook somewhere
   LAST,          // run this hook after every other hook which is defined
   REALLY_LAST    // run this hook last, after EVERYTHING
}

impl Into<::libc::c_int> for HookOrder {
   fn into(self) -> ::libc::c_int {
      match self {
         HookOrder::REALLY_FIRST => ffi::APR_HOOK_REALLY_FIRST,
         HookOrder::FIRST => ffi::APR_HOOK_FIRST,
         HookOrder::MIDDLE => ffi::APR_HOOK_MIDDLE,
         HookOrder::LAST => ffi::APR_HOOK_LAST,
         HookOrder::REALLY_LAST => ffi::APR_HOOK_REALLY_LAST
      }
   }
}

pub type AprTable<'a> = Wrapper<'a, ffi::apr_table_t>;

impl<'a> AprTable<'a> {
   pub fn get<T: Into<Vec<u8>>>(&self, key: T) -> Result<&'a str, ()> {
      let key = match CString::new(key) {
         Ok(s) => s,
         Err(_) => return Err(())
      };

      from_char_ptr(
         unsafe { ffi::apr_table_get(self.raw, key.as_ptr()) }
      )
   }

   pub fn set<T: Into<Vec<u8>>, U: Into<Vec<u8>>>(&mut self, key: T, val: U) -> Result<(), ()> {
      let key = match CString::new(key) {
         Ok(s) => s,
         Err(_) => return Err(())
      };

      let val = match CString::new(val) {
         Ok(s) => s,
         Err(_) => return Err(())
      };

      unsafe {
         ffi::apr_table_set(
            self.raw,
            key.as_ptr(),
            val.as_ptr()
         )
      };

      Ok(())
   }

   pub fn add<T: Into<Vec<u8>>, U: Into<Vec<u8>>>(&mut self, key: T, val: U) -> Result<(), ()> {
      let key = match CString::new(key) {
         Ok(s) => s,
         Err(_) => return Err(())
      };

      let val = match CString::new(val) {
         Ok(s) => s,
         Err(_) => return Err(())
      };

      unsafe {
         ffi::apr_table_add(
            self.raw,
            key.as_ptr(),
            val.as_ptr()
         )
      };

      Ok(())
   }

   pub fn iter(&self) -> AprTableIter {
      let ptr = unsafe { ffi::apr_table_elts(self.raw) };
      let raw: &ffi::apr_array_header_t = unsafe { &*ptr };

      AprTableIter {
         array_header: raw,
         next_idx: 0
      }
   }
}

pub type Pool<'a> = Wrapper<'a, ffi::apr_pool_t>;

pub struct AprTableIter<'a> {
   array_header: &'a ffi::apr_array_header_t,
   next_idx: usize,
}

impl<'a> Iterator for AprTableIter<'a> {
   type Item = (&'a str, Result<&'a str, ()>);

   fn next(&mut self) -> Option<(&'a str, Result<&'a str, ()>)> {
      if self.next_idx != self.array_header.nelts as usize {
         let mut elts = self.array_header.elts as *const ffi::apr_table_entry_t;

         elts = unsafe { elts.offset(self.next_idx as isize) };
         self.next_idx += 1;

         let key = from_char_ptr(unsafe { (*elts).key }).unwrap();
         let val_result = from_char_ptr(unsafe { (*elts).val });

         Some((key, val_result))
      } else {
         None
      }
   }

   fn size_hint(&self) -> (usize, Option<usize>) {
      let rem = self.array_header.nelts as usize - self.next_idx;
      (rem, Some(rem))
   }
}

pub fn apr_version_string<'a>() -> Result<&'a str, ()> {
   from_char_ptr(
      unsafe { ffi::apr_version_string() }
   )
}

pub fn apu_version_string<'a>() -> Result<&'a str, ()> {
   from_char_ptr(
      unsafe { ffi::apu_version_string() }
   )
}

pub fn time_now() -> i64 {
   unsafe {
      ffi::apr_time_now()
   }
}
<|endoftext|>