Skip to content

Commit c293382

Browse files
committed
update delete && readme
1 parent 62eccbc commit c293382

File tree

11 files changed

+160
-78
lines changed

11 files changed

+160
-78
lines changed

Cargo.lock

+10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ bincode = "1.3.3"
1414
chrono = { version = "0.4.31", features = ["serde"] }
1515
clap = { version = "4.4.16", features = ["derive"] }
1616
futures = "0.3.30"
17+
hex = { version = "0.4.3", features = ["serde"] }
1718
hyper = { version = "1.1.0", features = ["full"] }
1819
hyper-util = { version = "0.1.2", features = ["tokio", "server-auto", "http1"] }
1920
reqwest = { version = "0.11.23", features = ["multipart", "json"] }

README.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,8 @@ target/release/mach
3535
```
3636

3737
### Roadmap
38-
TBD
38+
- Improved test coverage
39+
- TLS/SSL support
40+
- IPFS storage backend
41+
- Inter-function calls
42+
- Inter server function calls

src/api/client.rs

+17-10
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
use std::net::SocketAddr;
22

33
use crate::{
4-
api::{routes::call::CallRequest, API_VERSION},
4+
api::{
5+
routes::{call::CallRequest, upload::UploadResponse},
6+
API_VERSION,
7+
},
58
exec::task::TaskResult,
9+
storage::FnEntry,
610
};
711

812
use super::routes::{get::GetResponse, list::ListResponse};
@@ -30,7 +34,7 @@ impl Client {
3034
}
3135

3236
/// Gets detailed information about a function
33-
pub async fn get(&self, addr: SocketAddr, fn_id: &str) -> anyhow::Result<GetResponse> {
37+
pub async fn get(&self, addr: SocketAddr, fn_id: &uuid::Uuid) -> anyhow::Result<GetResponse> {
3438
let url = format!("http://{addr}/{API_VERSION}/functions/{fn_id}");
3539

3640
let response = self.r_client.get(url).send().await?;
@@ -43,12 +47,12 @@ impl Client {
4347
pub async fn call(
4448
&mut self,
4549
addr: SocketAddr,
46-
fn_name: &str,
50+
id: &uuid::Uuid,
4751
args: Vec<u8>,
4852
) -> anyhow::Result<TaskResult> {
49-
let call_url = format!("http://{addr}/{API_VERSION}/functions/{fn_name}");
53+
let call_url = format!("http://{addr}/{API_VERSION}/functions/{id}");
5054
let call_request = CallRequest {
51-
function: fn_name.to_string(),
55+
id: id.to_owned(),
5256
args,
5357
};
5458

@@ -70,7 +74,7 @@ impl Client {
7074
addr: SocketAddr,
7175
fn_name: &str,
7276
fn_data: Vec<u8>,
73-
) -> anyhow::Result<()> {
77+
) -> anyhow::Result<UploadResponse> {
7478
let form = reqwest::multipart::Form::new();
7579
let part = reqwest::multipart::Part::bytes(fn_data)
7680
.file_name(fn_name.to_string())
@@ -80,18 +84,21 @@ impl Client {
8084

8185
let upload_url = format!("http://{addr}/{API_VERSION}/functions");
8286

83-
self.r_client
87+
let raw_response = self
88+
.r_client
8489
.post(upload_url)
8590
.multipart(form)
8691
.send()
8792
.await?;
8893

89-
Ok(())
94+
let response = raw_response.json::<UploadResponse>().await?;
95+
96+
Ok(response)
9097
}
9198

9299
/// Deletes a function from the server
93-
pub async fn delete(&mut self, addr: SocketAddr, fn_name: &str) -> anyhow::Result<()> {
94-
let delete_url = format!("http://{addr}/{API_VERSION}/functions/{fn_name}");
100+
pub async fn delete(&mut self, addr: SocketAddr, fn_id: &uuid::Uuid) -> anyhow::Result<()> {
101+
let delete_url = format!("http://{addr}/{API_VERSION}/functions/{fn_id}");
95102

96103
self.r_client.delete(delete_url).send().await?;
97104

src/api/mod.rs

+49-31
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,17 @@ mod tests {
104104
server.run().await.unwrap();
105105

106106
let server_addr = server.local_addr();
107-
let fn_id = TEST_WASM_NAME;
108-
let fn_id = fn_id.replace(".wasm", "");
109107

110-
let api_client = ApiClient::new().unwrap();
111-
let response = api_client.get(server_addr, &fn_id).await.unwrap();
108+
let fn_file = read_file_to_bytes("tests/fixtures/hello.wasm").unwrap();
109+
let fn_name = "hello_1.wasm";
110+
111+
let mut api_client = ApiClient::new().unwrap();
112+
let response = api_client
113+
.upload(server_addr, fn_name, fn_file)
114+
.await
115+
.unwrap();
116+
117+
let response = api_client.get(server_addr, &response.id).await.unwrap();
112118

113119
assert!(!response.fn_data.is_empty());
114120

@@ -120,12 +126,13 @@ mod tests {
120126
let mut server = setup_server().await;
121127
server.run().await.unwrap();
122128

123-
let non_existent_fn_id = "non_existent_function";
124-
125129
let server_addr = server.local_addr();
126130

127131
let api_client = ApiClient::new().unwrap();
128-
let response = api_client.get(server_addr, non_existent_fn_id).await;
132+
133+
let fn_id = uuid::Uuid::new_v4();
134+
135+
let response = api_client.get(server_addr, &fn_id).await;
129136
assert!(response.is_err());
130137

131138
server.stop();
@@ -138,14 +145,21 @@ mod tests {
138145

139146
let server_addr = server.local_addr();
140147

141-
let fn_id = TEST_WASM_NAME;
142-
let fn_id = fn_id.replace(".wasm", "");
148+
let fn_file = read_file_to_bytes("tests/fixtures/hello.wasm").unwrap();
149+
let fn_name = "hello_1.wasm";
143150

144151
let mut api_client = ApiClient::new().unwrap();
145-
let response = api_client.call(server_addr, &fn_id, vec![]).await.unwrap();
152+
let response = api_client
153+
.upload(server_addr, fn_name, fn_file)
154+
.await
155+
.unwrap();
146156

147-
let expected_response = "Hello, world!\n";
157+
let response = api_client
158+
.call(server_addr, &response.id, vec![])
159+
.await
160+
.unwrap();
148161

162+
let expected_response = "Hello, world!\n";
149163
assert_eq!(response.stdout, expected_response);
150164

151165
server.stop();
@@ -157,34 +171,38 @@ mod tests {
157171
server.run().await.unwrap();
158172

159173
let server_addr = server.local_addr();
160-
let invalid_fn_name = "non_existent_function";
161174

162-
let mut api_client = ApiClient::new().unwrap();
163-
let response = api_client.call(server_addr, invalid_fn_name, vec![]).await;
175+
let fn_id = uuid::Uuid::new_v4();
164176

177+
let mut api_client = ApiClient::new().unwrap();
178+
let response = api_client.call(server_addr, &fn_id, vec![]).await;
165179
assert!(response.is_err());
166180

167181
server.stop();
168182
}
169183

170184
#[tokio::test]
171-
#[ignore]
172185
async fn test_delete_functions() {
173-
// let mut server = setup_server().await;
174-
// server.run().await.unwrap();
175-
//
176-
// let server_addr = server.local_addr();
177-
//
178-
// let fn_file = read_file_to_bytes("tests/fixtures/hello.wasm").unwrap();
179-
//
180-
// let fn_id = TEST_WASM_NAME;
181-
// let fn_id = fn_id.replace(".wasm", "");
182-
//
183-
// let mut api_client = ApiClient::new().unwrap();
184-
// let response = api_client.upload(server_addr, &fn_id, fn_file).await;
185-
//
186-
// assert!(response.is_ok());
187-
//
188-
// server.stop();
186+
let mut server = setup_server().await;
187+
server.run().await.unwrap();
188+
189+
let server_addr = server.local_addr();
190+
191+
let fn_file = read_file_to_bytes("tests/fixtures/hello.wasm").unwrap();
192+
let fn_name = "hello_1.wasm";
193+
194+
let mut api_client = ApiClient::new().unwrap();
195+
196+
let response = api_client
197+
.upload(server_addr, fn_name, fn_file)
198+
.await
199+
.unwrap();
200+
201+
api_client.delete(server_addr, &response.id).await.unwrap();
202+
203+
let get_response = api_client.get(server_addr, &response.id).await;
204+
assert!(get_response.is_err());
205+
206+
server.stop();
189207
}
190208
}

src/api/routes/call.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::storage::FnStorage;
99

1010
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1111
pub struct CallRequest {
12-
pub function: String,
12+
pub id: uuid::Uuid,
1313
pub args: Vec<u8>,
1414
}
1515

@@ -23,7 +23,7 @@ where
2323
T: TaskExecutor + 'static,
2424
{
2525
let mut state = state.write().await;
26-
let module = state.storage_backend.load(&req.function).await?;
26+
let module = state.storage_backend.load(&req.id).await?;
2727

2828
let task = Task {
2929
id: uuid::Uuid::new_v4(),

src/api/routes/delete.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ use axum::extract::{Path, State};
33
use crate::{
44
api::{ApiError, SharedServerState},
55
exec::TaskExecutor,
6-
storage::FnStorage,
6+
storage::{FnId, FnStorage},
77
};
88

99
#[tracing::instrument]
1010
pub async fn delete_handler<F, T>(
11-
Path(fn_id): Path<String>,
11+
Path(fn_id): Path<FnId>,
1212
State(state): State<SharedServerState<F, T>>,
1313
) -> Result<(), ApiError>
1414
where

src/api/routes/get.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub struct GetResponse {
1818

1919
#[tracing::instrument]
2020
pub async fn get_handler<F, T>(
21-
Path(fn_id): Path<String>,
21+
Path(fn_id): Path<uuid::Uuid>,
2222
State(state): State<SharedServerState<F, T>>,
2323
) -> Result<Json<GetResponse>, ApiError>
2424
where

src/api/routes/upload.rs

+31-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use axum::extract::{Multipart, State};
1+
use axum::{
2+
extract::{Multipart, State},
3+
Json,
4+
};
5+
use serde::{Deserialize, Serialize};
26

37
use crate::{
48
api::{ApiError, SharedServerState},
@@ -12,12 +16,22 @@ use std::{io, path::Path};
1216
use tokio::{fs::File, io::BufWriter};
1317
use tokio_util::io::StreamReader;
1418

19+
#[derive(Debug, Clone, Serialize, Deserialize)]
20+
pub struct UploadResponse {
21+
/// Unique identifier for the function
22+
pub id: uuid::Uuid,
23+
/// Display name for the function
24+
pub name: String,
25+
/// Cecksum of the function file
26+
pub hash: String,
27+
}
28+
1529
/// Handler that accepts a multipart form upload and streams each field to a file.
1630
#[tracing::instrument]
1731
pub async fn upload_handler<F, T>(
1832
State(state): State<SharedServerState<F, T>>,
1933
mut multipart: Multipart,
20-
) -> Result<(), ApiError>
34+
) -> Result<Json<UploadResponse>, ApiError>
2135
where
2236
F: FnStorage + 'static,
2337
T: TaskExecutor + 'static,
@@ -45,10 +59,23 @@ where
4559
hash: fn_hash,
4660
};
4761

48-
state.write().await.storage_backend.save(fn_entry).await?;
62+
let response = UploadResponse {
63+
id: fn_entry.id,
64+
name: fn_entry.name.clone(),
65+
hash: hex::encode(fn_entry.hash.clone()),
66+
};
67+
68+
state
69+
.write()
70+
.await
71+
.storage_backend
72+
.save(fn_entry.clone())
73+
.await?;
74+
75+
return Ok(Json(response));
4976
}
5077

51-
Ok(())
78+
Err(ApiError::Other("received no files".to_string()))
5279
}
5380

5481
async fn stream_to_file<S, E>(path: &Path, file_name: &str, stream: S) -> anyhow::Result<Vec<u8>>

0 commit comments

Comments
 (0)