<commit_before>#[macro_use]
extern crate iron;
extern crate persistent;
extern crate staticfile;
extern crate mount;
extern crate gluon;
extern crate serde_json;
#[macro_use]
extern crate log;
extern crate env_logger;

use std::io::Read;
use std::time::Instant;

use iron::prelude::*;
use iron::status;
use iron::typemap::Key;

use staticfile::Static;

use mount::Mount;

use gluon::vm::thread::{RootedThread, ThreadInternal};
use gluon::vm::Error;
use gluon::vm::api::Generic;
use gluon::vm::api::generic::A;
use gluon::{Compiler, new_vm};
use gluon::import::Import;

pub struct VMKey;
impl Key for VMKey {
    type Value = RootedThread;
}

fn eval(req: &mut Request) -> IronResult<Response> {
    eval_(req).map(|s| Response::with((status::Ok, ::serde_json::to_string(&s).unwrap())))
}
fn eval_(req: &mut Request) -> IronResult<String> {
    let mut body = String::new();
    itry!(req.body.read_to_string(&mut body));
    info!("Eval: `{}`", body);
    body.push(' ');
    let global_vm = req.get::<persistent::Read<VMKey>>().unwrap();
    let vm = match global_vm.new_thread() {
        Ok(vm) => vm,
        Err(err) => return Ok(format!("{}", err)),
    };

    // Prevent a single thread from allocating to much memory
    vm.set_memory_limit(2_000_000);

    // Prevent infinite loops from running forever
    let start = Instant::now();
    vm.context().set_hook(Some(Box::new(move |_| {
        if start.elapsed().as_secs() < 10 {
            Ok(())
        } else {
            Err(Error::Message("Thread has exceeded the allowed exection time".into()))
        }
    })));

    let (value, typ) = match Compiler::new().run_expr::<Generic<A>>(&vm, "<top>", &body) {
        Ok(value) => value,
        Err(err) => return Ok(format!("{}", err)),
    };
    Ok(format!("{:?} : {}", value, typ))
}

fn main() {
    env_logger::init().unwrap();
    let mut mount = Mount::new();

    mount.mount("/", Static::new("public"));

    let mut middleware = Chain::new(eval);
    let vm = new_vm();

    // Ensure the import macro cannot be abused to to open files
    {
        // Ensure the lock to `paths` are released
        let mac = vm.get_macros().get("import").expect("import");
        let mut import = mac.downcast_ref::<Import>()
            .expect("Import macro")
            .paths
            .write()
            .unwrap();
        import.clear();
    }

    middleware.link(persistent::Read::<VMKey>::both(vm));
    mount.mount("/eval", middleware);

    let address = "0.0.0.0:8080";
    let _server = Iron::new(mount).http(address).unwrap();
    println!("Server started at `{}`", address);
}<commit_msg>fix: Update code to work with a newever version of gluon<commit_after>#[macro_use]
extern crate iron;
extern crate persistent;
extern crate staticfile;
extern crate mount;
extern crate gluon;
extern crate serde_json;
#[macro_use]
extern crate log;
extern crate env_logger;

use std::io::Read;
use std::time::Instant;

use iron::prelude::*;
use iron::status;
use iron::typemap::Key;

use staticfile::Static;

use mount::Mount;

use gluon::vm::thread::{RootedThread, Thread, ThreadInternal};
use gluon::vm::Error;
use gluon::vm::api::{Hole, OpaqueValue};
use gluon::Compiler;
use gluon::import::{DefaultImporter, Import};

pub struct VMKey;
impl Key for VMKey {
    type Value = RootedThread;
}

fn eval(req: &mut Request) -> IronResult<Response> {
    eval_(req).map(|s| Response::with((status::Ok, ::serde_json::to_string(&s).unwrap())))
}
fn eval_(req: &mut Request) -> IronResult<String> {
    let mut body = String::new();
    itry!(req.body.read_to_string(&mut body));
    info!("Eval: `{}`", body);
    body.push(' ');
    let global_vm = req.get::<persistent::Read<VMKey>>().unwrap();
    let vm = match global_vm.new_thread() {
        Ok(vm) => vm,
        Err(err) => return Ok(format!("{}", err)),
    };

    // Prevent a single thread from allocating to much memory
    vm.set_memory_limit(2_000_000);

    // Prevent infinite loops from running forever
    let start = Instant::now();
    vm.context().set_hook(Some(Box::new(move |_| {
        if start.elapsed().as_secs() < 10 {
            Ok(())
        } else {
            Err(Error::Message("Thread has exceeded the allowed exection time".into()))
        }
    })));

    let (value, typ) = match Compiler::new()
        .run_expr::<OpaqueValue<&Thread, Hole>>(&vm, "<top>", &body) {
        Ok(value) => value,
        Err(err) => return Ok(format!("{}", err)),
    };
    Ok(format!("{:?} : {}", value, typ))
}

fn main() {
    env_logger::init().unwrap();
    let mut mount = Mount::new();

    mount.mount("/", Static::new("public"));

    let mut middleware = Chain::new(eval);
    let vm = RootedThread::new();

    // Ensure the import macro cannot be abused to to open files
    {
        // Ensure the lock to `paths` are released
        let import = Import::new(DefaultImporter);
        import.paths.write().unwrap().clear();
        vm.get_macros()
            .insert(String::from("import"), import);
    }
    Compiler::new()
        .implicit_prelude(false)
        .run_expr::<OpaqueValue<&Thread, Hole>>(&vm, "", r#" import "std/types.glu" "#)
        .unwrap();
    gluon::vm::primitives::load(&vm).expect("Loaded primitives library");
    gluon::io::load(&vm).expect("Loaded IO library");

    middleware.link(persistent::Read::<VMKey>::both(vm));
    mount.mount("/eval", middleware);

    let address = "0.0.0.0:8080";
    let _server = Iron::new(mount).http(address).unwrap();
    println!("Server started at `{}`", address);
}
{'fraction_non_alphanumeric': 0.1829004329004329, 'fraction_numerical': 0.006132756132756133, 'mean_word_length': 3.486245954692557, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 34, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3334960', 'n_tokens_mistral': 1861, 'n_tokens_neox': 1805, 'n_words': 436}