From 3aea275d8f27d5b94469ad9bcae814b4163b20ed Mon Sep 17 00:00:00 2001 From: Gabriel Simmer Date: Sun, 16 Jul 2023 19:20:39 +0100 Subject: [PATCH] Split common functions into lib.rs --- Cargo.lock | 4 +-- Cargo.toml | 6 ++-- flake.nix | 12 ++++---- src/lib.rs | 58 +++++++++++++++++++++++++++++++++++ src/main.rs | 88 +++++++++++------------------------------------------ 5 files changed, 87 insertions(+), 81 deletions(-) create mode 100644 src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 4508954..e3f7b25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -170,8 +170,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] -name = "docker-rs-dashboard" -version = "0.1.0" +name = "dref" +version = "0.2.0" dependencies = [ "axum", "axum-extra", diff --git a/Cargo.toml b/Cargo.toml index b5f74f4..dad852c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "docker-rs-dashboard" -version = "0.1.0" +name = "dref" +version = "0.2.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -13,4 +13,4 @@ futures = "0.3" axum-extra = { version = "0.4.2", features = ["spa"] } reqwest = { version = "0.11", features = ["json"] } serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" \ No newline at end of file +serde_json = "1.0" diff --git a/flake.nix b/flake.nix index 526679d..98bf3a1 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,5 @@ { - description = "Build a cargo project without extra checks"; + description = "Docker registry frontend & basic library"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; @@ -22,7 +22,7 @@ }; craneLib = crane.lib.${system}; - my-crate = craneLib.buildPackage { + dref = craneLib.buildPackage { src = craneLib.cleanCargoSource ./.; buildInputs = [ @@ -38,7 +38,7 @@ dockerImage = pkgs.dockerTools.buildImage { name = "dref"; config = { - Cmd = [ "${my-crate}/bin/docker-rs-dashboard" ]; + Cmd = [ "${dref}/bin/dref" ]; ExposedPorts = { "3000/tcp" = {}; }; @@ -47,15 +47,15 @@ in { checks = { - inherit my-crate; + inherit dref; }; apps.default = flake-utils.lib.mkApp { - drv = my-crate; + drv = dref; }; packages = rec { - bin = my-crate; + bin = dref; docker = dockerImage; default = pkgs.symlinkJoin { name = "dref-${bin.version}"; diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..893da74 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,58 @@ +use std::collections::HashMap; +use std::{boxed, error}; +use serde::{Serialize, Deserialize}; + +#[derive(Clone)] +pub struct Registry { + pub url: String, +} + +#[derive(Debug)] +pub struct Image { + pub name: String, +} + +#[derive(Debug)] +pub struct RichTag { + pub name: String, + architectures: Vec +} + +#[derive(Deserialize)] +struct Tags { + name: String, + tags: Vec +} + +impl Registry { + pub async fn images(&self) -> Result, boxed::Box> { + let resq_url = format!("{}/v2/_catalog", self.url); + let resp = reqwest::get(resq_url) + .await? + .json::>>() + .await?; + let i = resp.get("repositories").unwrap().into_iter().map(|i| async { + Image{ + name: i.to_string(), + } + }); + let images: Vec = futures::future::join_all(i).await; + Ok(images) + } + pub async fn image_tags(&self, image: String) -> Result, boxed::Box> { + let resq_url = format!("{}/v2/{}/tags/list", self.url, image); + let resp: Tags = reqwest::get(resq_url) + .await? + .json::() + .await?; + let i = resp.tags.into_iter().map(|i| async move { + RichTag{ + name: i.to_string(), + architectures: Vec::new(), + } + }); + let tags: Vec = futures::future::join_all(i).await; + Ok(tags) + } +} + diff --git a/src/main.rs b/src/main.rs index 0dab755..08b6b33 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,33 +2,24 @@ mod css; use std::{boxed, error, env, collections::{HashMap, self}}; use maud::{html, Markup, DOCTYPE}; -use axum::{Router, routing::get, response::IntoResponse}; -use futures::{stream::StreamExt, future::join_all}; -use serde::{Serialize, Deserialize}; +use axum::{Router, routing::get, response::IntoResponse, extract::State}; +use dref; -// To be expanded upon. -#[derive(Debug)] -struct Image { - name: String, - tags: Vec, -} -#[derive(Debug)] -struct RichTag { - name: String, - architectures: Vec -} - -#[derive(Deserialize)] -struct Tags { - name: String, - tags: Vec +#[derive(Clone)] +struct AppState { + registry: dref::Registry } #[tokio::main(flavor = "multi_thread", worker_threads = 10)] async fn main() { + let registry = dref::Registry{ + url: env::var("DREF_REGISTRY").unwrap(), + }; + let state = AppState {registry}; // build our application with a single route let app = Router::new() - .route("/", get(root)).route("/styles.css", get(css)); + .route("/", get(root)).route("/styles.css", get(css)) + .with_state(state); // run it with hyper on localhost:3000 println!("Running webserver on port :3000"); @@ -48,7 +39,7 @@ async fn css() -> impl IntoResponse { fn header(page_title: &str) -> Markup { html! { (DOCTYPE) - meta charset="utf-8"; + meta charset="utf-8"; title { (page_title) } link rel="stylesheet" href="/styles.css"; } @@ -61,29 +52,23 @@ fn footer() -> Markup { } } -async fn root() -> Markup { - let c = get_images().await.unwrap_or_else(|e| panic!("{}", e)); +async fn root(State(state): State) -> Markup { + let c = state.registry.images().await.unwrap(); html! { (header("/DREF")) body { main { h1 { "/DREF" } hr; - @for image in &c { + @for image in c { div { details { summary { (image.name) } ul { - @for tag in &image.tags { - li { (tag.name) - // div { - // @for arch in &tag.architectures { - // span { (arch) } - // } - // } - } + @for tag in state.registry.image_tags(image.name).await.unwrap() { + li { (tag.name) } } - } + } } } } @@ -92,40 +77,3 @@ async fn root() -> Markup { (footer()) } } - -async fn get_images() -> Result, boxed::Box> { - let host = env::var("DREF_REGISTRY").unwrap(); - let resp = reqwest::get(host + "/v2/_catalog") - .await? - .json::>>() - .await?; - let i = resp.get("repositories").unwrap().into_iter().map(|i| async { - let tags = get_tags(i.to_string()).await; - Image{ - name: i.to_string(), - tags: tags.unwrap(), - } - }); - let images: Vec = futures::future::join_all(i).await; - Ok(images) -} - -async fn get_tags(image: String) -> Result, boxed::Box> { - let host = env::var("DREF_REGISTRY").unwrap(); - let resp: Tags = reqwest::get(host + "/v2/" + &image + "/tags/list") - .await? - .json::() - .await?; - let i = resp.tags.into_iter().map(|i| async move { - RichTag{ - name: i.to_string(), - architectures: Vec::new(), - } - }); - let tags: Vec = futures::future::join_all(i).await; - Ok(tags) -} - -async fn get_platforms(image: &String, tag: String) -> Result, boxed::Box> { - todo!() -}