Skip to content

Commit

Permalink
Begin work on OCI example.
Browse files Browse the repository at this point in the history
  • Loading branch information
CathalMullan committed Aug 30, 2024
1 parent e9a8342 commit 2872fbd
Show file tree
Hide file tree
Showing 12 changed files with 137 additions and 137 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ corpus
artifacts
coverage

# OCI
junit.xml
report.html

# Nix
result
result-dev
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ fn main() -> Result<(), Box<dyn Error>> {
router.insert("/user/logout", 12)?;
router.insert("/user/{username}", 13)?;

assert_eq!(router.to_string(), ROUTER_DISPLAY.trim_start());
assert_eq!(router.to_string(), ROUTER_DISPLAY.trim());
Ok(())
}
```
Expand Down
2 changes: 1 addition & 1 deletion examples/hyper/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ publish = false
version.workspace = true
authors.workspace = true
edition.workspace = true
rust-version.workspace = true
repository.workspace = true
license.workspace = true
keywords.workspace = true
Expand All @@ -28,3 +27,4 @@ bytes = "1.7"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
anyhow = "1.0"
regex = "1.10"
7 changes: 7 additions & 0 deletions examples/hyper/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# `hyper` example

This is a mini implementation of an [Open Container Initiative (OCI) Distribution Specification](https://github.com/opencontainers/distribution-spec/blob/main/spec.md) registry.

## Inspirations:
- https://github.com/mcronce/oci-registry
- https://github.com/Trow-Registry/trow
90 changes: 7 additions & 83 deletions examples/hyper/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,54 +1,28 @@
#![allow(clippy::unused_async)]

use bytes::Bytes;
use http_body_util::{combinators::BoxBody, BodyExt, Full};
use hyper::{body::Incoming, header, service::service_fn, Request, Response, StatusCode};
use hyper::{body::Incoming, service::service_fn, Request};
use hyper_util::{
rt::{TokioExecutor, TokioIo},
server::conn::auto::Builder,
};
use routes::router;
use std::{
convert::Infallible,
future::Future,
net::{IpAddr, Ipv4Addr, SocketAddr},
pin::Pin,
sync::Arc,
};
use tokio::{net::TcpListener, task::JoinSet};
use wayfind::{Parameter, Path, Router};

type BoxFuture<'a> = Pin<
Box<
dyn Future<Output = Result<Response<BoxBody<Bytes, Infallible>>, anyhow::Error>>
+ Send
+ 'a,
>,
>;
use wayfind::Path;

type HandlerFn =
Arc<dyn for<'a> Fn(&'a str, &'a [Parameter<'_, 'a>]) -> BoxFuture<'a> + Send + Sync>;
pub mod routes;

#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
let mut router: Router<HandlerFn> = Router::new();
router.insert(
"/",
Arc::new(move |path, parameters| Box::pin(index_route(path, parameters))),
)?;
router.insert(
"/hello/{name}",
Arc::new(move |path, parameters| Box::pin(hello_route(path, parameters))),
)?;
router.insert(
"{*catch_all}",
Arc::new(move |path, parameters| Box::pin(not_found(path, parameters))),
)?;

let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 1337);
let listener = TcpListener::bind(&socket).await?;
println!("Listening on http://{socket}");

let router = router()?;
println!("Router:\n{router}");
let router = Arc::new(router);

let mut join_set = JoinSet::new();

loop {
Expand Down Expand Up @@ -81,53 +55,3 @@ async fn main() -> Result<(), anyhow::Error> {
});
}
}

async fn index_route(
_: &'_ str,
_: &'_ [Parameter<'_, '_>],
) -> Result<Response<BoxBody<Bytes, Infallible>>, anyhow::Error> {
let json = serde_json::json!({
"hello": "world"
});

let body = Full::new(Bytes::from(json.to_string()));
let response = Response::builder()
.header(header::CONTENT_TYPE, "application/json")
.body(body.boxed())?;

Ok(response)
}

async fn hello_route(
_: &'_ str,
parameters: &'_ [Parameter<'_, '_>],
) -> Result<Response<BoxBody<Bytes, Infallible>>, anyhow::Error> {
let name = parameters[0].value;
let json = serde_json::json!({
"hello": name,
});

let body = Full::new(Bytes::from(json.to_string()));
let response = Response::builder()
.header(header::CONTENT_TYPE, "application/json")
.body(body.boxed())?;

Ok(response)
}

async fn not_found(
path: &'_ str,
_: &'_ [Parameter<'_, '_>],
) -> Result<Response<BoxBody<Bytes, Infallible>>, anyhow::Error> {
let json = serde_json::json!({
"error": "route_not_found",
"route": path,
});

let body = Full::new(Bytes::from(json.to_string()));
let response = Response::builder()
.status(StatusCode::NOT_FOUND)
.body(body.boxed())?;

Ok(response)
}
32 changes: 32 additions & 0 deletions examples/hyper/src/routes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#![allow(clippy::unused_async)]

use bytes::Bytes;
use http_body_util::combinators::BoxBody;
use hyper::Response;
use index::index_route;
use std::{convert::Infallible, future::Future, pin::Pin, sync::Arc};
use wayfind::{errors::InsertError, Parameter, Router};

pub mod index;

type BoxFuture<'a> = Pin<
Box<
dyn Future<Output = Result<Response<BoxBody<Bytes, Infallible>>, anyhow::Error>>
+ Send
+ 'a,
>,
>;

type HandlerFn =
Arc<dyn for<'a> Fn(&'a str, &'a [Parameter<'_, 'a>]) -> BoxFuture<'a> + Send + Sync>;

pub fn router() -> Result<Router<HandlerFn>, InsertError> {
let mut router: Router<HandlerFn> = Router::new();

router.insert(
"/",
Arc::new(move |path, parameters| Box::pin(index_route(path, parameters))),
)?;

Ok(router)
}
21 changes: 21 additions & 0 deletions examples/hyper/src/routes/index.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use bytes::Bytes;
use http_body_util::{combinators::BoxBody, BodyExt, Full};
use hyper::{header, Response};
use std::convert::Infallible;
use wayfind::Parameter;

pub async fn index_route(
_: &'_ str,
_: &'_ [Parameter<'_, '_>],
) -> Result<Response<BoxBody<Bytes, Infallible>>, anyhow::Error> {
let json = serde_json::json!({
"hello": "world"
});

let body = Full::new(Bytes::from(json.to_string()));
let response = Response::builder()
.header(header::CONTENT_TYPE, "application/json")
.body(body.boxed())?;

Ok(response)
}
4 changes: 4 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
(self: super: {
cargo-codspeed = pkgs.callPackage ./nix/pkgs/cargo-codspeed {};
cargo-insta = pkgs.callPackage ./nix/pkgs/cargo-insta {};
oci-distribution-spec-conformance = pkgs.callPackage ./nix/pkgs/oci-distribution-spec-conformance {};
})
];
};
Expand Down Expand Up @@ -70,6 +71,9 @@
# Release
cargo-semver-checks

# OCI
oci-distribution-spec-conformance

# Nix
alejandra
statix
Expand Down
38 changes: 38 additions & 0 deletions nix/pkgs/oci-distribution-spec-conformance/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
lib,
buildGoModule,
fetchFromGitHub,
}:
buildGoModule rec {
pname = "oci-distribution-spec-conformance";
version = "1.1.0";

src = fetchFromGitHub {
owner = "opencontainers";
repo = "distribution-spec";
rev = "v${version}";
hash = "sha256-GL28YUwDRicxS65E7SDR/Q3tJOWN4iwgq4AGBjwVPzA=";
};

sourceRoot = "source/conformance";
vendorHash = "sha256-5gn9RpjCALZB/GFjlJHDqPs2fIHl7NJr5QjPmsLnnO4=";

CGO_ENABLED = 0;

postInstall = ''
go test -c ./... -o oci-distribution-spec-conformance
mkdir -p $out/bin
mv oci-distribution-spec-conformance $out/bin
'';

doCheck = false;

meta = with lib; {
description = " OCI Distribution Specification Conformance Tests";
mainProgram = "oci-distribution-spec-conformance";
homepage = "https://opencontainers.org";
changelog = "https://github.com/opencontainers/distribution-spec/releases/tag/v${version}";
license = licenses.asl20;
platforms = platforms.all;
};
}
71 changes: 20 additions & 51 deletions src/node/display.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use super::Node;
use crate::node::NodeKind;
use std::fmt::Display;
use std::fmt::{Display, Write};

impl<T> Display for Node<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn debug_node<T>(
f: &mut std::fmt::Formatter,
output: &mut String,
node: &Node<T>,
padding: &str,
is_root: bool,
Expand Down Expand Up @@ -41,10 +41,10 @@ impl<T> Display for Node<T> {
.map_or(String::new(), |_node_data| " [*]".to_string());

if is_root {
writeln!(f, "{key}")?;
writeln!(output, "{key}")?;
} else {
let branch = if is_last { "╰─" } else { "├─" };
writeln!(f, "{padding}{branch} {key}{value}")?;
writeln!(output, "{padding}{branch} {key}{value}")?;
}

// Ensure we align children correctly
Expand All @@ -57,63 +57,32 @@ impl<T> Display for Node<T> {
format!("{padding}│ {extra_spacing}")
};

let has_dynamic_children = !node.dynamic_children.is_empty();
let has_wildcard_children = !node.wildcard_children.is_empty();
let has_end_wildcard = !node.end_wildcard_children.is_empty();

// Recursively print the static children
let static_count = node.static_children.len();
for (index, child) in node.static_children.iter().enumerate() {
let is_last = if has_dynamic_children || has_wildcard_children || has_end_wildcard {
false
} else {
index == (static_count - 1)
};

debug_node(f, child, &new_prefix, false, is_last)?;
}

// Recursively print dynamic children
let dynamic_count = node.dynamic_children.len();
for (index, child) in node.dynamic_children.iter().enumerate() {
let is_last = if has_wildcard_children || has_end_wildcard {
false
} else {
index == (dynamic_count - 1)
};

debug_node(f, child, &new_prefix, false, is_last)?;
}

// Recursively print wildcard children
let wildcard_count = node.wildcard_children.len();
for (index, child) in node.wildcard_children.iter().enumerate() {
let is_last = if has_end_wildcard {
false
} else {
index == (wildcard_count - 1)
};

debug_node(f, child, &new_prefix, false, is_last)?;
}

// Recursively print end wildcard children
let end_wildcard_count = node.end_wildcard_children.len();
for (index, child) in node.end_wildcard_children.iter().enumerate() {
let is_last = index == (end_wildcard_count - 1);
debug_node(f, child, &new_prefix, false, is_last)?;
// Chain all children together, in order
let all_children = node
.static_children
.iter()
.chain(node.dynamic_children.iter())
.chain(node.wildcard_children.iter())
.chain(node.end_wildcard_children.iter());

let total_children = all_children.clone().count();
for (index, child) in all_children.enumerate() {
let is_last = index == total_children - 1;
debug_node(output, child, &new_prefix, false, is_last)?;
}

Ok(())
}

let mut output = String::new();

let padding = if self.prefix.is_empty() {
String::new()
} else {
" ".repeat(self.prefix.len() - 1)
};

debug_node(f, self, &padding, true, true)?;
Ok(())
debug_node(&mut output, self, &padding, true, true)?;
write!(f, "{}", output.trim_end())
}
}
2 changes: 1 addition & 1 deletion src/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ impl<T> Default for Router<T> {
}
}

impl<T: Display> Display for Router<T> {
impl<T> Display for Router<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.root)
}
Expand Down

0 comments on commit 2872fbd

Please sign in to comment.