summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArnaud Bailly <arnaud@pankzsoft.com>2025-10-09 12:47:18 +0200
committerArnaud Bailly <arnaud@pankzsoft.com>2025-10-09 12:49:27 +0200
commitbf7f549e309a4da97def326b3fdf19a4d8833450 (patch)
treeb9a0777ab20a1b41b16b3fd9087af465879ab05d
parent3050ae41c4e74b8bfa12aca31ab3af4c83ac5379 (diff)
downloadlambda-nantes-bf7f549e309a4da97def326b3fdf19a4d8833450.tar.gz
feat: can serve and receive Json or Sexp
depending on Registration by client
-rw-r--r--lambda-calcul/rust/Cargo.toml2
-rw-r--r--lambda-calcul/rust/README.md8
-rw-r--r--lambda-calcul/rust/src/web.rs64
3 files changed, 50 insertions, 24 deletions
diff --git a/lambda-calcul/rust/Cargo.toml b/lambda-calcul/rust/Cargo.toml
index 230e422..51185e5 100644
--- a/lambda-calcul/rust/Cargo.toml
+++ b/lambda-calcul/rust/Cargo.toml
@@ -14,7 +14,7 @@ env_logger = "0.8"
log = "0.4"
futures = "0.3.30"
async-std = "1.13.0"
-reqwest = "0.12.8"
+reqwest = { version = "0.12.8", features = ["json"] }
tokio = { version = "1.40.0", features = ["rt", "macros", "rt-multi-thread"]}
clap = { version = "4.5.19", features = ["derive"] }
proptest = "1.0.0"
diff --git a/lambda-calcul/rust/README.md b/lambda-calcul/rust/README.md
index 0b13e5c..08dfc3d 100644
--- a/lambda-calcul/rust/README.md
+++ b/lambda-calcul/rust/README.md
@@ -26,9 +26,14 @@ We use the following variables to represent, well, variable elements that should
The client needs to send a `POST /register` request, passing in as payload a JSON object with a `url` and `name` string fields:
```
-curl -v -X POST -d '{"url":"${CLIENT_URL}", "name": "toto"}' -H 'Content-type: application/json' ${SERVER_BASE_URL}/register
+curl -v -X POST -d '{"url":"${CLIENT_URL}", "name": "toto", "encoding": "Json"}' -H 'Content-type: application/json' ${SERVER_BASE_URL}/register
```
+The payload is expected to be a JSON object with the following fields:
+* `url`: The client URL for the server to callback and send expressions to evaluate
+* `name`: The name of this client
+* _(Optional)_ `encoding`: Which encoding to use to receive expressions and send responses. One of `Json` or `Sexp`, defaulting to `Json`.
+
Notes:
* Obviously, client needs to start a HTTP server able to respond to a `GET` request at the given URL. To check or troubleshoot connectivity, one can use the [netcat](https://linux.die.net/man/1/nc) program to fire up a local server with `nc -l 12345` and use the ip and port to register the client. This will echo in the terminal whatever the _server_ sends
@@ -74,6 +79,7 @@ There are `--port` and `--host` arguments should one want to change the default
* [ ] persist user state to avoid losing connections
* [ ] deploy automatically server on punkachien.net with radicle CI
* [ ] better JSON representation for AST than raw serde stuff
+* [ ] Document JSON format...
* [ ] ask people to implement something
* [ ] prepare starter kit to overcome
diff --git a/lambda-calcul/rust/src/web.rs b/lambda-calcul/rust/src/web.rs
index ad6bc03..5bc8c3f 100644
--- a/lambda-calcul/rust/src/web.rs
+++ b/lambda-calcul/rust/src/web.rs
@@ -96,7 +96,7 @@ enum TestResult {
}
impl Client {
- fn new(url: String, name: String, delay: Duration) -> Self {
+ fn new(url: String, name: String, delay: Duration, encoding: AstEncoding) -> Self {
let id = Uuid::new_v4();
let runner = TestRunner::new_with_rng(
Config::default(),
@@ -110,7 +110,7 @@ impl Client {
runner,
results: Vec::new(),
delay,
- encoding: AstEncoding::Json,
+ encoding,
}
}
@@ -213,6 +213,7 @@ impl AppState for State {
registration.url.clone(),
registration.name.clone(),
self.base_duration,
+ registration.encoding.clone().unwrap_or(AstEncoding::Json),
);
let id = client.id.to_string();
let client_ref = Arc::new(Mutex::new(client));
@@ -362,17 +363,7 @@ async fn send_one_test(client_m: &Arc<Mutex<Client>>, sleep: Duration) {
let encoding = client_m.lock().unwrap().encoding.clone();
- let request = match encoding {
- AstEncoding::Json => serde_json::to_string(&input).unwrap(),
- _ => input
- .iter()
- .map(|v| format!("{}", v))
- .collect::<Vec<_>>()
- .join("\n"),
- };
- let response: Result<Vec<Value>, TestResult> = send_test(&request, &url, sleep)
- .await
- .and_then(|r| serde_json::from_str(&r).map_err(|e| TestResult::TestFailed(e.to_string())));
+ let response: Result<Vec<Value>, TestResult> = send_test(&input, &url, encoding, sleep).await;
apply_result(client_m, expected, response);
}
@@ -391,22 +382,50 @@ fn sleep_time(client_m: &Arc<Mutex<Client>>) -> Duration {
client_m.lock().unwrap().time_to_next_test()
}
-async fn send_test(input: &String, url: &String, timeout: Duration) -> Result<String, TestResult> {
- info!("Sending {} to {}", input, url);
- let body = input.clone();
+async fn send_test(
+ input: &Vec<Value>,
+ url: &String,
+ encoding: AstEncoding,
+ timeout: Duration,
+) -> Result<Vec<Value>, TestResult> {
+ info!("Sending {:?} to {}", input, url);
+
+ let body = match encoding {
+ AstEncoding::Json => serde_json::to_string(&input).unwrap(),
+ AstEncoding::Sexp => input
+ .iter()
+ .map(|v| format!("{}", v))
+ .collect::<Vec<_>>()
+ .join("\n"),
+ };
+ let content_type = match encoding {
+ AstEncoding::Json => "application/json",
+ AstEncoding::Sexp => "text/plain",
+ };
+
let response = reqwest::Client::new()
.post(url)
.timeout(timeout)
- .header("content-type", "text/plain")
+ .header("content-type", content_type)
.body(body)
.send()
.await;
+
match response {
- Ok(response) => {
- let body = response.text().await.unwrap();
- info!("Response from {}: {}", url, body);
- Ok(body)
- }
+ Ok(response) => match encoding {
+ AstEncoding::Json => {
+ let body = response.json().await.unwrap();
+ info!("Response from {}: {:?}", url, body);
+ Ok(body)
+ }
+ AstEncoding::Sexp => {
+ let body = response.text().await.unwrap();
+ info!("Response from {}: {}", url, body);
+ let exprs =
+ parse_total(&body).map_err(|e| TestResult::TestFailed(e.to_string()))?;
+ Ok(exprs)
+ }
+ },
Err(e) => {
info!("Error sending test: {}", e);
Err(TestResult::ErrorSendingTest(e.to_string()))
@@ -625,6 +644,7 @@ mod app_tests {
"http://1.2.3.4".to_string(),
"foo".to_string(),
Duration::from_secs(10),
+ AstEncoding::Json,
)
}