diff options
| author | Arnaud Bailly <arnaud.bailly@iohk.io> | 2024-10-05 15:04:10 +0200 |
|---|---|---|
| committer | Arnaud Bailly <arnaud.bailly@iohk.io> | 2024-10-05 15:04:10 +0200 |
| commit | d96f415a2cfb55715c095cc9c2775b1413e06203 (patch) | |
| tree | 25b22d08b361798a5a407e9f03e9383ae1273561 /rust | |
| parent | 22a53ab297447c2f044d01bf443f7b140745762f (diff) | |
| download | lambda-nantes-d96f415a2cfb55715c095cc9c2775b1413e06203.tar.gz | |
Server can also evaluate expressions
Diffstat (limited to 'rust')
| -rw-r--r-- | rust/Cargo.lock | 120 | ||||
| -rw-r--r-- | rust/Cargo.toml | 1 | ||||
| -rw-r--r-- | rust/src/web.rs | 51 |
3 files changed, 170 insertions, 2 deletions
diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 1f35d11..0d9e14f 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -253,6 +253,55 @@ dependencies = [ ] [[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] name = "async-channel" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -533,6 +582,52 @@ dependencies = [ ] [[package]] +name = "clap" +version = "4.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + +[[package]] name = "concurrent-queue" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -937,6 +1032,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" [[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] name = "hermit-abi" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1148,6 +1249,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1664,6 +1771,7 @@ dependencies = [ "actix-web", "async-std", "chrono", + "clap", "env_logger", "futures", "log", @@ -1907,6 +2015,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] name = "subtle" version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2167,6 +2281,12 @@ dependencies = [ ] [[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] name = "uuid" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 7635eae..01a9aa0 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -15,6 +15,7 @@ futures = "0.3.30" async-std = "1.13.0" reqwest = "0.12.8" tokio = { version = "1.40.0", features = ["rt", "macros", "rt-multi-thread"]} +clap = { version = "4.5.19", features = ["derive"] } [dependencies.uuid] version = "1.10.0" diff --git a/rust/src/web.rs b/rust/src/web.rs index 94b01cb..b48900e 100644 --- a/rust/src/web.rs +++ b/rust/src/web.rs @@ -2,6 +2,7 @@ use actix_web::{ get, http::header::ContentType, middleware::Logger, post, web, App, HttpResponse, HttpServer, Responder, }; +use clap::Parser; use futures::try_join; use futures::{future::join_all, lock::Mutex}; use log::info; @@ -90,8 +91,33 @@ async fn register( } } +#[post("/eval")] +async fn eval(input: String) -> impl Responder { + let mut env = Environment::new(); + match parse(&input).first() { + Some(expr) => { + let output = eval_whnf(expr, &mut env); + HttpResponse::Ok().body(format!("{}", output)) + } + None => HttpResponse::BadRequest().finish(), + } +} + +#[derive(Parser, Debug)] +struct Options { + /// The port to listen on + /// Defaults to 8080 + #[arg(short, long, default_value_t = 8080)] + port: u16, + /// The host to bind the server to + /// Defaults to 127.0.0.1 + #[arg(long, default_value = "127.0.0.1")] + host: String, +} + #[tokio::main] async fn main() -> std::io::Result<()> { + let options = Options::parse(); let app_state = Arc::new(Mutex::new(State::new())); let send_state: Arc<Mutex<State>> = app_state.clone(); let http_state: Arc<Mutex<dyn AppState>> = app_state; @@ -103,8 +129,9 @@ async fn main() -> std::io::Result<()> { .wrap(Logger::default()) .app_data(web::Data::new(http_state.clone())) .service(register) + .service(eval) }) - .bind(("127.0.0.1", 8080))? + .bind((options.host, options.port))? .run() .await } @@ -134,6 +161,7 @@ async fn send_test(grade: u8, url: &String) -> Result<(), String> { info!("Sending {} to {}", input, url); let response = reqwest::Client::new() .post(url) + .header("content-type", "text/plain") .body(format!("{}", input)) .send() .await; @@ -141,7 +169,7 @@ async fn send_test(grade: u8, url: &String) -> Result<(), String> { Ok(response) => { let body = response.text().await.unwrap(); let vals = parse(&body); - // FIXME + // FIXME: should be able to handle multiple values let result = eval_whnf(vals.first().unwrap(), &mut env); info!("Received {} from {}", body, url); if result == output { @@ -256,6 +284,25 @@ mod app_tests { ); } + #[actix_web::test] + async fn post_expression_returns_evaluation() { + let app = test::init_service(App::new().wrap(Logger::default()).service(eval)).await; + + let req = test::TestRequest::post() + .uri("/eval") + .set_payload("((lam (x y) x) 1 2)") + .insert_header(ContentType::plaintext()) + .to_request(); + + let resp = test::call_service(&app, req).await; + + assert!(resp.status().is_success()); + + let body = resp.into_body(); + let bytes = body::to_bytes(body).await.unwrap(); + assert_eq!(bytes, "1".to_string().into_bytes()); + } + #[test] async fn app_does_not_register_same_url_twice() { let mut app_state = State::new(); |
