Radish alpha
r
Radicle web interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
httpd: Update axum from 0.5.x to 0.6.x
xphoniex committed 3 years ago
commit 59e3afac6750ef5b1fc410100890e631e96e34a5
parent 64a933dccdda6b2c79c77a32be9accd5978214b5
8 files changed +57 -49
modified radicle-httpd/Cargo.toml
@@ -16,8 +16,8 @@ logfmt = [

[dependencies]
anyhow = { version = "1" }
-
axum = { version = "0.5.16", default-features = false, features = ["json", "headers", "query"] }
-
axum-server = { version = "0.4.2", default-features = false }
+
axum = { version = "0.6.2", default-features = false, features = ["headers", "json", "query", "tokio"] }
+
axum-server = { version = "0.4.4", default-features = false }
chrono = { version = "0.4.22" }
ethers-core = { version = "1.0" }
fastrand = { version = "1.7.0" }
modified radicle-httpd/src/api/axum_extra.rs
@@ -1,6 +1,7 @@
use axum::extract::path::ErrorKind;
use axum::extract::rejection::{PathRejection, QueryRejection};
-
use axum::extract::{FromRequest, RequestParts};
+
use axum::extract::FromRequestParts;
+
use axum::http::request::Parts;
use axum::http::StatusCode;
use axum::{async_trait, Json};

@@ -10,15 +11,15 @@ use serde::Serialize;
pub struct Path<T>(pub T);

#[async_trait]
-
impl<B, T> FromRequest<B> for Path<T>
+
impl<S, T> FromRequestParts<S> for Path<T>
where
    T: DeserializeOwned + Send,
-
    B: Send,
+
    S: Send + Sync,
{
    type Rejection = (StatusCode, axum::Json<Error>);

-
    async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
-
        match axum::extract::Path::<T>::from_request(req).await {
+
    async fn from_request_parts(req: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
+
        match axum::extract::Path::<T>::from_request_parts(req, state).await {
            Ok(value) => Ok(Self(value.0)),
            Err(rejection) => {
                let status = StatusCode::BAD_REQUEST;
@@ -52,15 +53,15 @@ where
pub struct Query<T>(pub T);

#[async_trait]
-
impl<B, T> FromRequest<B> for Query<T>
+
impl<S, T> FromRequestParts<S> for Query<T>
where
    T: DeserializeOwned + Send,
-
    B: Send,
+
    S: Send + Sync,
{
    type Rejection = (StatusCode, axum::Json<Error>);

-
    async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
-
        match axum::extract::Query::<T>::from_request(req).await {
+
    async fn from_request_parts(req: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
+
        match axum::extract::Query::<T>::from_request_parts(req, state).await {
            Ok(value) => Ok(Self(value.0)),
            Err(rejection) => {
                let status = StatusCode::BAD_REQUEST;
modified radicle-httpd/src/api/v1/delegates.rs
@@ -1,6 +1,7 @@
+
use axum::extract::State;
use axum::response::IntoResponse;
use axum::routing::get;
-
use axum::{Extension, Json, Router};
+
use axum::{Json, Router};

use radicle::cob::issue::Issues;
use radicle::identity::Did;
@@ -18,13 +19,13 @@ pub fn router(ctx: Context) -> Router {
            "/delegates/:delegate/projects",
            get(delegates_projects_handler),
        )
-
        .layer(Extension(ctx))
+
        .with_state(ctx)
}

/// List all projects which delegate is a part of.
/// `GET /delegates/:delegate/projects`
async fn delegates_projects_handler(
-
    Extension(ctx): Extension<Context>,
+
    State(ctx): State<Context>,
    Path(delegate): Path<Did>,
    Query(qs): Query<PaginationQuery>,
) -> impl IntoResponse {
modified radicle-httpd/src/api/v1/node.rs
@@ -1,6 +1,7 @@
+
use axum::extract::State;
use axum::response::IntoResponse;
use axum::routing::get;
-
use axum::{Extension, Json, Router};
+
use axum::{Json, Router};
use serde_json::json;

use radicle::node::NodeId;
@@ -12,12 +13,12 @@ pub fn router(ctx: Context) -> Router {

    Router::new()
        .route("/node", get(node_handler))
-
        .layer(Extension(node_id))
+
        .with_state(node_id)
}

/// Return the node id for the node identity.
/// `GET /node`
-
async fn node_handler(Extension(node_id): Extension<NodeId>) -> impl IntoResponse {
+
async fn node_handler(State(node_id): State<NodeId>) -> impl IntoResponse {
    let response = json!({
        "id": node_id.to_string(),
    });
modified radicle-httpd/src/api/v1/projects.rs
@@ -1,10 +1,11 @@
use std::collections::BTreeMap;

+
use axum::extract::State;
use axum::handler::Handler;
use axum::http::{header, HeaderValue};
use axum::response::IntoResponse;
use axum::routing::get;
-
use axum::{Extension, Json, Router};
+
use axum::{Json, Router};
use hyper::StatusCode;
use serde::{Deserialize, Serialize};
use serde_json::json;
@@ -40,6 +41,7 @@ pub fn router(ctx: Context) -> Router {
                )),
            ),
        )
+
        .route("/projects/:project/tree/:sha/", get(tree_handler_root))
        .route("/projects/:project/tree/:sha/*path", get(tree_handler))
        .route("/projects/:project/remotes", get(remotes_handler))
        .route("/projects/:project/remotes/:peer", get(remote_handler))
@@ -47,13 +49,13 @@ pub fn router(ctx: Context) -> Router {
        .route("/projects/:project/readme/:sha", get(readme_handler))
        .route("/projects/:project/issues", get(issues_handler))
        .route("/projects/:project/issues/:id", get(issue_handler))
-
        .layer(Extension(ctx))
+
        .with_state(ctx)
}

/// List all projects.
/// `GET /projects`
async fn project_root_handler(
-
    Extension(ctx): Extension<Context>,
+
    State(ctx): State<Context>,
    Query(qs): Query<PaginationQuery>,
) -> impl IntoResponse {
    let PaginationQuery { page, per_page } = qs;
@@ -87,10 +89,7 @@ async fn project_root_handler(

/// Get project metadata.
/// `GET /projects/:project`
-
async fn project_handler(
-
    Extension(ctx): Extension<Context>,
-
    Path(id): Path<Id>,
-
) -> impl IntoResponse {
+
async fn project_handler(State(ctx): State<Context>, Path(id): Path<Id>) -> impl IntoResponse {
    let info = ctx.project_info(id)?;

    Ok::<_, Error>(Json(info))
@@ -109,7 +108,7 @@ pub struct CommitsQueryString {
/// Get project commit range.
/// `GET /projects/:project/commits?since=<sha>`
async fn history_handler(
-
    Extension(ctx): Extension<Context>,
+
    State(ctx): State<Context>,
    Path(project): Path<Id>,
    Query(qs): Query<CommitsQueryString>,
) -> impl IntoResponse {
@@ -194,7 +193,7 @@ async fn history_handler(
/// Get project commit.
/// `GET /projects/:project/commits/:sha`
async fn commit_handler(
-
    Extension(ctx): Extension<Context>,
+
    State(ctx): State<Context>,
    Path((project, sha)): Path<(Id, Oid)>,
) -> impl IntoResponse {
    let storage = &ctx.profile.storage;
@@ -220,7 +219,7 @@ async fn commit_handler(
/// Get project activity for the past year.
/// `GET /projects/:project/activity`
async fn activity_handler(
-
    Extension(ctx): Extension<Context>,
+
    State(ctx): State<Context>,
    Path(project): Path<Id>,
) -> impl IntoResponse {
    let current_date = chrono::Utc::now().timestamp();
@@ -244,13 +243,21 @@ async fn activity_handler(
    Ok::<_, Error>((StatusCode::OK, Json(json!({ "activity": timestamps }))))
}

+
/// Get project source tree for '/' path.
+
/// `GET /projects/:project/tree/:sha/`
+
async fn tree_handler_root(
+
    State(ctx): State<Context>,
+
    Path((project, sha)): Path<(Id, Oid)>,
+
) -> impl IntoResponse {
+
    tree_handler(State(ctx), Path((project, sha, String::new()))).await
+
}
+

/// Get project source tree.
/// `GET /projects/:project/tree/:sha/*path`
async fn tree_handler(
-
    Extension(ctx): Extension<Context>,
+
    State(ctx): State<Context>,
    Path((project, sha, path)): Path<(Id, Oid, String)>,
) -> impl IntoResponse {
-
    let path = path.strip_prefix('/').ok_or(Error::NotFound)?.to_string();
    let storage = &ctx.profile.storage;
    let repo = Repository::open(paths::repository(storage, &project))?;
    let tree = repo.tree(sha, &path)?;
@@ -262,10 +269,7 @@ async fn tree_handler(

/// Get all project remotes.
/// `GET /projects/:project/remotes`
-
async fn remotes_handler(
-
    Extension(ctx): Extension<Context>,
-
    Path(project): Path<Id>,
-
) -> impl IntoResponse {
+
async fn remotes_handler(State(ctx): State<Context>, Path(project): Path<Id>) -> impl IntoResponse {
    let storage = &ctx.profile.storage;
    let repo = storage.repository(project)?;
    let remotes = repo
@@ -296,7 +300,7 @@ async fn remotes_handler(
/// Get project remote.
/// `GET /projects/:project/remotes/:peer`
async fn remote_handler(
-
    Extension(ctx): Extension<Context>,
+
    State(ctx): State<Context>,
    Path((project, node_id)): Path<(Id, NodeId)>,
) -> impl IntoResponse {
    let storage = &ctx.profile.storage;
@@ -323,14 +327,13 @@ async fn remote_handler(
/// Get project source file.
/// `GET /projects/:project/blob/:sha/*path`
async fn blob_handler(
-
    Extension(ctx): Extension<Context>,
+
    State(ctx): State<Context>,
    Path((project, sha, path)): Path<(Id, Oid, String)>,
) -> impl IntoResponse {
-
    let path = path.strip_prefix('/').ok_or(Error::NotFound)?;
    let storage = &ctx.profile.storage;
    let repo = Repository::open(paths::repository(storage, &project))?;
    let blob = repo.blob(sha, &path)?;
-
    let response = api::json::blob(&blob, path);
+
    let response = api::json::blob(&blob, &path);

    Ok::<_, Error>(Json(response))
}
@@ -338,7 +341,7 @@ async fn blob_handler(
/// Get project readme.
/// `GET /projects/:project/readme/:sha`
async fn readme_handler(
-
    Extension(ctx): Extension<Context>,
+
    State(ctx): State<Context>,
    Path((project, sha)): Path<(Id, Oid)>,
) -> impl IntoResponse {
    let storage = &ctx.profile.storage;
@@ -365,7 +368,7 @@ async fn readme_handler(
/// Get project issues list.
/// `GET /projects/:project/issues`
async fn issues_handler(
-
    Extension(ctx): Extension<Context>,
+
    State(ctx): State<Context>,
    Path(project): Path<Id>,
    Query(qs): Query<PaginationQuery>,
) -> impl IntoResponse {
@@ -399,7 +402,7 @@ async fn issues_handler(
/// Get project issue.
/// `GET /projects/:project/issues/:id`
async fn issue_handler(
-
    Extension(ctx): Extension<Context>,
+
    State(ctx): State<Context>,
    Path((project, issue_id)): Path<(Id, Oid)>,
) -> impl IntoResponse {
    let storage = &ctx.profile.storage;
modified radicle-httpd/src/api/v1/sessions.rs
@@ -4,9 +4,10 @@ use std::env;
use std::iter::repeat_with;
use std::str::FromStr;

+
use axum::extract::State;
use axum::response::IntoResponse;
use axum::routing::{get, post};
-
use axum::{Extension, Json, Router};
+
use axum::{Json, Router};
use ethers_core::utils::hex;
use hyper::http::uri::Authority;
use serde_json::json;
@@ -27,12 +28,12 @@ pub fn router(ctx: Context) -> Router {
            "/sessions/:id",
            get(session_get_handler).put(session_signin_handler),
        )
-
        .layer(Extension(ctx))
+
        .with_state(ctx)
}

/// Create session.
/// `POST /sessions`
-
async fn session_create_handler(Extension(ctx): Extension<Context>) -> impl IntoResponse {
+
async fn session_create_handler(State(ctx): State<Context>) -> impl IntoResponse {
    let expiration_time = OffsetDateTime::now_utc()
        .checked_add(UNAUTHORIZED_SESSIONS_EXPIRATION)
        .unwrap();
@@ -45,7 +46,7 @@ async fn session_create_handler(Extension(ctx): Extension<Context>) -> impl Into
/// Get session.
/// `GET /sessions/:id`
async fn session_get_handler(
-
    Extension(ctx): Extension<Context>,
+
    State(ctx): State<Context>,
    Path(id): Path<String>,
) -> impl IntoResponse {
    let sessions = ctx.sessions.read().await;
@@ -67,7 +68,7 @@ async fn session_get_handler(
/// Update session.
/// `PUT /sessions/:id`
async fn session_signin_handler(
-
    Extension(ctx): Extension<Context>,
+
    State(ctx): State<Context>,
    Path(id): Path<String>,
    Json(request): Json<AuthRequest>,
) -> impl IntoResponse {
modified radicle-httpd/src/api/v1/stats.rs
@@ -1,6 +1,7 @@
+
use axum::extract::State;
use axum::response::IntoResponse;
use axum::routing::get;
-
use axum::{Extension, Json, Router};
+
use axum::{Json, Router};
use serde_json::json;

use crate::api::error::Error;
@@ -9,12 +10,12 @@ use crate::api::Context;
pub fn router(ctx: Context) -> Router {
    Router::new()
        .route("/stats", get(stats_handler))
-
        .layer(Extension(ctx))
+
        .with_state(ctx)
}

/// Return the stats for the node.
/// `GET /stats`
-
async fn stats_handler(Extension(ctx): Extension<Context>) -> impl IntoResponse {
+
async fn stats_handler(State(ctx): State<Context>) -> impl IntoResponse {
    let storage = &ctx.profile.storage;
    let projects = storage.projects()?.len();

modified radicle-httpd/src/lib.rs
@@ -98,9 +98,9 @@ async fn git_handler(
    AxumPath((project, request)): AxumPath<(String, String)>,
    method: Method,
    headers: HeaderMap,
-
    body: Bytes,
    ConnectInfo(remote): ConnectInfo<SocketAddr>,
    query: RawQuery,
+
    body: Bytes,
) -> impl IntoResponse {
    let query = query.0.unwrap_or_default();
    let id: Id = project.strip_suffix(".git").unwrap_or(&project).parse()?;