Skip to content

Commit

Permalink
chore: Run cargo fmt
Browse files Browse the repository at this point in the history
  • Loading branch information
adamreese committed Mar 24, 2022
1 parent 984c392 commit 64ba587
Show file tree
Hide file tree
Showing 26 changed files with 1,030 additions and 375 deletions.
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "wagi"
version = "0.6.2"
version = "0.8.1"
authors = ["Matt Butcher <[email protected]>"]
edition = "2021"

Expand All @@ -17,6 +17,7 @@
hyper = { version = "0.14", features = ["full"] }
indexmap = { version = "^1.6.2", features = ["serde"] }
oci-distribution = "0.6"
reqwest = { version = "0.11", features = ["stream"] }
serde = { version = "1.0", features = ["derive"] }
sha2 = "0.9"
tokio = { version = "1.1", features = ["full"] }
Expand Down
4 changes: 3 additions & 1 deletion docs/configuring_and_running.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ In a nutshell, these are the fields that `modules.toml` supports.
- `route` (REQUIRED): The path that is appended to the server URL to create a full URL (e.g. `/foo` becomes `https://example.com/foo`)
- `module` (REQUIRED): A module reference. See Module References below.
- `repository`: RESERVED for future use
- `entrypoint` (default: `_start`): The name of the function within the module. This will directly execute that function. Most WASM/WASI implementations create a `_start` function by default. An example of a module that declares 3 entrypoints can be found [here](https://github.com/technosophos/hello-wagi).
- `entrypoint` (Optional, default: `_start`): The name of the function within the module. This will directly execute that function. Most WASM/WASI implementations create a `_start` function by default. An example of a module that declares 3 entrypoints can be found [here](https://github.com/technosophos/hello-wagi).
- `argv`: (Optional, default: "${SCRIPT_NAME} ${ARGS}"). This determines what the `argv` array looks like for the invoked program. The CGI 1.1 spec says that the `argv` array should contain the script name followed by the parameters. However, some Wasm modules require specifically formatted `argv`. This allows a way to override the CGI 1.1 defaults. Example: `argv = "ruby index.rb ${SCRIPT_NAME} ${ARGS}"`. This could expand to `ruby index.rb /example param1=val1 param2=val2`

Here is a brief example of a `modules.toml` file that declares two routes:

Expand Down Expand Up @@ -262,6 +263,7 @@ The following features are available for Wagi under `feature.wagi.FEATURE`:
| route | The relative path from the server route. e.g. "/foo" is mapped to http://example.com/foo |
| allowed_hosts | A comma-separated list of hosts that the HTTP client is allowed to access |
| file | If this is "true", this parcel will be treated as a file for consumption by a Wagi module |
| argv | If this is set, use this as a template for building the `argv` array. Two values are substituted: `${SCRIPT_NAME}` is replaced with the CGI `$SCRIPT_NAME` and `${ARGS}` is replaced with the query parameters formatted for CGI. |

### Simple Bindle Example

Expand Down
6 changes: 3 additions & 3 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ and download the desired release. Usually, the most recent release is the one yo
You can generate and compare the SHA with `shasum`:

```console
$ shasum wagi-v0.6.2-linux-amd64.tar.gz
ad4114b2ed9e510a8c24348d5ea544da55c685f5 wagi-v0.6.2-linux-amd64.tar.gz
$ shasum wagi-v0.8.1-linux-amd64.tar.gz
ad4114b2ed9e510a8c24348d5ea544da55c685f5 wagi-v0.8.1-linux-amd64.tar.gz
```

You can then compare that SHA with the one present in the release notes.
Expand Down Expand Up @@ -40,7 +40,7 @@ To build a static binary, run the following command:

```console
$ make build
Compiling wagi v0.6.2 (/Users/technosophos/Code/Rust/wagi)
Compiling wagi v0.8.1 (/Users/technosophos/Code/Rust/wagi)
Finished release [optimized] target(s) in 18.47s
```

Expand Down
159 changes: 132 additions & 27 deletions src/bindle_util.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::{collections::{HashMap, HashSet}, iter::FromIterator};
use std::{
collections::{HashMap, HashSet},
iter::FromIterator,
};

use bindle::{Invoice, Parcel};

Expand Down Expand Up @@ -45,30 +48,35 @@ impl InvoiceUnderstander {
pub fn classify_parcel(&self, parcel: &Parcel) -> Option<InterestingParcel> {
// Currently only handlers but we have talked of scheduled tasks etc.
parcel.label.feature.as_ref().and_then(|features| {
features.get("wagi").and_then(|wagi_features| {
match wagi_features.get("route") {
features
.get("wagi")
.and_then(|wagi_features| match wagi_features.get("route") {
Some(route) => {
let handler_info = WagiHandlerInfo {
invoice_id: self.id(),
parcel: parcel.clone(),
route: route.to_owned(),
entrypoint: wagi_features.get("entrypoint").map(|s| s.to_owned()),
allowed_hosts: wagi_features.get("allowed_hosts").map(|h| parse_csv(h)),
required_parcels: parcels_required_for(parcel, &self.group_dependency_map),
argv: wagi_features.get("argv").map(|s| s.to_owned()),
required_parcels: parcels_required_for(
parcel,
&self.group_dependency_map,
),
};
Some(InterestingParcel::WagiHandler(handler_info))
},
}
None => None,
}
})
})
})
}

pub fn parse_wagi_handlers(&self) -> Vec<WagiHandlerInfo> {
self
.top_modules().iter()
self.top_modules()
.iter()
.filter_map(|parcel| self.classify_parcel(parcel))
.map(|parcel| match parcel { // If there are other cases of InterestingParcel this may need to become a filter_map, but right now that makes Clippy mad
.map(|parcel| match parcel {
// If there are other cases of InterestingParcel this may need to become a filter_map, but right now that makes Clippy mad
InterestingParcel::WagiHandler(h) => h,
})
.collect()
Expand All @@ -87,31 +95,50 @@ pub struct WagiHandlerInfo {
pub entrypoint: Option<String>,
pub allowed_hosts: Option<Vec<String>>,
pub required_parcels: Vec<Parcel>,
pub argv: Option<String>,
}

impl WagiHandlerInfo {
pub fn asset_parcels(&self) -> Vec<Parcel> {
self.required_parcels.iter().filter(|p| is_file(p)).cloned().collect()
self.required_parcels
.iter()
.filter(|p| is_file(p))
.cloned()
.collect()
}
}

const NO_PARCELS: Vec<Parcel> = vec![];

pub fn is_file(parcel: &Parcel) -> bool {
parcel.label.feature.as_ref().and_then(|features| {
features.get("wagi").map(|wagi_features| {
match wagi_features.get("file") {
Some(s) => s == "true",
_ => false,
}
parcel
.label
.feature
.as_ref()
.and_then(|features| {
features
.get("wagi")
.map(|wagi_features| match wagi_features.get("file") {
Some(s) => s == "true",
_ => false,
})
})
}).unwrap_or(false)
.unwrap_or(false)
}

pub fn parcels_required_for(parcel: &Parcel, full_dep_map: &HashMap<String, Vec<Parcel>>) -> Vec<Parcel> {
pub fn parcels_required_for(
parcel: &Parcel,
full_dep_map: &HashMap<String, Vec<Parcel>>,
) -> Vec<Parcel> {
let mut required = HashSet::new();
for group in parcel.directly_requires() {
required.extend(full_dep_map.get(&group).unwrap_or(&NO_PARCELS).iter().cloned());
required.extend(
full_dep_map
.get(&group)
.unwrap_or(&NO_PARCELS)
.iter()
.cloned(),
);
}
Vec::from_iter(required)
}
Expand Down Expand Up @@ -142,25 +169,39 @@ pub fn build_full_memberships(invoice: &Invoice) -> HashMap<String, Vec<Parcel>>
for group in direct_memberships.keys() {
let mut all_members = HashSet::new();
for dep_group in gg_deps.get(group).unwrap() {
all_members.extend(direct_memberships.get(dep_group).unwrap_or(&NO_PARCELS).iter().cloned());
all_members.extend(
direct_memberships
.get(dep_group)
.unwrap_or(&NO_PARCELS)
.iter()
.cloned(),
);
}
full_memberships.insert(group.to_owned(), Vec::from_iter(all_members));
}

full_memberships
}

fn group_to_group_direct_dependencies(direct_memberships: &HashMap<String, Vec<Parcel>>) -> HashMap<String, Vec<String>> {
fn group_to_group_direct_dependencies(
direct_memberships: &HashMap<String, Vec<Parcel>>,
) -> HashMap<String, Vec<String>> {
let mut ggd = HashMap::new();
for (group, members) in direct_memberships {
let mut directs: Vec<_> = members.iter().flat_map(|parcel| parcel.directly_requires()).collect();
let mut directs: Vec<_> = members
.iter()
.flat_map(|parcel| parcel.directly_requires())
.collect();
directs.push(group.to_owned());
ggd.insert(group.to_owned(), directs);
}
ggd
}

fn direct_deps_not_already_in_list(list: &[String], direct_dep_map: &HashMap<String, Vec<String>>) -> Vec<String> {
fn direct_deps_not_already_in_list(
list: &[String],
direct_dep_map: &HashMap<String, Vec<String>>,
) -> Vec<String> {
let mut new_dds = vec![];
for group in list {
if let Some(child_groups) = direct_dep_map.get(group) {
Expand All @@ -172,7 +213,9 @@ fn direct_deps_not_already_in_list(list: &[String], direct_dep_map: &HashMap<Str
HashSet::<String>::from_iter(new_dds).into_iter().collect()
}

fn group_to_group_full_dependencies(direct_memberships: &HashMap<String, Vec<Parcel>>) -> HashMap<String, Vec<String>> {
fn group_to_group_full_dependencies(
direct_memberships: &HashMap<String, Vec<Parcel>>,
) -> HashMap<String, Vec<String>> {
let mut ggd = HashMap::new();
let direct_deps = group_to_group_direct_dependencies(direct_memberships);
for (group, directs) in &direct_deps {
Expand Down Expand Up @@ -208,7 +251,67 @@ impl ParcelUtils for Parcel {
}

fn parse_csv(text: &str) -> Vec<String> {
text.split(',').map(|v| v.to_owned()).collect() // TODO: trim etc.?
text.split(',').map(|v| v.to_owned()).collect() // TODO: trim etc.?
}

// Bindle client/auth utils, derived from github.com/deislabs/hippo-cli

use std::sync::Arc;

use bindle::client::{
tokens::{HttpBasic, NoToken, TokenManager},
Client, ClientBuilder,
};

#[derive(Clone)]
pub struct BindleConnectionInfo {
base_url: String,
allow_insecure: bool,
token_manager: AnyAuth,
}

impl BindleConnectionInfo {
pub fn new<I: Into<String>>(
base_url: I,
allow_insecure: bool,
username: Option<String>,
password: Option<String>,
) -> Self {
let token_manager: Box<dyn TokenManager + Send + Sync> = match (username, password) {
(Some(u), Some(p)) => Box::new(HttpBasic::new(&u, &p)),
_ => Box::new(NoToken::default()),
};

Self {
base_url: base_url.into(),
allow_insecure,
token_manager: AnyAuth {
token_manager: Arc::new(token_manager),
},
}
}

pub fn client(&self) -> bindle::client::Result<Client<AnyAuth>> {
let builder = ClientBuilder::default()
.http2_prior_knowledge(false)
.danger_accept_invalid_certs(self.allow_insecure);
builder.build(&self.base_url, self.token_manager.clone())
}
}

#[derive(Clone)]
pub struct AnyAuth {
token_manager: Arc<Box<dyn TokenManager + Send + Sync>>,
}

#[async_trait::async_trait]
impl TokenManager for AnyAuth {
async fn apply_auth_header(
&self,
builder: reqwest::RequestBuilder,
) -> bindle::client::Result<reqwest::RequestBuilder> {
self.token_manager.apply_auth_header(builder).await
}
}

#[cfg(test)]
Expand Down Expand Up @@ -394,7 +497,9 @@ mod test {
};

let membership_map = build_full_memberships(&inv);
let members = membership_map.get("coffee").expect("there should have been a group called 'coffee'");
let members = membership_map
.get("coffee")
.expect("there should have been a group called 'coffee'");
assert_eq!(2, members.len());
}
}
Loading

0 comments on commit 64ba587

Please sign in to comment.