<commit_before>use std::thread;
use std::sync::mpsc;
use websocket;
use websocket::{Message, Sender, Receiver};
use websocket::server::sender;
use websocket::stream::WebSocketStream;
use websocket::message::CloseData;
use std::io::prelude::*;
use std::fs::{OpenOptions};
use std::net::Shutdown;
use rustc_serialize::json::{Json, ToJson};
use cbor;
use hyper::header::Cookie;

use value::Value;
use relation::Change;
use flow::{Changes, Flow};

// The server manages a single Eve program and handles communication with the editor and clients
// TODO needs review / refactoring, especially session handling

pub struct Server {
    pub flow: Flow,
    pub senders: Vec<sender::Sender<WebSocketStream>>,
}

#[derive(Debug, Clone)]
pub struct Event {
    pub changes: Changes,
    pub session: String,
    // commands that affect the whole program state have to go through this side-channel rather than being added to a view
    // supported commands: ["load", filename], ["save", filename]
    pub commands: Vec<Vec<String>>,
}

pub enum ServerEvent {
    Change(Vec<u8>),
    Sync((sender::Sender<WebSocketStream>, Option<String>)),
    Terminate(Option<CloseData>),
}

// --- json encodings ---

pub trait FromJson {
    fn from_json(json: &Json) -> Self;
}

impl ToJson for Value {
    fn to_json(&self) -> Json {
        match *self {
            Value::Null => panic!("Cannot allow the client to see nulls"),
            Value::Bool(bool) => Json::Boolean(bool),
            Value::String(ref string) => Json::String(string.clone()),
            Value::Float(float) => Json::F64(float),
            Value::Column(ref column) => Json::Array(column.iter().map(|v| v.to_json()).collect()),
        }
    }
}

impl FromJson for Value {
    fn from_json(json: &Json) -> Self {
        match *json {
            Json::Boolean(bool) => Value::Bool(bool),
            Json::String(ref string) => Value::String(string.clone()),
            Json::F64(float) => Value::Float(float),
            Json::I64(int) => Value::Float(int as f64),
            Json::U64(uint) => Value::Float(uint as f64),
            Json::Array(ref array) => Value::Column(array.iter().map(FromJson::from_json).collect()),
            _ => panic!("Cannot decode {:?} as Value", json),
        }
    }
}

impl FromJson for String {
    fn from_json(json: &Json) -> Self {
        json.as_string().unwrap().to_owned()
    }
}

impl<T: FromJson> FromJson for Vec<T> {
    fn from_json(json: &Json) -> Self {
        json.as_array().unwrap().iter().map(|t| FromJson::from_json(t)).collect()
    }
}

impl ToJson for Event {
    fn to_json(&self) -> Json {
        Json::Object(vec![
            ("changes".to_string(), Json::Array(
                self.changes.iter().map(|&(ref view_id, ref view_changes)| {
                    Json::Array(vec![
                        view_id.to_json(),
                        view_changes.fields.to_json(),
                        view_changes.insert.to_json(),
                        view_changes.remove.to_json(),
                        ])
                }).collect()
                )
            ),
            ("session".to_string(), self.session.to_json()),
            ("commands".to_string(), self.commands.to_json()),
        ].into_iter().collect())
    }
}

impl FromJson for Event {
    fn from_json(json: &Json) -> Self {
        Event{
            changes: json.as_object().unwrap()["changes"]
            .as_array().unwrap().iter().map(|change| {
                let change = change.as_array().unwrap();
                assert_eq!(change.len(), 4);
                let view_id = FromJson::from_json(&change[0]);
                let fields = FromJson::from_json(&change[1]);
                let insert = FromJson::from_json(&change[2]);
                let remove = FromJson::from_json(&change[3]);
                (view_id, Change{fields:fields, insert: insert, remove: remove})
            }).collect(),
            session: "".to_string(),
            commands: FromJson::from_json(json.as_object().unwrap().get("commands").unwrap_or(&Json::Array(vec![]))),
        }
    }
}

// --- persistence ---

pub fn read_file(filename: &str) -> String {
    let mut file = OpenOptions::new().create(true).open(filename).unwrap();
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    contents
}

pub fn write_file(filename: &str, contents: &str) {
    let mut file = OpenOptions::new().create(true).truncate(true).write(true).open(filename).unwrap();
    file.write_all(contents.as_bytes()).unwrap();
}

pub fn load(flow: &mut Flow, filename: &str) {
    for line in read_file(filename).lines() {
        let json = Json::from_str(&line).unwrap();
        let event: Event = FromJson::from_json(&json);
        flow.quiesce(event.changes);
    }
}

// TODO should probably just save changes, not the whole event
pub fn save(flow: &Flow, filename: &str) {
    let changes = flow.as_changes();
    let text = format!("{}", Event{changes: changes, session: "".to_owned(), commands: vec![]}.to_json());
    write_file(filename, &text[..]);
}

// --- server ---

pub fn send_event(server: &mut Server, changes: &Changes, commands: &Vec<Vec<String>>) {
    for sender in server.senders.iter_mut() {
        let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
        let event = Event{changes: changes.clone(), session: session_id, commands: commands.clone()};
        let text = format!("{}", event.to_json());
        match sender.send_message(Message::Text(text)) {
            Ok(_) => (),
            Err(error) => println!("Send error: {}", error),
        };
    }
}

pub fn get_user_id(cookies: Option<&Cookie>) -> Option<String> {
    match cookies {
        Some(cookies) => {
            match cookies.iter().find(|cookie| cookie.name == "userid") {
                Some(user_id) => Some(user_id.value.clone()),
                None => None,
            }
        },
        None => None,
    }
}

// rust-websocket is blocking, so we have to spawn a thread per connection
// each thread sends events back to a central channel
pub fn server_events() -> mpsc::Receiver<ServerEvent> {
    let (event_sender, event_receiver) = mpsc::channel();
    thread::spawn(move || {
        let server = websocket::Server::bind("0.0.0.0:2794").unwrap();
        for connection in server {
            let event_sender = event_sender.clone();
            thread::spawn(move || {
                // accept request
                let request = connection.unwrap().read_request().unwrap();
                request.validate().unwrap();

                // get the User ID from a cookie in the headers
                let user_id = get_user_id(request.headers.get::<Cookie>());

                let response = request.accept();
                let (mut sender, mut receiver) = response.send().unwrap().split();

                let ip = sender.get_mut().peer_addr().unwrap();
                println!("Connection from {}", ip);
                ::std::io::stdout().flush().unwrap(); // TODO is this actually necessary?

                // hand over the sender
                event_sender.send(ServerEvent::Sync((sender,user_id))).unwrap();

                // handle messages
                for message in receiver.incoming_messages() {
                    let message = match message {
                        Ok(m) => m,
                        Err(_) => return,
                    };
                    match message {
                        Message::Binary(bytes) => {
                            event_sender.send(ServerEvent::Change(bytes)).unwrap();
                        }
                        Message::Close(_) => {
                            let ip_addr = format!("{}", ip);
                            println!("Received close message from {}.",ip_addr);
                            let close_message = CloseData{status_code: 0, reason: ip_addr};
                            event_sender.send(ServerEvent::Terminate(Some(close_message))).unwrap();
                        }
                        _ => println!("Unknown message: {:?}", message)
                    }
                }
            });
        }
    });
    event_receiver
}

pub fn handle_event(server: &mut Server, event: Event, event_json: Json) {
    // save the event
    {
        let mut autosave = OpenOptions::new().write(true).append(true).open("./autosave").unwrap();
        autosave.write_all(format!("{}", event_json).as_bytes()).unwrap();
        autosave.write_all("\n".as_bytes()).unwrap();
        autosave.flush().unwrap();
    }

    // copy the old flow so we can compare to the new flow for changes
    let old_flow = server.flow.clone();

    // run the flow until it reaches fixpoint
    server.flow.quiesce(event.changes);

    // handle commands
    for command in event.commands.iter() {
        let borrowed_words = command.iter().map(|word| &word[..]).collect::<Vec<_>>();
        match &borrowed_words[..] {
            ["load", filename] => {
                server.flow = Flow::new();
                load(&mut server.flow, "./bootstrap");
                load(&mut server.flow, filename);
                save(&server.flow, "./autosave");
                send_event(server, &vec![], &vec![
                    vec!["loaded".to_owned(), filename.to_owned()]
                    ]);
            }
            ["save", filename] => {
                save(&server.flow, filename);
            }
            ["get events", id] => {
                let events_string = read_file("./autosave");
                send_event(server, &vec![], &vec![
                    vec!["got events".to_owned(), id.to_owned(), events_string]
                    ]);
            }
            ["set events", events_string] => {
                write_file("./autosave", events_string);
                server.flow = Flow::new();
                load(&mut server.flow, "./bootstrap");
                load(&mut server.flow, "./autosave");
            }
            other => panic!("Unknown command: {:?}", other),
        }
    }

    let changes = &server.flow.changes_from(old_flow);
    send_event(server, changes, &vec![]);
}

pub fn run() {
    let mut flow = Flow::new();
    time!("reading saved state", {
        load(&mut flow, "./bootstrap");
        load(&mut flow, "./autosave");
    });

    let senders: Vec<sender::Sender<WebSocketStream>> = Vec::new();

    let mut server = Server{flow: flow, senders: senders};

    for server_event in server_events() {
        match server_event {

            // a new client has connected and needs to sync its state
            ServerEvent::Sync((mut sender, user_id)) => {
                let mut changes = vec![];

                // add a session to the session table
                let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
                changes.push(("sessions".to_owned(),
                    Change{
                        fields: vec!["sessions: id".to_owned(), "sessions: status".to_owned()],
                        insert: vec![vec![Value::String(session_id.clone()), Value::Float(1f64)]],
                        remove: vec![],
                    }));

                // if we have a user ID, add a mapping from the session ID to the user ID
                if let Some(user_id) = user_id {
                    changes.push(("session id to user id".to_owned(),
                        Change{
                            fields: vec!["session id to user id: session id".to_owned(), "session id to user id: user id".to_owned()],
                            insert: vec![vec![Value::String(session_id.clone()), Value::String(user_id)]],
                            remove: vec![]
                        }));
                }

                // handle the session change
                let event = Event{changes: changes, session: session_id.clone(), commands: vec![]};
                let json = event.to_json();
                handle_event(&mut server, event, json);

                // sync the new client
                let changes = server.flow.as_changes();
                let event = Event{changes: changes, session: session_id, commands: vec![]};
                let text = format!("{}", event.to_json());
                match sender.send_message(Message::Text(text)) {
                    Ok(_) => (),
                    Err(error) => println!("Send error: {}", error),
                };
                server.senders.push(sender)
            }

            // an existing client has sent a new message
            ServerEvent::Change(input_bytes) => {
                // TODO we throw cbor in here to avoid https://github.com/rust-lang/rustc-serialize/issues/113
                let mut decoder = cbor::Decoder::from_bytes(&input_bytes[..]);
                let cbor = decoder.items().next().unwrap().unwrap();
                let json = cbor.to_json();
                let event = FromJson::from_json(&json);
                handle_event(&mut server, event, json);
            }

            ServerEvent::Terminate(m) => {
                let terminate_ip = m.unwrap().reason;
                println!("Closing connection from {}...",terminate_ip);

                // find the index of the connection's sender
                let ip_ix = server.senders.iter_mut().position(|mut sender| {
                    let ip = format!("{}",sender.get_mut().peer_addr().unwrap());
                    ip == terminate_ip
                });

                match ip_ix {
                    Some(ix) => {
                        // close the connection
                        let _ = server.senders[ix].send_message(Message::Close(None));
                        match server.senders[ix].get_mut().shutdown(Shutdown::Both) {
                            Ok(_) => println!("Connection from {} has closed successfully.",terminate_ip),
                            Err(e) => println!("Connection from {} failed to shut down properly: {}",terminate_ip,e),
                        }
                        server.senders.remove(ix);

                        // update the session table
                        let sessions = server.flow.get_output("sessions").clone();
                        let ip_string = Value::String(terminate_ip.clone());

                        // change the session status to 0
                        for row in sessions.find(vec![&ip_string, &Value::Null]) {
                            match row {
                                [_, ref status] => {
                                    let change = Change {
                                        fields: sessions.fields.clone(),
                                        insert: vec![vec![ip_string.clone(), Value::Float(0f64)]],
                                        remove: vec![vec![ip_string.clone(), status.clone()]],
                                    };
                                    let event = Event{changes: vec![("sessions".to_string(),change)], session: "".to_string(), commands: vec![]};
                                    let json = event.to_json();
                                    handle_event(&mut server, event, json);
                                }
                                _ => unreachable!(),
                            }
                        }

                    },
                    None => panic!("IP address {} is not connected",terminate_ip),
                }
            }
        }
    }
}<commit_msg>Send current dir to editor on load/save so it can figure out where the file is<commit_after>use std::thread;
use std::sync::mpsc;
use websocket;
use websocket::{Message, Sender, Receiver};
use websocket::server::sender;
use websocket::stream::WebSocketStream;
use websocket::message::CloseData;
use std::io::prelude::*;
use std::fs::{OpenOptions};
use std::net::Shutdown;
use rustc_serialize::json::{Json, ToJson};
use cbor;
use hyper::header::Cookie;

use value::Value;
use relation::Change;
use flow::{Changes, Flow};

// The server manages a single Eve program and handles communication with the editor and clients
// TODO needs review / refactoring, especially session handling

pub struct Server {
    pub flow: Flow,
    pub senders: Vec<sender::Sender<WebSocketStream>>,
}

#[derive(Debug, Clone)]
pub struct Event {
    pub changes: Changes,
    pub session: String,
    // commands that affect the whole program state have to go through this side-channel rather than being added to a view
    pub commands: Vec<Vec<String>>,
}

pub enum ServerEvent {
    Change(Vec<u8>),
    Sync((sender::Sender<WebSocketStream>, Option<String>)),
    Terminate(Option<CloseData>),
}

// --- json encodings ---

pub trait FromJson {
    fn from_json(json: &Json) -> Self;
}

impl ToJson for Value {
    fn to_json(&self) -> Json {
        match *self {
            Value::Null => panic!("Cannot allow the client to see nulls"),
            Value::Bool(bool) => Json::Boolean(bool),
            Value::String(ref string) => Json::String(string.clone()),
            Value::Float(float) => Json::F64(float),
            Value::Column(ref column) => Json::Array(column.iter().map(|v| v.to_json()).collect()),
        }
    }
}

impl FromJson for Value {
    fn from_json(json: &Json) -> Self {
        match *json {
            Json::Boolean(bool) => Value::Bool(bool),
            Json::String(ref string) => Value::String(string.clone()),
            Json::F64(float) => Value::Float(float),
            Json::I64(int) => Value::Float(int as f64),
            Json::U64(uint) => Value::Float(uint as f64),
            Json::Array(ref array) => Value::Column(array.iter().map(FromJson::from_json).collect()),
            _ => panic!("Cannot decode {:?} as Value", json),
        }
    }
}

impl FromJson for String {
    fn from_json(json: &Json) -> Self {
        json.as_string().unwrap().to_owned()
    }
}

impl<T: FromJson> FromJson for Vec<T> {
    fn from_json(json: &Json) -> Self {
        json.as_array().unwrap().iter().map(|t| FromJson::from_json(t)).collect()
    }
}

impl ToJson for Event {
    fn to_json(&self) -> Json {
        Json::Object(vec![
            ("changes".to_string(), Json::Array(
                self.changes.iter().map(|&(ref view_id, ref view_changes)| {
                    Json::Array(vec![
                        view_id.to_json(),
                        view_changes.fields.to_json(),
                        view_changes.insert.to_json(),
                        view_changes.remove.to_json(),
                        ])
                }).collect()
                )
            ),
            ("session".to_string(), self.session.to_json()),
            ("commands".to_string(), self.commands.to_json()),
        ].into_iter().collect())
    }
}

impl FromJson for Event {
    fn from_json(json: &Json) -> Self {
        Event{
            changes: json.as_object().unwrap()["changes"]
            .as_array().unwrap().iter().map(|change| {
                let change = change.as_array().unwrap();
                assert_eq!(change.len(), 4);
                let view_id = FromJson::from_json(&change[0]);
                let fields = FromJson::from_json(&change[1]);
                let insert = FromJson::from_json(&change[2]);
                let remove = FromJson::from_json(&change[3]);
                (view_id, Change{fields:fields, insert: insert, remove: remove})
            }).collect(),
            session: "".to_string(),
            commands: FromJson::from_json(json.as_object().unwrap().get("commands").unwrap_or(&Json::Array(vec![]))),
        }
    }
}

// --- persistence ---

pub fn read_file(filename: &str) -> String {
    let mut file = OpenOptions::new().create(true).open(filename).unwrap();
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    contents
}

pub fn write_file(filename: &str, contents: &str) {
    let mut file = OpenOptions::new().create(true).truncate(true).write(true).open(filename).unwrap();
    file.write_all(contents.as_bytes()).unwrap();
}

pub fn load(flow: &mut Flow, filename: &str) {
    for line in read_file(filename).lines() {
        let json = Json::from_str(&line).unwrap();
        let event: Event = FromJson::from_json(&json);
        flow.quiesce(event.changes);
    }
}

// TODO should probably just save changes, not the whole event
pub fn save(flow: &Flow, filename: &str) {
    let changes = flow.as_changes();
    let text = format!("{}", Event{changes: changes, session: "".to_owned(), commands: vec![]}.to_json());
    write_file(filename, &text[..]);
}

// --- server ---

pub fn send_event(server: &mut Server, changes: &Changes, commands: &Vec<Vec<String>>) {
    for sender in server.senders.iter_mut() {
        let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
        let event = Event{changes: changes.clone(), session: session_id, commands: commands.clone()};
        let text = format!("{}", event.to_json());
        match sender.send_message(Message::Text(text)) {
            Ok(_) => (),
            Err(error) => println!("Send error: {}", error),
        };
    }
}

pub fn get_user_id(cookies: Option<&Cookie>) -> Option<String> {
    match cookies {
        Some(cookies) => {
            match cookies.iter().find(|cookie| cookie.name == "userid") {
                Some(user_id) => Some(user_id.value.clone()),
                None => None,
            }
        },
        None => None,
    }
}

// rust-websocket is blocking, so we have to spawn a thread per connection
// each thread sends events back to a central channel
pub fn server_events() -> mpsc::Receiver<ServerEvent> {
    let (event_sender, event_receiver) = mpsc::channel();
    thread::spawn(move || {
        let server = websocket::Server::bind("0.0.0.0:2794").unwrap();
        for connection in server {
            let event_sender = event_sender.clone();
            thread::spawn(move || {
                // accept request
                let request = connection.unwrap().read_request().unwrap();
                request.validate().unwrap();

                // get the User ID from a cookie in the headers
                let user_id = get_user_id(request.headers.get::<Cookie>());

                let response = request.accept();
                let (mut sender, mut receiver) = response.send().unwrap().split();

                let ip = sender.get_mut().peer_addr().unwrap();
                println!("Connection from {}", ip);
                ::std::io::stdout().flush().unwrap(); // TODO is this actually necessary?

                // hand over the sender
                event_sender.send(ServerEvent::Sync((sender,user_id))).unwrap();

                // handle messages
                for message in receiver.incoming_messages() {
                    let message = match message {
                        Ok(m) => m,
                        Err(_) => return,
                    };
                    match message {
                        Message::Binary(bytes) => {
                            event_sender.send(ServerEvent::Change(bytes)).unwrap();
                        }
                        Message::Close(_) => {
                            let ip_addr = format!("{}", ip);
                            println!("Received close message from {}.",ip_addr);
                            let close_message = CloseData{status_code: 0, reason: ip_addr};
                            event_sender.send(ServerEvent::Terminate(Some(close_message))).unwrap();
                        }
                        _ => println!("Unknown message: {:?}", message)
                    }
                }
            });
        }
    });
    event_receiver
}

pub fn handle_event(server: &mut Server, event: Event, event_json: Json) {
    // save the event
    {
        let mut autosave = OpenOptions::new().write(true).append(true).open("./autosave").unwrap();
        autosave.write_all(format!("{}", event_json).as_bytes()).unwrap();
        autosave.write_all("\n".as_bytes()).unwrap();
        autosave.flush().unwrap();
    }

    // copy the old flow so we can compare to the new flow for changes
    let old_flow = server.flow.clone();

    // run the flow until it reaches fixpoint
    server.flow.quiesce(event.changes);

    // handle commands
    for command in event.commands.iter() {
        let borrowed_words = command.iter().map(|word| &word[..]).collect::<Vec<_>>();
        match &borrowed_words[..] {
            ["load", filename] => {
                server.flow = Flow::new();
                load(&mut server.flow, "./bootstrap");
                load(&mut server.flow, filename);
                save(&server.flow, "./autosave");
                let current_dir = ::std::env::current_dir().unwrap().to_str().unwrap().to_owned();
                send_event(server, &vec![], &vec![
                    vec!["loaded".to_owned(), current_dir, filename.to_owned()]
                    ]);
            }
            ["save", filename] => {
                save(&server.flow, filename);
                let current_dir = ::std::env::current_dir().unwrap().to_str().unwrap().to_owned();
                send_event(server, &vec![], &vec![
                    vec!["saved".to_owned(), current_dir, filename.to_owned()]
                    ]);
            }
            ["get events", id] => {
                let events_string = read_file("./autosave");
                send_event(server, &vec![], &vec![
                    vec!["got events".to_owned(), id.to_owned(), events_string]
                    ]);
            }
            ["set events", events_string] => {
                write_file("./autosave", events_string);
                server.flow = Flow::new();
                load(&mut server.flow, "./bootstrap");
                load(&mut server.flow, "./autosave");
            }
            other => panic!("Unknown command: {:?}", other),
        }
    }

    let changes = &server.flow.changes_from(old_flow);
    send_event(server, changes, &vec![]);
}

pub fn run() {
    let mut flow = Flow::new();
    time!("reading saved state", {
        load(&mut flow, "./bootstrap");
        load(&mut flow, "./autosave");
    });

    let senders: Vec<sender::Sender<WebSocketStream>> = Vec::new();

    let mut server = Server{flow: flow, senders: senders};

    for server_event in server_events() {
        match server_event {

            // a new client has connected and needs to sync its state
            ServerEvent::Sync((mut sender, user_id)) => {
                let mut changes = vec![];

                // add a session to the session table
                let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
                changes.push(("sessions".to_owned(),
                    Change{
                        fields: vec!["sessions: id".to_owned(), "sessions: status".to_owned()],
                        insert: vec![vec![Value::String(session_id.clone()), Value::Float(1f64)]],
                        remove: vec![],
                    }));

                // if we have a user ID, add a mapping from the session ID to the user ID
                if let Some(user_id) = user_id {
                    changes.push(("session id to user id".to_owned(),
                        Change{
                            fields: vec!["session id to user id: session id".to_owned(), "session id to user id: user id".to_owned()],
                            insert: vec![vec![Value::String(session_id.clone()), Value::String(user_id)]],
                            remove: vec![]
                        }));
                }

                // handle the session change
                let event = Event{changes: changes, session: session_id.clone(), commands: vec![]};
                let json = event.to_json();
                handle_event(&mut server, event, json);

                // sync the new client
                let changes = server.flow.as_changes();
                let event = Event{changes: changes, session: session_id, commands: vec![]};
                let text = format!("{}", event.to_json());
                match sender.send_message(Message::Text(text)) {
                    Ok(_) => (),
                    Err(error) => println!("Send error: {}", error),
                };
                server.senders.push(sender)
            }

            // an existing client has sent a new message
            ServerEvent::Change(input_bytes) => {
                // TODO we throw cbor in here to avoid https://github.com/rust-lang/rustc-serialize/issues/113
                let mut decoder = cbor::Decoder::from_bytes(&input_bytes[..]);
                let cbor = decoder.items().next().unwrap().unwrap();
                let json = cbor.to_json();
                let event = FromJson::from_json(&json);
                handle_event(&mut server, event, json);
            }

            ServerEvent::Terminate(m) => {
                let terminate_ip = m.unwrap().reason;
                println!("Closing connection from {}...",terminate_ip);

                // find the index of the connection's sender
                let ip_ix = server.senders.iter_mut().position(|mut sender| {
                    let ip = format!("{}",sender.get_mut().peer_addr().unwrap());
                    ip == terminate_ip
                });

                match ip_ix {
                    Some(ix) => {
                        // close the connection
                        let _ = server.senders[ix].send_message(Message::Close(None));
                        match server.senders[ix].get_mut().shutdown(Shutdown::Both) {
                            Ok(_) => println!("Connection from {} has closed successfully.",terminate_ip),
                            Err(e) => println!("Connection from {} failed to shut down properly: {}",terminate_ip,e),
                        }
                        server.senders.remove(ix);

                        // update the session table
                        let sessions = server.flow.get_output("sessions").clone();
                        let ip_string = Value::String(terminate_ip.clone());

                        // change the session status to 0
                        for row in sessions.find(vec![&ip_string, &Value::Null]) {
                            match row {
                                [_, ref status] => {
                                    let change = Change {
                                        fields: sessions.fields.clone(),
                                        insert: vec![vec![ip_string.clone(), Value::Float(0f64)]],
                                        remove: vec![vec![ip_string.clone(), status.clone()]],
                                    };
                                    let event = Event{changes: vec![("sessions".to_string(),change)], session: "".to_string(), commands: vec![]};
                                    let json = event.to_json();
                                    handle_event(&mut server, event, json);
                                }
                                _ => unreachable!(),
                            }
                        }

                    },
                    None => panic!("IP address {} is not connected",terminate_ip),
                }
            }
        }
    }
}<|endoftext|>


<commit_before>use std::thread;
use std::sync::mpsc;
use websocket;
use websocket::{Message, Sender, Receiver};
use websocket::server::sender;
use websocket::stream::WebSocketStream;
use websocket::message::CloseData;
use std::io::prelude::*;
use std::fs::{OpenOptions};
use std::net::Shutdown;
use rustc_serialize::json::{Json, ToJson};
use cbor;
use hyper::header::Cookie;

use value::Value;
use relation::Change;
use flow::{Changes, Flow};
use client;

pub trait FromJson {
    fn from_json(json: &Json) -> Self;
}

impl ToJson for Value {
    fn to_json(&self) -> Json {
        match *self {
            Value::Null => panic!("Cannot allow the client to see nulls"),
            Value::Bool(bool) => Json::Boolean(bool),
            Value::String(ref string) => Json::String(string.clone()),
            Value::Float(float) => Json::F64(float),
            Value::Column(ref column) => Json::Array(column.iter().map(|v| v.to_json()).collect()),
        }
    }
}

impl FromJson for Value {
    fn from_json(json: &Json) -> Self {
        match *json {
            Json::Boolean(bool) => Value::Bool(bool),
            Json::String(ref string) => Value::String(string.clone()),
            Json::F64(float) => Value::Float(float),
            Json::I64(int) => Value::Float(int as f64),
            Json::U64(uint) => Value::Float(uint as f64),
            Json::Array(ref array) => Value::Column(array.iter().map(FromJson::from_json).collect()),
            _ => panic!("Cannot decode {:?} as Value", json),
        }
    }
}

impl FromJson for String {
    fn from_json(json: &Json) -> Self {
        json.as_string().unwrap().to_owned()
    }
}

impl<T: FromJson> FromJson for Vec<T> {
    fn from_json(json: &Json) -> Self {
        json.as_array().unwrap().iter().map(|t| FromJson::from_json(t)).collect()
    }
}

#[derive(Debug, Clone)]
pub struct Event {
    pub changes: Changes,
    pub session: String,
    pub commands: Vec<Vec<String>>,
}

impl ToJson for Event {
    fn to_json(&self) -> Json {
        Json::Object(vec![
            ("changes".to_string(), Json::Array(
                self.changes.iter().map(|&(ref view_id, ref view_changes)| {
                    Json::Array(vec![
                        view_id.to_json(),
                        view_changes.fields.to_json(),
                        view_changes.insert.to_json(),
                        view_changes.remove.to_json(),
                        ])
                }).collect()
                )
            ),
            ("session".to_string(), self.session.to_json()),
            ("commands".to_string(), self.commands.to_json()),
        ].into_iter().collect())
    }
}

impl FromJson for Event {
    fn from_json(json: &Json) -> Self {
        Event{
            changes: json.as_object().unwrap()["changes"]
            .as_array().unwrap().iter().map(|change| {
                let change = change.as_array().unwrap();
                assert_eq!(change.len(), 4);
                let view_id = FromJson::from_json(&change[0]);
                let fields = FromJson::from_json(&change[1]);
                let insert = FromJson::from_json(&change[2]);
                let remove = FromJson::from_json(&change[3]);
                (view_id, Change{fields:fields, insert: insert, remove: remove})
            }).collect(),
            session: "".to_string(),
            commands: FromJson::from_json(json.as_object().unwrap().get("commands").unwrap_or(&Json::Array(vec![]))),
        }
    }
}

pub enum ServerEvent {
    Change(Vec<u8>),
    Sync((sender::Sender<WebSocketStream>,Option<String>)),
    Terminate(Option<CloseData>),
}

// TODO holy crap why is everything blocking? this is a mess
pub fn server_events() -> mpsc::Receiver<ServerEvent> {
    let (event_sender, event_receiver) = mpsc::channel();
    thread::spawn(move || {
        let server = websocket::Server::bind("0.0.0.0:2794").unwrap();
        for connection in server {
            let event_sender = event_sender.clone();
            thread::spawn(move || {
                // accept request
                let request = connection.unwrap().read_request().unwrap();
                request.validate().unwrap();

                // Get the User ID from a cookie in the headers
                let user_id = get_user_id(request.headers.get::<Cookie>());

                let response = request.accept();
                let (mut sender, mut receiver) = response.send().unwrap().split();

                let ip = sender.get_mut().peer_addr().unwrap();
                println!("Connection from {}", ip);
                ::std::io::stdout().flush().unwrap(); // TODO is this actually necessary?

                // hand over sender
                event_sender.send(ServerEvent::Sync((sender,user_id))).unwrap();

                // handle messages
                for message in receiver.incoming_messages() {
                    let message = match message {
                        Ok(m) => m,
                        Err(_) => return,
                    };
                    match message {
                        Message::Binary(bytes) => {
                            event_sender.send(ServerEvent::Change(bytes)).unwrap();
                        }
                        Message::Close(_) => {
                            let ip_addr = format!("{}", ip);
                            println!("Received close message from {}.",ip_addr);
                            let close_message = CloseData{status_code: 0, reason: ip_addr};
                            event_sender.send(ServerEvent::Terminate(Some(close_message))).unwrap();
                        }
                        _ => println!("Unknown message: {:?}", message)
                    }
                }
            });
        }
    });
    event_receiver
}

pub fn load(flow: &mut Flow, filename: &str) {
    let mut events = OpenOptions::new().create(true).open(filename).unwrap();
    let mut old_events = String::new();
    events.read_to_string(&mut old_events).unwrap();
    for line in old_events.lines() {
        let json = Json::from_str(&line).unwrap();
        let event: Event = FromJson::from_json(&json);
        flow.quiesce(event.changes);
    }
}

pub fn save(flow: &Flow, filename: &str) {
    let changes = flow.as_changes();
    let text = format!("{}", Event{changes: changes, session: "".to_owned(), commands: vec![]}.to_json());
    let mut events = OpenOptions::new().create(true).truncate(true).write(true).open(filename).unwrap();
    events.write_all(text.as_bytes()).unwrap();
}

pub struct Server {
    pub flow: Flow,
    pub senders: Vec<sender::Sender<WebSocketStream>>,
}

pub fn handle_event(server: &mut Server, event: Event, event_json: Json) {
    let mut autosave = OpenOptions::new().write(true).append(true).open("./autosave").unwrap();
    autosave.write_all(format!("{}", event_json).as_bytes()).unwrap();
    autosave.write_all("\n".as_bytes()).unwrap();
    autosave.flush().unwrap();
    let old_flow = time!("cloning", {
        server.flow.clone()
    });
    server.flow.quiesce(event.changes);
    let changes = time!("diffing", {
        server.flow.changes_from(old_flow)
    });
    for command in event.commands.iter() {
        let borrowed_words = command.iter().map(|word| &word[..]).collect::<Vec<_>>();
        match &borrowed_words[..] {
            ["load", filename] => {
                server.flow = Flow::new();
                load(&mut server.flow, "./bootstrap");
                load(&mut server.flow, filename);
                save(&server.flow, "./autosave");
            }
            ["save", filename] => {
                save(&server.flow, filename);
            }
            other => panic!("Unknown command: {:?}", other),
        }
    }
    for sender in server.senders.iter_mut() {
        let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
        let text = format!("{}", Event{changes: changes.clone(), session: session_id, commands: vec![]}.to_json());
        match sender.send_message(Message::Text(text)) {
            Ok(_) => (),
            Err(error) => println!("Send error: {}", error),
        };
    }
}

pub fn run() {
    let mut flow = Flow::new();
    time!("reading saved state", {
        load(&mut flow, "./bootstrap");
        load(&mut flow, "./autosave");
    });

    let senders: Vec<sender::Sender<WebSocketStream>> = Vec::new();

    let mut server = Server{flow: flow, senders: senders};

    for server_event in server_events() {
        match server_event {

            ServerEvent::Sync((mut sender,user_id)) => {

                // Add a session to the session table
                let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
				let mut add_session = client::insert_fact(&"sessions",&vec!["id","status"],&vec![Value::String(session_id.clone()),
				                                                                       		   Value::Float(1f64)
				                                                                      	     ],None);

				// If we have a user ID, add a mapping from the session ID to the user ID
                add_session = match user_id {
                    Some(user_id) => {

                        client::insert_fact(&"session id to user id",&vec!["session id","user id"],&vec![Value::String(session_id.clone()),
                                                                                Value::String(user_id),
                                                                                ],Some(add_session))
                    },
                    None => add_session,
                };
                let json = add_session.to_json();
                handle_event(&mut server, add_session, json);

                let changes = server.flow.as_changes();
                let text = format!("{}", Event{changes: changes, session: session_id, commands: vec![]}.to_json());
                match sender.send_message(Message::Text(text)) {
                    Ok(_) => (),
                    Err(error) => println!("Send error: {}", error),
                };
                server.senders.push(sender)
            }

            ServerEvent::Change(input_bytes) => {
                // TODO we throw cbor in here to avoid https://github.com/rust-lang/rustc-serialize/issues/113
                let mut decoder = cbor::Decoder::from_bytes(&input_bytes[..]);
                let cbor = decoder.items().next().unwrap().unwrap();
                let json = cbor.to_json();
                let event = FromJson::from_json(&json);
                handle_event(&mut server, event, json);
            }

            ServerEvent::Terminate(m) => {

                let terminate_ip = m.unwrap().reason;
                println!("Closing connection from {}...",terminate_ip);
                // Find the index of the connection's sender
                let ip_ix = server.senders.iter_mut().position(|mut sender| {
                                                          let ip = format!("{}",sender.get_mut().peer_addr().unwrap());
                                                          ip == terminate_ip
                                                        });

                // Properly clean up connections and the session table
                match ip_ix {
                    Some(ix) => {
                        // Close the connection
                        let _ = server.senders[ix].send_message(Message::Close(None));

                        match server.senders[ix].get_mut().shutdown(Shutdown::Both) {
                            Ok(_) => println!("Connection from {} has closed successfully.",terminate_ip),
                            Err(e) => println!("Connection from {} failed to shut down properly: {}",terminate_ip,e),
                        }
                        server.senders.remove(ix);

                        // Update the session table
                        let sessions = server.flow.get_output("sessions").clone();
                        let ip_string = Value::String(terminate_ip.clone());

                        for row in sessions.find(vec![&ip_string, &Value::Null]) {
                            match row {
                                [_, ref status] => {
                                    let change = Change {
                                        fields: sessions.fields.clone(),
                                        insert: vec![vec![ip_string.clone(), Value::Float(0f64)]],
                                        remove: vec![vec![ip_string.clone(), status.clone()]],
                                    };
                                    let event = Event{changes: vec![("sessions".to_string(),change)], session: "".to_string(), commands: vec![]};
                                    let json = event.to_json();
                                    handle_event(&mut server, event, json);
                                }
                                _ => unreachable!(),
                            }
                        }

                    },
                    None => panic!("IP address {} is not connected",terminate_ip),
                }
            }
        }
    }
}

pub fn get_user_id(cookies: Option<&Cookie>) -> Option<String> {
    match cookies {
        Some(cookies) => {
            match cookies.iter().find(|cookie| cookie.name == "userid") {
                Some(user_id) => Some(user_id.value.clone()),
                None => None,
            }
        },
        None => None,
    }
}<commit_msg>Diff after load<commit_after>use std::thread;
use std::sync::mpsc;
use websocket;
use websocket::{Message, Sender, Receiver};
use websocket::server::sender;
use websocket::stream::WebSocketStream;
use websocket::message::CloseData;
use std::io::prelude::*;
use std::fs::{OpenOptions};
use std::net::Shutdown;
use rustc_serialize::json::{Json, ToJson};
use cbor;
use hyper::header::Cookie;

use value::Value;
use relation::Change;
use flow::{Changes, Flow};
use client;

pub trait FromJson {
    fn from_json(json: &Json) -> Self;
}

impl ToJson for Value {
    fn to_json(&self) -> Json {
        match *self {
            Value::Null => panic!("Cannot allow the client to see nulls"),
            Value::Bool(bool) => Json::Boolean(bool),
            Value::String(ref string) => Json::String(string.clone()),
            Value::Float(float) => Json::F64(float),
            Value::Column(ref column) => Json::Array(column.iter().map(|v| v.to_json()).collect()),
        }
    }
}

impl FromJson for Value {
    fn from_json(json: &Json) -> Self {
        match *json {
            Json::Boolean(bool) => Value::Bool(bool),
            Json::String(ref string) => Value::String(string.clone()),
            Json::F64(float) => Value::Float(float),
            Json::I64(int) => Value::Float(int as f64),
            Json::U64(uint) => Value::Float(uint as f64),
            Json::Array(ref array) => Value::Column(array.iter().map(FromJson::from_json).collect()),
            _ => panic!("Cannot decode {:?} as Value", json),
        }
    }
}

impl FromJson for String {
    fn from_json(json: &Json) -> Self {
        json.as_string().unwrap().to_owned()
    }
}

impl<T: FromJson> FromJson for Vec<T> {
    fn from_json(json: &Json) -> Self {
        json.as_array().unwrap().iter().map(|t| FromJson::from_json(t)).collect()
    }
}

#[derive(Debug, Clone)]
pub struct Event {
    pub changes: Changes,
    pub session: String,
    pub commands: Vec<Vec<String>>,
}

impl ToJson for Event {
    fn to_json(&self) -> Json {
        Json::Object(vec![
            ("changes".to_string(), Json::Array(
                self.changes.iter().map(|&(ref view_id, ref view_changes)| {
                    Json::Array(vec![
                        view_id.to_json(),
                        view_changes.fields.to_json(),
                        view_changes.insert.to_json(),
                        view_changes.remove.to_json(),
                        ])
                }).collect()
                )
            ),
            ("session".to_string(), self.session.to_json()),
            ("commands".to_string(), self.commands.to_json()),
        ].into_iter().collect())
    }
}

impl FromJson for Event {
    fn from_json(json: &Json) -> Self {
        Event{
            changes: json.as_object().unwrap()["changes"]
            .as_array().unwrap().iter().map(|change| {
                let change = change.as_array().unwrap();
                assert_eq!(change.len(), 4);
                let view_id = FromJson::from_json(&change[0]);
                let fields = FromJson::from_json(&change[1]);
                let insert = FromJson::from_json(&change[2]);
                let remove = FromJson::from_json(&change[3]);
                (view_id, Change{fields:fields, insert: insert, remove: remove})
            }).collect(),
            session: "".to_string(),
            commands: FromJson::from_json(json.as_object().unwrap().get("commands").unwrap_or(&Json::Array(vec![]))),
        }
    }
}

pub enum ServerEvent {
    Change(Vec<u8>),
    Sync((sender::Sender<WebSocketStream>,Option<String>)),
    Terminate(Option<CloseData>),
}

// TODO holy crap why is everything blocking? this is a mess
pub fn server_events() -> mpsc::Receiver<ServerEvent> {
    let (event_sender, event_receiver) = mpsc::channel();
    thread::spawn(move || {
        let server = websocket::Server::bind("0.0.0.0:2794").unwrap();
        for connection in server {
            let event_sender = event_sender.clone();
            thread::spawn(move || {
                // accept request
                let request = connection.unwrap().read_request().unwrap();
                request.validate().unwrap();

                // Get the User ID from a cookie in the headers
                let user_id = get_user_id(request.headers.get::<Cookie>());

                let response = request.accept();
                let (mut sender, mut receiver) = response.send().unwrap().split();

                let ip = sender.get_mut().peer_addr().unwrap();
                println!("Connection from {}", ip);
                ::std::io::stdout().flush().unwrap(); // TODO is this actually necessary?

                // hand over sender
                event_sender.send(ServerEvent::Sync((sender,user_id))).unwrap();

                // handle messages
                for message in receiver.incoming_messages() {
                    let message = match message {
                        Ok(m) => m,
                        Err(_) => return,
                    };
                    match message {
                        Message::Binary(bytes) => {
                            event_sender.send(ServerEvent::Change(bytes)).unwrap();
                        }
                        Message::Close(_) => {
                            let ip_addr = format!("{}", ip);
                            println!("Received close message from {}.",ip_addr);
                            let close_message = CloseData{status_code: 0, reason: ip_addr};
                            event_sender.send(ServerEvent::Terminate(Some(close_message))).unwrap();
                        }
                        _ => println!("Unknown message: {:?}", message)
                    }
                }
            });
        }
    });
    event_receiver
}

pub fn load(flow: &mut Flow, filename: &str) {
    let mut events = OpenOptions::new().create(true).open(filename).unwrap();
    let mut old_events = String::new();
    events.read_to_string(&mut old_events).unwrap();
    for line in old_events.lines() {
        let json = Json::from_str(&line).unwrap();
        let event: Event = FromJson::from_json(&json);
        flow.quiesce(event.changes);
    }
}

pub fn save(flow: &Flow, filename: &str) {
    let changes = flow.as_changes();
    let text = format!("{}", Event{changes: changes, session: "".to_owned(), commands: vec![]}.to_json());
    let mut events = OpenOptions::new().create(true).truncate(true).write(true).open(filename).unwrap();
    events.write_all(text.as_bytes()).unwrap();
}

pub struct Server {
    pub flow: Flow,
    pub senders: Vec<sender::Sender<WebSocketStream>>,
}

pub fn handle_event(server: &mut Server, event: Event, event_json: Json) {
    let mut autosave = OpenOptions::new().write(true).append(true).open("./autosave").unwrap();
    autosave.write_all(format!("{}", event_json).as_bytes()).unwrap();
    autosave.write_all("\n".as_bytes()).unwrap();
    autosave.flush().unwrap();
    let old_flow = time!("cloning", {
        server.flow.clone()
    });
    server.flow.quiesce(event.changes);
    for command in event.commands.iter() {
        let borrowed_words = command.iter().map(|word| &word[..]).collect::<Vec<_>>();
        match &borrowed_words[..] {
            ["load", filename] => {
                server.flow = Flow::new();
                load(&mut server.flow, "./bootstrap");
                load(&mut server.flow, filename);
                save(&server.flow, "./autosave");
            }
            ["save", filename] => {
                save(&server.flow, filename);
            }
            other => panic!("Unknown command: {:?}", other),
        }
    }
    let changes = time!("diffing", {
        server.flow.changes_from(old_flow)
    });
    for sender in server.senders.iter_mut() {
        let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
        let text = format!("{}", Event{changes: changes.clone(), session: session_id, commands: vec![]}.to_json());
        match sender.send_message(Message::Text(text)) {
            Ok(_) => (),
            Err(error) => println!("Send error: {}", error),
        };
    }
}

pub fn run() {
    let mut flow = Flow::new();
    time!("reading saved state", {
        load(&mut flow, "./bootstrap");
        load(&mut flow, "./autosave");
    });

    let senders: Vec<sender::Sender<WebSocketStream>> = Vec::new();

    let mut server = Server{flow: flow, senders: senders};

    for server_event in server_events() {
        match server_event {

            ServerEvent::Sync((mut sender,user_id)) => {

                // Add a session to the session table
                let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
				let mut add_session = client::insert_fact(&"sessions",&vec!["id","status"],&vec![Value::String(session_id.clone()),
				                                                                       		   Value::Float(1f64)
				                                                                      	     ],None);

				// If we have a user ID, add a mapping from the session ID to the user ID
                add_session = match user_id {
                    Some(user_id) => {

                        client::insert_fact(&"session id to user id",&vec!["session id","user id"],&vec![Value::String(session_id.clone()),
                                                                                Value::String(user_id),
                                                                                ],Some(add_session))
                    },
                    None => add_session,
                };
                let json = add_session.to_json();
                handle_event(&mut server, add_session, json);

                let changes = server.flow.as_changes();
                let text = format!("{}", Event{changes: changes, session: session_id, commands: vec![]}.to_json());
                match sender.send_message(Message::Text(text)) {
                    Ok(_) => (),
                    Err(error) => println!("Send error: {}", error),
                };
                server.senders.push(sender)
            }

            ServerEvent::Change(input_bytes) => {
                // TODO we throw cbor in here to avoid https://github.com/rust-lang/rustc-serialize/issues/113
                let mut decoder = cbor::Decoder::from_bytes(&input_bytes[..]);
                let cbor = decoder.items().next().unwrap().unwrap();
                let json = cbor.to_json();
                let event = FromJson::from_json(&json);
                handle_event(&mut server, event, json);
            }

            ServerEvent::Terminate(m) => {

                let terminate_ip = m.unwrap().reason;
                println!("Closing connection from {}...",terminate_ip);
                // Find the index of the connection's sender
                let ip_ix = server.senders.iter_mut().position(|mut sender| {
                                                          let ip = format!("{}",sender.get_mut().peer_addr().unwrap());
                                                          ip == terminate_ip
                                                        });

                // Properly clean up connections and the session table
                match ip_ix {
                    Some(ix) => {
                        // Close the connection
                        let _ = server.senders[ix].send_message(Message::Close(None));

                        match server.senders[ix].get_mut().shutdown(Shutdown::Both) {
                            Ok(_) => println!("Connection from {} has closed successfully.",terminate_ip),
                            Err(e) => println!("Connection from {} failed to shut down properly: {}",terminate_ip,e),
                        }
                        server.senders.remove(ix);

                        // Update the session table
                        let sessions = server.flow.get_output("sessions").clone();
                        let ip_string = Value::String(terminate_ip.clone());

                        for row in sessions.find(vec![&ip_string, &Value::Null]) {
                            match row {
                                [_, ref status] => {
                                    let change = Change {
                                        fields: sessions.fields.clone(),
                                        insert: vec![vec![ip_string.clone(), Value::Float(0f64)]],
                                        remove: vec![vec![ip_string.clone(), status.clone()]],
                                    };
                                    let event = Event{changes: vec![("sessions".to_string(),change)], session: "".to_string(), commands: vec![]};
                                    let json = event.to_json();
                                    handle_event(&mut server, event, json);
                                }
                                _ => unreachable!(),
                            }
                        }

                    },
                    None => panic!("IP address {} is not connected",terminate_ip),
                }
            }
        }
    }
}

pub fn get_user_id(cookies: Option<&Cookie>) -> Option<String> {
    match cookies {
        Some(cookies) => {
            match cookies.iter().find(|cookie| cookie.name == "userid") {
                Some(user_id) => Some(user_id.value.clone()),
                None => None,
            }
        },
        None => None,
    }
}<|endoftext|>


<commit_before>use std::thread;
use std::sync::mpsc;
use websocket::{Server, Message, Sender, Receiver};
use websocket::server::sender;
use websocket::stream::WebSocketStream;
use websocket::message::CloseData;
use std::io::prelude::*;
use std::fs::OpenOptions;
use std::net::Shutdown;
use rustc_serialize::json::{Json, ToJson};

use value::Value;
use relation::Change;
use flow::{Changes, Flow};

trait FromJson {
    fn from_json(json: &Json) -> Self;
}

impl ToJson for Value {
    fn to_json(&self) -> Json {
        match *self {
            Value::Null => panic!("Cannot allow the client to see nulls"),
            Value::Bool(bool) => Json::Boolean(bool),
            Value::String(ref string) => Json::String(string.clone()),
            Value::Float(float) => Json::F64(float),
        }
    }
}

impl FromJson for Value {
    fn from_json(json: &Json) -> Self {
        match *json {
            Json::Boolean(bool) => Value::Bool(bool),
            Json::String(ref string) => Value::String(string.clone()),
            Json::F64(float) => Value::Float(float),
            Json::I64(int) => Value::Float(int as f64),
            Json::U64(uint) => Value::Float(uint as f64),
            _ => panic!("Cannot decode {:?} as Value", json),
        }
    }
}

impl FromJson for String {
    fn from_json(json: &Json) -> Self {
        json.as_string().unwrap().to_owned()
    }
}

impl<T: FromJson> FromJson for Vec<T> {
    fn from_json(json: &Json) -> Self {
        json.as_array().unwrap().iter().map(|t| FromJson::from_json(t)).collect()
    }
}

pub struct Event {
    pub changes: Changes,
}

impl ToJson for Event {
    fn to_json(&self) -> Json {
        Json::Object(vec![
            ("changes".to_string(), Json::Array(
                self.changes.iter().map(|&(ref view_id, ref view_changes)| {
                    Json::Array(vec![
                        view_id.to_json(),
                        view_changes.fields.to_json(),
                        view_changes.insert.to_json(),
                        view_changes.remove.to_json(),
                        ])
                }).collect())
            )].into_iter().collect())
    }
}

impl FromJson for Event {
    fn from_json(json: &Json) -> Self {
        Event{
            changes: json.as_object().unwrap()["changes"]
            .as_array().unwrap().iter().map(|change| {
                let change = change.as_array().unwrap();
                assert_eq!(change.len(), 4);
                let view_id = FromJson::from_json(&change[0]);
                let fields = FromJson::from_json(&change[1]);
                let insert = FromJson::from_json(&change[2]);
                let remove = FromJson::from_json(&change[3]);
                (view_id, Change{fields:fields, insert: insert, remove: remove})
            }).collect()
        }
    }
}

pub enum ServerEvent {
    Change(String),
    Sync(sender::Sender<WebSocketStream>),
    Terminate(Option<CloseData>),
}

// TODO holy crap why is everything blocking? this is a mess
pub fn serve() -> mpsc::Receiver<ServerEvent> {
    let (event_sender, event_receiver) = mpsc::channel();
    thread::spawn(move || {
        let server = Server::bind("0.0.0.0:2794").unwrap();
        for connection in server {
            let event_sender = event_sender.clone();
            thread::spawn(move || {
                // accept request
                let request = connection.unwrap().read_request().unwrap();
                request.validate().unwrap();
                let response = request.accept();
                let (mut sender, mut receiver) = response.send().unwrap().split();

                let ip = sender.get_mut().peer_addr().unwrap();
                println!("Connection from {}", ip);
                ::std::io::stdout().flush().unwrap(); // TODO is this actually necessary?

                // hand over sender
                event_sender.send(ServerEvent::Sync(sender)).unwrap();

                // handle messages
                for message in receiver.incoming_messages() {
                    let message = match message {
                        Ok(m) => m,
                        Err(_) => return,
                    };
                    match message {
                        Message::Text(text) => {
                            event_sender.send(ServerEvent::Change(text)).unwrap();
                        }
                        Message::Close(_) => {
                            let ip_addr = format!("{}", ip);
                            println!("Received close message from {}.",ip_addr);
                            let close_message = CloseData{status_code: 0, reason: ip_addr};
                            event_sender.send(ServerEvent::Terminate(Some(close_message))).unwrap();
                        }
                        _ => println!("Unknown message: {:?}", message)
                    }
                }
            });
        }
    });
    event_receiver
}

pub fn run() {
    let mut flow = Flow::new();

    time!("reading saved state", {
        let mut events = OpenOptions::new().create(true).open("./events").unwrap();
        let mut old_events = String::new();
        events.read_to_string(&mut old_events).unwrap();
        for line in old_events.lines() {
            let json = Json::from_str(&line).unwrap();
            let event: Event = FromJson::from_json(&json);
            flow = flow.quiesce(event.changes);
        }
    });

    let mut events = OpenOptions::new().write(true).append(true).open("./events").unwrap();
    let mut senders: Vec<sender::Sender<_>> = Vec::new();
    for server_event in serve() {
        match server_event {

            ServerEvent::Sync(mut sender) => {
                time!("syncing", {
                    let changes = flow.as_changes();
                    let text = format!("{}", Event{changes: changes}.to_json());
                    match sender.send_message(Message::Text(text)) {
                        Ok(_) => (),
                        Err(error) => println!("Send error: {}", error),
                    };
                    senders.push(sender)
                })
            }

            ServerEvent::Change(input_text) => {
                time!("changing", {
                    let json = Json::from_str(&input_text).unwrap();
                    let event: Event = FromJson::from_json(&json);
                    events.write_all(input_text.as_bytes()).unwrap();
                    events.write_all("\n".as_bytes()).unwrap();
                    let old_flow = flow.clone();
                    flow = flow.quiesce(event.changes);
                    let changes = flow.changes_from(old_flow);
                    let output_text = format!("{}", Event{changes: changes}.to_json());
                    events.flush().unwrap();
                    for sender in senders.iter_mut() {
                        match sender.send_message(Message::Text(output_text.clone())) {
                            Ok(_) => (),
                            Err(error) => println!("Send error: {}", error),
                        };
                    }
                })
            }

            ServerEvent::Terminate(m) => {
                let terminate_ip = m.unwrap().reason;
                println!("Closing connection from {}....",terminate_ip);
                let ip_ix = senders.iter_mut().position(|mut sender| {
                                                          let ip = sender.get_mut().peer_addr().unwrap();
                                                          let ip_addr = format!("{}", ip);
                                                          ip_addr == terminate_ip
                                                     });
                match ip_ix {
                    Some(ix) => {
                        match senders[ix].get_mut().shutdown(Shutdown::Both) {
                            Ok(_) => {
                                senders.remove(ix);
                                println!("Connection from {} has closed successfully.",terminate_ip);
                            },
                            Err(_) => println!("Connection from {} failed to shut down!",terminate_ip),
                        }
                    },
                    None => panic!("IP address {} is not connected",terminate_ip),
                }
            }

        }
    }
}
<commit_msg>Close loop on closing a connection.<commit_after>use std::thread;
use std::sync::mpsc;
use websocket::{Server, Message, Sender, Receiver};
use websocket::server::sender;
use websocket::stream::WebSocketStream;
use websocket::message::CloseData;
use std::io::prelude::*;
use std::fs::OpenOptions;
use std::net::Shutdown;
use rustc_serialize::json::{Json, ToJson};

use value::Value;
use relation::Change;
use flow::{Changes, Flow};

trait FromJson {
    fn from_json(json: &Json) -> Self;
}

impl ToJson for Value {
    fn to_json(&self) -> Json {
        match *self {
            Value::Null => panic!("Cannot allow the client to see nulls"),
            Value::Bool(bool) => Json::Boolean(bool),
            Value::String(ref string) => Json::String(string.clone()),
            Value::Float(float) => Json::F64(float),
        }
    }
}

impl FromJson for Value {
    fn from_json(json: &Json) -> Self {
        match *json {
            Json::Boolean(bool) => Value::Bool(bool),
            Json::String(ref string) => Value::String(string.clone()),
            Json::F64(float) => Value::Float(float),
            Json::I64(int) => Value::Float(int as f64),
            Json::U64(uint) => Value::Float(uint as f64),
            _ => panic!("Cannot decode {:?} as Value", json),
        }
    }
}

impl FromJson for String {
    fn from_json(json: &Json) -> Self {
        json.as_string().unwrap().to_owned()
    }
}

impl<T: FromJson> FromJson for Vec<T> {
    fn from_json(json: &Json) -> Self {
        json.as_array().unwrap().iter().map(|t| FromJson::from_json(t)).collect()
    }
}

pub struct Event {
    pub changes: Changes,
}

impl ToJson for Event {
    fn to_json(&self) -> Json {
        Json::Object(vec![
            ("changes".to_string(), Json::Array(
                self.changes.iter().map(|&(ref view_id, ref view_changes)| {
                    Json::Array(vec![
                        view_id.to_json(),
                        view_changes.fields.to_json(),
                        view_changes.insert.to_json(),
                        view_changes.remove.to_json(),
                        ])
                }).collect())
            )].into_iter().collect())
    }
}

impl FromJson for Event {
    fn from_json(json: &Json) -> Self {
        Event{
            changes: json.as_object().unwrap()["changes"]
            .as_array().unwrap().iter().map(|change| {
                let change = change.as_array().unwrap();
                assert_eq!(change.len(), 4);
                let view_id = FromJson::from_json(&change[0]);
                let fields = FromJson::from_json(&change[1]);
                let insert = FromJson::from_json(&change[2]);
                let remove = FromJson::from_json(&change[3]);
                (view_id, Change{fields:fields, insert: insert, remove: remove})
            }).collect()
        }
    }
}

pub enum ServerEvent {
    Change(String),
    Sync(sender::Sender<WebSocketStream>),
    Terminate(Option<CloseData>),
}

// TODO holy crap why is everything blocking? this is a mess
pub fn serve() -> mpsc::Receiver<ServerEvent> {
    let (event_sender, event_receiver) = mpsc::channel();
    thread::spawn(move || {
        let server = Server::bind("0.0.0.0:2794").unwrap();
        for connection in server {
            let event_sender = event_sender.clone();
            thread::spawn(move || {
                // accept request
                let request = connection.unwrap().read_request().unwrap();
                request.validate().unwrap();
                let response = request.accept();
                let (mut sender, mut receiver) = response.send().unwrap().split();

                let ip = sender.get_mut().peer_addr().unwrap();
                println!("Connection from {}", ip);
                ::std::io::stdout().flush().unwrap(); // TODO is this actually necessary?

                // hand over sender
                event_sender.send(ServerEvent::Sync(sender)).unwrap();

                // handle messages
                for message in receiver.incoming_messages() {
                    let message = match message {
                        Ok(m) => m,
                        Err(_) => return,
                    };
                    match message {
                        Message::Text(text) => {
                            event_sender.send(ServerEvent::Change(text)).unwrap();
                        }
                        Message::Close(_) => {
                            let ip_addr = format!("{}", ip);
                            println!("Received close message from {}.",ip_addr);
                            let close_message = CloseData{status_code: 0, reason: ip_addr};
                            event_sender.send(ServerEvent::Terminate(Some(close_message))).unwrap();
                        }
                        _ => println!("Unknown message: {:?}", message)
                    }
                }
            });
        }
    });
    event_receiver
}

pub fn run() {
    let mut flow = Flow::new();

    time!("reading saved state", {
        let mut events = OpenOptions::new().create(true).open("./events").unwrap();
        let mut old_events = String::new();
        events.read_to_string(&mut old_events).unwrap();
        for line in old_events.lines() {
            let json = Json::from_str(&line).unwrap();
            let event: Event = FromJson::from_json(&json);
            flow = flow.quiesce(event.changes);
        }
    });

    let mut events = OpenOptions::new().write(true).append(true).open("./events").unwrap();
    let mut senders: Vec<sender::Sender<_>> = Vec::new();
    for server_event in serve() {
        match server_event {

            ServerEvent::Sync(mut sender) => {
                time!("syncing", {
                    let changes = flow.as_changes();
                    let text = format!("{}", Event{changes: changes}.to_json());
                    match sender.send_message(Message::Text(text)) {
                        Ok(_) => (),
                        Err(error) => println!("Send error: {}", error),
                    };
                    senders.push(sender)
                })
            }

            ServerEvent::Change(input_text) => {
                time!("changing", {
                    let json = Json::from_str(&input_text).unwrap();
                    let event: Event = FromJson::from_json(&json);
                    events.write_all(input_text.as_bytes()).unwrap();
                    events.write_all("\n".as_bytes()).unwrap();
                    let old_flow = flow.clone();
                    flow = flow.quiesce(event.changes);
                    let changes = flow.changes_from(old_flow);
                    let output_text = format!("{}", Event{changes: changes}.to_json());
                    events.flush().unwrap();
                    for sender in senders.iter_mut() {
                        match sender.send_message(Message::Text(output_text.clone())) {
                            Ok(_) => (),
                            Err(error) => println!("Send error: {}", error),
                        };
                    }
                })
            }

            ServerEvent::Terminate(m) => {
                let terminate_ip = m.unwrap().reason;
                println!("Closing connection from {}....",terminate_ip);
                let ip_ix = senders.iter_mut().position(|mut sender| {
                                                          let ip = sender.get_mut().peer_addr().unwrap();
                                                          let ip_addr = format!("{}", ip);
                                                          ip_addr == terminate_ip
                                                     });
                match ip_ix {
                    Some(ix) => {
                        senders[ix].send_message(Message::Close(None)).unwrap();
                        match senders[ix].get_mut().shutdown(Shutdown::Both) {
                            Ok(_) => {
                                senders.remove(ix);
                                println!("Connection from {} has closed successfully.",terminate_ip);
                            },
                            Err(_) => println!("Connection from {} failed to shut down!",terminate_ip),
                        }
                    },
                    None => panic!("IP address {} is not connected",terminate_ip),
                }
            }

        }
    }
}
<|endoftext|>


<commit_before>use async_trait::async_trait;
use eyre::{bail, Result};
use serde::{Deserialize, Serialize};
use std::path::Path;
use stencila_schema::Node;
use tokio::{
    fs::File,
    io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, BufReader, BufWriter},
};
use utils::vec_string;

// Re-export for the convenience of crates that implement `CodecTrait`
pub use ::async_trait;
pub use eyre;
pub use serde;
pub use stencila_schema;
pub use utils;

/// A specification for codecs
///
/// All codecs, including those implemented in plugins, should provide this
/// specification. Rust implementations return a `Codec` instance from the
/// `spec` function of `CodecTrait`. Plugins provide a JSON or YAML serialization
/// as part of their manifest.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, rename_all = "camelCase")]
pub struct Codec {
    /// A list of format names (or aliases) that the codec can decode from
    /// or encode to
    pub formats: Vec<String>,

    /// Whether the codec supports decoding from string content
    pub from_string: bool,

    /// Whether the codec supports decoding from a file system path
    pub from_path: bool,

    /// Whether the codec supports encoding to string content
    pub to_string: bool,

    /// Whether the codec supports encoding to a file system path
    pub to_path: bool,

    /// A list of root node types that the codec can encode / decode
    ///
    /// Most codecs usually only handle one root type e.g. `Article`.
    /// Used to provide a list of formats to the user that support
    /// the current document type.
    pub root_types: Vec<String>,

    /// A list of node types that the codec does not support
    ///
    /// Used to provide warnings to the user on potential loss of content
    /// when encoding using the codec.
    pub unsupported_types: Vec<String>,

    /// A list of node properties that the codec does not support
    ///
    /// The format for these strings is `<type>.<property>` e.g. `Article.funders`
    /// Used to provide warnings to the user on potential loss of content
    /// when encoding using the codec.
    pub unsupported_properties: Vec<String>,

    /// The status of the codec e.g. `alpha`, `beta`, `stable`
    pub status: String,
}

impl Default for Codec {
    fn default() -> Self {
        Self {
            formats: vec![],
            from_string: true,
            from_path: true,
            to_string: true,
            to_path: true,
            root_types: vec_string!["Article"],
            unsupported_types: vec![],
            unsupported_properties: vec![],
            status: "alpha".to_string(),
        }
    }
}

/// A trait for codecs
///
/// This trait can be used by Rust implementations of codecs, allowing them to
/// be compiled into the Stencila binaries.
///
/// It defines similar functions to `serde_json` (and other `serde_` crates) for
/// converting nodes to/from strings, files, readers etc.
#[async_trait]
pub trait CodecTrait {
    /// Get the [`Codec`] specification for this implementation
    fn spec() -> Codec;

    /// Decode a document node from a string
    fn from_str(_str: &str, _options: Option<DecodeOptions>) -> Result<Node> {
        bail!("Decoding from string is not implemented for this format")
    }

    /// Decode a document node from a string asynchronously
    async fn from_str_async(str: &str, options: Option<DecodeOptions>) -> Result<Node> {
        Self::from_str(str, options)
    }

    /// Decode a document node from a `BufReader`
    async fn from_buffer<T: AsyncRead>(
        reader: &mut BufReader<T>,
        options: Option<DecodeOptions>,
    ) -> Result<Node>
    where
        T: Send + Sync + Unpin,
    {
        let mut content = String::new();
        reader.read_to_string(&mut content).await?;
        Self::from_str_async(&content, options).await
    }

    /// Decode a document node from a file
    ///
    /// This function reads the file as a string and passes that on to `from_str`
    /// for decoding. If working with binary formats, you should override this function
    /// to read the file as bytes instead.
    async fn from_file(file: &mut File, options: Option<DecodeOptions>) -> Result<Node> {
        let mut content = String::new();
        file.read_to_string(&mut content).await?;
        Self::from_str_async(&content, options).await
    }

    /// Decode a document node from a file system path
    async fn from_path(path: &Path, options: Option<DecodeOptions>) -> Result<Node> {
        let mut file = File::open(path).await?;
        Self::from_file(&mut file, options).await
    }

    /// Encode a document node to a string
    fn to_string(_node: &Node, _options: Option<EncodeOptions>) -> Result<String> {
        bail!("Encoding to string is not implemented for this format")
    }

    /// Encode a document node to a string asynchronously
    async fn to_string_async(node: &Node, options: Option<EncodeOptions>) -> Result<String> {
        Self::to_string(node, options)
    }

    /// Encode a document node to a `BufWriter`
    async fn to_buffer<T: AsyncWrite>(
        node: &Node,
        writer: &mut BufWriter<T>,
        options: Option<EncodeOptions>,
    ) -> Result<()>
    where
        T: Send + Sync + Unpin,
    {
        let content = Self::to_string_async(node, options).await?;
        writer.write_all(content.as_bytes()).await?;
        Ok(())
    }

    /// Encode a document node to a file
    async fn to_file(node: &Node, file: &mut File, options: Option<EncodeOptions>) -> Result<()> {
        let content = Self::to_string_async(node, options).await?;
        file.write_all(content.as_bytes()).await?;
        Ok(())
    }

    /// Encode a document node to a file system path
    async fn to_path(node: &Node, path: &Path, options: Option<EncodeOptions>) -> Result<()> {
        let mut file = File::create(path).await?;
        Self::to_file(node, &mut file, options).await
    }
}

/// Decoding options
///
/// Decoding functions (including those in plugins) are encouraged to respect these options
/// but are not required to.
#[derive(Clone)]
pub struct DecodeOptions {
    /// The format of the input to be decoded
    ///
    /// Most codecs only decode one format. However, for those that handle multiple
    /// format it may be necessary to specify this option.
    pub format: Option<String>,
}

impl Default for DecodeOptions {
    fn default() -> Self {
        Self { format: None }
    }
}

/// Encoding options
///
/// Encoding functions (including those in plugins) are encouraged to respect these options
/// but are not required to. Indeed, some options do not apply for some formats.
/// For example, a PDF is always `standalone` (so if that option is set to `false` is it will be ignored).
/// Futhermore, some combinations of options are ineffectual e.g. a `theme` when `standalone: false`
#[derive(Clone)]
pub struct EncodeOptions {
    /// Whether to encode in compact form.
    ///
    /// Some formats (e.g HTML and JSON) can be encoded in either compact
    /// or "pretty-printed" ie.e. indented forms.
    pub compact: bool,

    /// Whether to ensure that the encoded document is standalone.
    ///
    /// Some formats (e.g. Markdown, DOCX) are always standalone, others
    /// can be frangments, or standalong documents (e.g HTML).
    pub standalone: bool,

    /// Whether to bundle local media files into the encoded document
    ///
    /// Some formats (e.g. DOCX, PDF) always bundle. For HTML,
    /// bundling means including media as data URIs rather than
    /// links to files.
    pub bundle: bool,

    /// The theme to apply to the encoded document
    ///
    /// Only applies to some formats (e.g. HTML, PDF, PNG).
    pub theme: String,

    /// The format to encode to
    ///
    /// Most codecs only encode to one format. However, for those that handle multiple
    /// formats it may be necessary to specify this option.
    pub format: Option<String>,
}

impl Default for EncodeOptions {
    fn default() -> Self {
        Self {
            compact: true,
            standalone: false,
            bundle: false,
            theme: "stencila".to_string(),
            format: None,
        }
    }
}
<commit_msg>fix(Codec): Always ensure parent directory is created<commit_after>use async_trait::async_trait;
use eyre::{bail, Result};
use serde::{Deserialize, Serialize};
use std::{path::Path, fs::create_dir_all};
use stencila_schema::Node;
use tokio::{
    fs::File,
    io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, BufReader, BufWriter},
};
use utils::vec_string;

// Re-export for the convenience of crates that implement `CodecTrait`
pub use ::async_trait;
pub use eyre;
pub use serde;
pub use stencila_schema;
pub use utils;

/// A specification for codecs
///
/// All codecs, including those implemented in plugins, should provide this
/// specification. Rust implementations return a `Codec` instance from the
/// `spec` function of `CodecTrait`. Plugins provide a JSON or YAML serialization
/// as part of their manifest.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, rename_all = "camelCase")]
pub struct Codec {
    /// A list of format names (or aliases) that the codec can decode from
    /// or encode to
    pub formats: Vec<String>,

    /// Whether the codec supports decoding from string content
    pub from_string: bool,

    /// Whether the codec supports decoding from a file system path
    pub from_path: bool,

    /// Whether the codec supports encoding to string content
    pub to_string: bool,

    /// Whether the codec supports encoding to a file system path
    pub to_path: bool,

    /// A list of root node types that the codec can encode / decode
    ///
    /// Most codecs usually only handle one root type e.g. `Article`.
    /// Used to provide a list of formats to the user that support
    /// the current document type.
    pub root_types: Vec<String>,

    /// A list of node types that the codec does not support
    ///
    /// Used to provide warnings to the user on potential loss of content
    /// when encoding using the codec.
    pub unsupported_types: Vec<String>,

    /// A list of node properties that the codec does not support
    ///
    /// The format for these strings is `<type>.<property>` e.g. `Article.funders`
    /// Used to provide warnings to the user on potential loss of content
    /// when encoding using the codec.
    pub unsupported_properties: Vec<String>,

    /// The status of the codec e.g. `alpha`, `beta`, `stable`
    pub status: String,
}

impl Default for Codec {
    fn default() -> Self {
        Self {
            formats: vec![],
            from_string: true,
            from_path: true,
            to_string: true,
            to_path: true,
            root_types: vec_string!["Article"],
            unsupported_types: vec![],
            unsupported_properties: vec![],
            status: "alpha".to_string(),
        }
    }
}

/// A trait for codecs
///
/// This trait can be used by Rust implementations of codecs, allowing them to
/// be compiled into the Stencila binaries.
///
/// It defines similar functions to `serde_json` (and other `serde_` crates) for
/// converting nodes to/from strings, files, readers etc.
#[async_trait]
pub trait CodecTrait {
    /// Get the [`Codec`] specification for this implementation
    fn spec() -> Codec;

    /// Decode a document node from a string
    fn from_str(_str: &str, _options: Option<DecodeOptions>) -> Result<Node> {
        bail!("Decoding from string is not implemented for this format")
    }

    /// Decode a document node from a string asynchronously
    async fn from_str_async(str: &str, options: Option<DecodeOptions>) -> Result<Node> {
        Self::from_str(str, options)
    }

    /// Decode a document node from a `BufReader`
    async fn from_buffer<T: AsyncRead>(
        reader: &mut BufReader<T>,
        options: Option<DecodeOptions>,
    ) -> Result<Node>
    where
        T: Send + Sync + Unpin,
    {
        let mut content = String::new();
        reader.read_to_string(&mut content).await?;
        Self::from_str_async(&content, options).await
    }

    /// Decode a document node from a file
    ///
    /// This function reads the file as a string and passes that on to `from_str`
    /// for decoding. If working with binary formats, you should override this function
    /// to read the file as bytes instead.
    async fn from_file(file: &mut File, options: Option<DecodeOptions>) -> Result<Node> {
        let mut content = String::new();
        file.read_to_string(&mut content).await?;
        Self::from_str_async(&content, options).await
    }

    /// Decode a document node from a file system path
    async fn from_path(path: &Path, options: Option<DecodeOptions>) -> Result<Node> {
        let mut file = File::open(path).await?;
        Self::from_file(&mut file, options).await
    }

    /// Encode a document node to a string
    fn to_string(_node: &Node, _options: Option<EncodeOptions>) -> Result<String> {
        bail!("Encoding to string is not implemented for this format")
    }

    /// Encode a document node to a string asynchronously
    async fn to_string_async(node: &Node, options: Option<EncodeOptions>) -> Result<String> {
        Self::to_string(node, options)
    }

    /// Encode a document node to a `BufWriter`
    async fn to_buffer<T: AsyncWrite>(
        node: &Node,
        writer: &mut BufWriter<T>,
        options: Option<EncodeOptions>,
    ) -> Result<()>
    where
        T: Send + Sync + Unpin,
    {
        let content = Self::to_string_async(node, options).await?;
        writer.write_all(content.as_bytes()).await?;
        Ok(())
    }

    /// Encode a document node to a file
    async fn to_file(node: &Node, file: &mut File, options: Option<EncodeOptions>) -> Result<()> {
        let content = Self::to_string_async(node, options).await?;
        file.write_all(content.as_bytes()).await?;
        Ok(())
    }

    /// Encode a document node to a file system path
    async fn to_path(node: &Node, path: &Path, options: Option<EncodeOptions>) -> Result<()> {
        if let Some(parent) = path.parent() {
            create_dir_all(parent)?
        }
        let mut file = File::create(path).await?;
        Self::to_file(node, &mut file, options).await
    }
}

/// Decoding options
///
/// Decoding functions (including those in plugins) are encouraged to respect these options
/// but are not required to.
#[derive(Clone, Default)]
pub struct DecodeOptions {
    /// The format of the input to be decoded
    ///
    /// Most codecs only decode one format. However, for those that handle multiple
    /// format it may be necessary to specify this option.
    pub format: Option<String>,
}

/// Encoding options
///
/// Encoding functions (including those in plugins) are encouraged to respect these options
/// but are not required to. Indeed, some options do not apply for some formats.
/// For example, a PDF is always `standalone` (so if that option is set to `false` is it will be ignored).
/// Futhermore, some combinations of options are ineffectual e.g. a `theme` when `standalone: false`
#[derive(Clone)]
pub struct EncodeOptions {
    /// Whether to encode in compact form.
    ///
    /// Some formats (e.g HTML and JSON) can be encoded in either compact
    /// or "pretty-printed" ie.e. indented forms.
    pub compact: bool,

    /// Whether to ensure that the encoded document is standalone.
    ///
    /// Some formats (e.g. Markdown, DOCX) are always standalone, others
    /// can be frangments, or standalong documents (e.g HTML).
    pub standalone: bool,

    /// Whether to bundle local media files into the encoded document
    ///
    /// Some formats (e.g. DOCX, PDF) always bundle. For HTML,
    /// bundling means including media as data URIs rather than
    /// links to files.
    pub bundle: bool,

    /// The theme to apply to the encoded document
    ///
    /// Only applies to some formats (e.g. HTML, PDF, PNG).
    pub theme: String,

    /// The format to encode to
    ///
    /// Most codecs only encode to one format. However, for those that handle multiple
    /// formats it may be necessary to specify this option.
    pub format: Option<String>,
}

impl Default for EncodeOptions {
    fn default() -> Self {
        Self {
            compact: true,
            standalone: false,
            bundle: false,
            theme: "stencila".to_string(),
            format: None,
        }
    }
}
<|endoftext|>