First commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
2233
Cargo.lock
generated
Normal file
2233
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "rdockup"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
oci-client = "0.15.0"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
axum = "0.8"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
tower-http = { version = "0.6", features = ["trace"] }
|
||||
tracing-subscriber = "0.3"
|
||||
52
src/api.rs
Normal file
52
src/api.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
use axum::{
|
||||
Router,
|
||||
extract::Json,
|
||||
http::{HeaderMap, StatusCode},
|
||||
response::IntoResponse,
|
||||
routing::post,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::registry_client;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct TagRequest {
|
||||
image: String,
|
||||
}
|
||||
|
||||
fn validate_token(token: &str) -> bool {
|
||||
token == "my-secret-token"
|
||||
}
|
||||
|
||||
pub fn create_router() -> Router {
|
||||
Router::new().route("/tags", post(get_tags_handler))
|
||||
}
|
||||
|
||||
async fn get_tags_handler(
|
||||
headers: HeaderMap,
|
||||
Json(payload): Json<TagRequest>,
|
||||
) -> impl IntoResponse {
|
||||
// Extract Bearer token from Authorization header
|
||||
let token = headers
|
||||
.get("authorization")
|
||||
.and_then(|h| h.to_str().ok())
|
||||
.and_then(|s| s.strip_prefix("Bearer "))
|
||||
.unwrap_or("");
|
||||
|
||||
if !validate_token(token) {
|
||||
return (
|
||||
StatusCode::UNAUTHORIZED,
|
||||
[("content-type", "text/plain")],
|
||||
"Invalid or missing token".to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
match registry_client::get_tags(&payload.image).await {
|
||||
Ok(json) => (StatusCode::OK, [("content-type", "application/json")], json),
|
||||
Err(e) => (
|
||||
StatusCode::BAD_REQUEST,
|
||||
[("content-type", "text/plain")],
|
||||
format!("Error: {}", e),
|
||||
),
|
||||
}
|
||||
}
|
||||
21
src/main.rs
Normal file
21
src/main.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
mod api;
|
||||
mod registry_client;
|
||||
|
||||
// use axum::Router;
|
||||
use tower_http::trace::TraceLayer;
|
||||
use tracing_subscriber::{filter::LevelFilter, layer::SubscriberExt, util::SubscriberInitExt};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// Initialize logging for access logs
|
||||
tracing_subscriber::registry()
|
||||
.with(tracing_subscriber::fmt::layer())
|
||||
.with(LevelFilter::INFO)
|
||||
.init();
|
||||
|
||||
// Build app with routes from api module and add logging middleware
|
||||
let app = api::create_router().layer(TraceLayer::new_for_http());
|
||||
|
||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
}
|
||||
21
src/registry_client.rs
Normal file
21
src/registry_client.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
use oci_client::client::ClientConfig;
|
||||
use oci_client::{Client, Reference, secrets::RegistryAuth};
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct SerializableTags<'a> {
|
||||
name: &'a str,
|
||||
tags: &'a [String],
|
||||
}
|
||||
|
||||
pub async fn get_tags(image: &str) -> Result<String, Box<dyn std::error::Error>> {
|
||||
let client = Client::new(ClientConfig::default());
|
||||
let img_ref: Reference = image.parse()?;
|
||||
let auth = RegistryAuth::Anonymous;
|
||||
let tags = client.list_tags(&img_ref, &auth, None, None).await?;
|
||||
let serialized_tags = SerializableTags {
|
||||
name: &tags.name,
|
||||
tags: &tags.tags,
|
||||
};
|
||||
Ok(serde_json::to_string_pretty(&serialized_tags)?)
|
||||
}
|
||||
Reference in New Issue
Block a user