From 2fda6c7ea3a007355e86607140fefb5683b41cc4 Mon Sep 17 00:00:00 2001 From: Gaius Date: Tue, 5 Mar 2024 17:01:36 +0800 Subject: [PATCH] refactor: add dragonfly-client-backend crate (#298) Signed-off-by: Gaius --- Cargo.lock | 15 ++++++- Cargo.toml | 16 ++++--- Dockerfile | 3 ++ dragonfly-client-backend/Cargo.toml | 22 ++++++++++ .../src}/http.rs | 44 ++++++++++++++++--- .../src/lib.rs | 2 +- src/bin/dfdaemon/main.rs | 2 +- src/lib.rs | 1 - src/task/mod.rs | 3 +- src/task/piece.rs | 3 +- 10 files changed, 93 insertions(+), 18 deletions(-) create mode 100644 dragonfly-client-backend/Cargo.toml rename {src/backend => dragonfly-client-backend/src}/http.rs (69%) rename src/backend/mod.rs => dragonfly-client-backend/src/lib.rs (92%) diff --git a/Cargo.lock b/Cargo.lock index 7c90d98d..88f7d855 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -610,13 +610,13 @@ dependencies = [ "clap", "dashmap", "dragonfly-api", + "dragonfly-client-backend", "dragonfly-client-config", "dragonfly-client-core", "dragonfly-client-storage", "dragonfly-client-util", "fs2", "fslock", - "futures", "futures-util", "hashring", "http 1.0.0", @@ -662,6 +662,19 @@ dependencies = [ "warp", ] +[[package]] +name = "dragonfly-client-backend" +version = "0.1.17" +dependencies = [ + "dragonfly-client-core", + "futures", + "reqwest", + "rustls 0.21.10", + "rustls-pki-types", + "tokio", + "tokio-util", +] + [[package]] name = "dragonfly-client-config" version = "0.1.17" diff --git a/Cargo.toml b/Cargo.toml index 26239ba9..23ea395e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ name = "dfstore" path = "src/bin/dfstore/main.rs" [workspace] -members = ["dragonfly-client-config","dragonfly-client-core", "dragonfly-client-storage", "dragonfly-client-util"] +members = [ "dragonfly-client-backend","dragonfly-client-config","dragonfly-client-core", "dragonfly-client-storage", "dragonfly-client-util"] [workspace.package] version = "0.1.17" @@ -36,9 +36,10 @@ readme = "README.md" edition = "2021" [workspace.dependencies] -dragonfly-client-core = { path = "dragonfly-client-core", version = "*" } -dragonfly-client-config = { path = "dragonfly-client-config", version = "*" } -dragonfly-client-storage = { path = "dragonfly-client-storage", version = "*" } +dragonfly-client-core = { path = "dragonfly-client-core", version = "0.1.17" } +dragonfly-client-config = { path = "dragonfly-client-config", version = "0.1.17" } +dragonfly-client-storage = { path = "dragonfly-client-storage", version = "0.1.17" } +dragonfly-client-backend = { path = "dragonfly-client-backend", version = "0.1.17" } dragonfly-client-util = { path = "dragonfly-client-util", version = "*" } thiserror = "1.0" dragonfly-api = "2.0.102" @@ -46,6 +47,7 @@ reqwest = { version = "0.11.24", features = ["stream", "native-tls", "rustls-tls rcgen = { version = "0.12.1", features = ["x509-parser"] } hyper = { version = "1.1", features = ["full"] } hyper-util = { version = "0.1.2", features = ["client", "client-legacy", "tokio", "server-auto", "http1", "http2"] } +hyper-rustls = { version = "0.26", features = [ "http1", "http2", "logging" ] } http-range-header = "0.4.0" tracing = "0.1" url = "2.4.0" @@ -76,9 +78,11 @@ chrono = { version = "0.4.34", features = ["serde"] } dragonfly-client-core.workspace = true dragonfly-client-config.workspace = true dragonfly-client-storage.workspace = true +dragonfly-client-backend.workspace = true dragonfly-client-util.workspace = true rcgen.workspace = true hyper-util.workspace = true +hyper-rustls.workspace = true tracing.workspace = true validator.workspace = true humantime.workspace = true @@ -88,6 +92,7 @@ chrono.workspace = true prost-wkt-types.workspace = true tokio.workspace = true tokio-util.workspace = true +rustls-pki-types.workspace = true clap = { version = "4.5.1", features = [ "derive" ] } tracing-log = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } @@ -103,7 +108,6 @@ tonic-health = "0.9.2" tonic-reflection = "0.9.2" tokio-stream = "0.1.14" reqwest = { version = "0.11.24", features = ["stream", "native-tls", "rustls-tls"] } -futures = "0.3.28" bytes = "1.4" rocksdb = "0.22.0" dragonfly-api = "2.0.102" @@ -125,8 +129,6 @@ openssl = { version = "0.10", features = ["vendored"] } leaky-bucket = "1.0.1" hyper = { version = "1.1", features = ["full"] } tokio-rustls = "0.25" -hyper-rustls = { version = "0.26", features = [ "http1", "http2", "logging" ] } http-body-util = "0.1.0" futures-util = "0.3.30" rustls = "0.22.2" -rustls-pki-types = "1.2.0" diff --git a/Dockerfile b/Dockerfile index a697a38c..a670d9d0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,6 +16,9 @@ COPY dragonfly-client-config/src ./dragonfly-client-config/src COPY dragonfly-client-storage/Cargo.toml ./dragonfly-client-storage/Cargo.toml COPY dragonfly-client-storage/src ./dragonfly-client-storage/src +COPY dragonfly-client-backend/Cargo.toml ./dragonfly-client-backend/Cargo.toml +COPY dragonfly-client-backend/src ./dragonfly-client-backend/src + COPY dragonfly-client-util/Cargo.toml ./dragonfly-client-util/Cargo.toml COPY dragonfly-client-util/src ./dragonfly-client-util/src diff --git a/dragonfly-client-backend/Cargo.toml b/dragonfly-client-backend/Cargo.toml new file mode 100644 index 00000000..0587929c --- /dev/null +++ b/dragonfly-client-backend/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "dragonfly-client-backend" +description = "Backend for the dragonfly client" +version.workspace = true +authors.workspace = true +homepage.workspace = true +repository.workspace = true +keywords.workspace = true +license.workspace = true +readme.workspace = true +edition.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dragonfly-client-core.workspace = true +reqwest.workspace = true +tokio.workspace = true +tokio-util.workspace = true +rustls-pki-types.workspace = true +futures = "0.3.28" +rustls = "0.21.6" diff --git a/src/backend/http.rs b/dragonfly-client-backend/src/http.rs similarity index 69% rename from src/backend/http.rs rename to dragonfly-client-backend/src/http.rs index 543c6dbd..1154a4c9 100644 --- a/src/backend/http.rs +++ b/dragonfly-client-backend/src/http.rs @@ -1,5 +1,5 @@ /* - * Copyright 2023 The Dragonfly Authors + * Copyright 2024 The Dragonfly Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ use dragonfly_client_core::Result; use futures::TryStreamExt; use reqwest::header::HeaderMap; +use rustls_pki_types::CertificateDer; use std::time::Duration; use tokio::io::AsyncRead; use tokio_util::compat::FuturesAsyncReadCompatExt; @@ -31,6 +32,9 @@ pub struct Request { // timeout is the timeout of the request. pub timeout: Duration, + + // client_certs is the client certificates for the request. + pub client_certs: Option>>, } // HeadResponse is the head response for HTTP backend. @@ -70,7 +74,10 @@ impl HTTP { // the request method. Therefore, the signed URL of the GET method cannot be requested // through the HEAD method. Use GET request to replace of HEAD request // to get header and status code. - let mut request_builder = self.client()?.get(&request.url).headers(request.header); + let mut request_builder = self + .client(request.client_certs)? + .get(&request.url) + .headers(request.header); request_builder = request_builder.timeout(request.timeout); let response = request_builder.send().await?; @@ -85,7 +92,10 @@ impl HTTP { // Get gets the content of the request. pub async fn get(&self, request: Request) -> Result> { - let mut request_builder = self.client()?.get(&request.url).headers(request.header); + let mut request_builder = self + .client(request.client_certs)? + .get(&request.url) + .headers(request.header); request_builder = request_builder.timeout(request.timeout); let response = request_builder.send().await?; @@ -105,8 +115,32 @@ impl HTTP { } // client returns a new reqwest client. - fn client(&self) -> Result { - Ok(reqwest::Client::builder().build()?) + fn client( + &self, + client_certs: Option>>, + ) -> Result { + match client_certs { + Some(client_certs) => { + // TLS client config using the custom CA store for lookups. + let mut root_cert_store = rustls::RootCertStore::empty(); + root_cert_store.add_parsable_certificates(&client_certs); + let client_config = rustls::ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates(root_cert_store) + .with_no_client_auth(); + + let client = reqwest::Client::builder() + .use_preconfigured_tls(client_config) + .build()?; + + Ok(client) + } + None => { + // Default TLS client config with native roots. + let client = reqwest::Client::builder().build()?; + Ok(client) + } + } } } diff --git a/src/backend/mod.rs b/dragonfly-client-backend/src/lib.rs similarity index 92% rename from src/backend/mod.rs rename to dragonfly-client-backend/src/lib.rs index 780033dd..d34c9e1a 100644 --- a/src/backend/mod.rs +++ b/dragonfly-client-backend/src/lib.rs @@ -1,5 +1,5 @@ /* - * Copyright 2023 The Dragonfly Authors + * Copyright 2024 The Dragonfly Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/bin/dfdaemon/main.rs b/src/bin/dfdaemon/main.rs index d2b74517..4d01bfbc 100644 --- a/src/bin/dfdaemon/main.rs +++ b/src/bin/dfdaemon/main.rs @@ -16,7 +16,6 @@ use clap::Parser; use dragonfly_client::announcer::{ManagerAnnouncer, SchedulerAnnouncer}; -use dragonfly_client::backend::http::HTTP; use dragonfly_client::dynconfig::Dynconfig; use dragonfly_client::gc::GC; use dragonfly_client::grpc::{ @@ -28,6 +27,7 @@ use dragonfly_client::proxy::Proxy; use dragonfly_client::shutdown; use dragonfly_client::task::Task; use dragonfly_client::tracing::init_tracing; +use dragonfly_client_backend::http::HTTP; use dragonfly_client_config::dfdaemon; use dragonfly_client_storage::Storage; use dragonfly_client_util::id_generator::IDGenerator; diff --git a/src/lib.rs b/src/lib.rs index 3cbcee59..bc6d908a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,6 @@ */ pub mod announcer; -pub mod backend; pub mod dynconfig; pub mod gc; pub mod grpc; diff --git a/src/task/mod.rs b/src/task/mod.rs index d200ac17..119a5d4e 100644 --- a/src/task/mod.rs +++ b/src/task/mod.rs @@ -14,7 +14,6 @@ * limitations under the License. */ -use crate::backend::http::{Request as HTTPRequest, HTTP}; use crate::grpc::{scheduler::SchedulerClient, REQUEST_TIMEOUT}; use dragonfly_api::common::v2::Range; use dragonfly_api::common::v2::{Download, Peer, Piece, TrafficType}; @@ -32,6 +31,7 @@ use dragonfly_api::scheduler::v2::{ DownloadPieceFailedRequest, DownloadPieceFinishedRequest, RegisterPeerRequest, RescheduleRequest, }; +use dragonfly_client_backend::http::{Request as HTTPRequest, HTTP}; use dragonfly_client_config::dfdaemon::Config; use dragonfly_client_core::{ DownloadFromRemotePeerFailed, Error, HTTPError, Result as ClientResult, @@ -136,6 +136,7 @@ impl Task { url: download.url, header: request_header, timeout: self.config.download.piece_timeout, + client_certs: None, }) .await?; diff --git a/src/task/piece.rs b/src/task/piece.rs index 4243c550..2517c71f 100644 --- a/src/task/piece.rs +++ b/src/task/piece.rs @@ -14,11 +14,11 @@ * limitations under the License. */ -use crate::backend::http::{Request as HTTPRequest, HTTP}; use crate::grpc::dfdaemon_upload::DfdaemonUploadClient; use chrono::Utc; use dragonfly_api::common::v2::{Peer, Range}; use dragonfly_api::dfdaemon::v2::DownloadPieceRequest; +use dragonfly_client_backend::http::{Request as HTTPRequest, HTTP}; use dragonfly_client_config::dfdaemon::Config; use dragonfly_client_core::{Error, HTTPError, Result}; use dragonfly_client_storage::{metadata, Storage}; @@ -367,6 +367,7 @@ impl Piece { url: url.to_string(), header: request_header.to_owned(), timeout: self.config.download.piece_timeout, + client_certs: None, }) .await .map_err(|err| {