后端重写提交

This commit is contained in:
2026-04-22 12:34:49 +08:00
parent cf8da3f50f
commit 997a8daada
438 changed files with 53355 additions and 865 deletions

View File

@@ -1,5 +1,3 @@
use std::collections::BTreeMap;
use axum::{
Json,
extract::{Extension, Query, State},
@@ -14,8 +12,13 @@ use platform_oss::{
LegacyAssetPrefix, OssHeadObjectRequest, OssObjectAccess, OssPostObjectRequest,
OssSignedGetObjectUrlRequest,
};
use serde::Deserialize;
use serde_json::{Value, json};
use shared_contracts::assets::{
AssetBindingPayload, AssetObjectPayload, AssetReadUrlPayload, BindAssetObjectRequest,
BindAssetObjectResponse, ConfirmAssetObjectAccessPolicy, ConfirmAssetObjectRequest,
ConfirmAssetObjectResponse, CreateDirectUploadTicketRequest, CreateDirectUploadTicketResponse,
DirectUploadTicketPayload, GetAssetReadUrlResponse, GetReadUrlQuery,
};
use spacetime_client::SpacetimeClientError;
use crate::{
@@ -23,84 +26,6 @@ use crate::{
state::AppState,
};
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateDirectUploadTicketRequest {
pub legacy_prefix: String,
#[serde(default)]
pub path_segments: Vec<String>,
pub file_name: String,
#[serde(default)]
pub content_type: Option<String>,
#[serde(default)]
pub access: Option<OssObjectAccess>,
#[serde(default)]
pub metadata: BTreeMap<String, String>,
#[serde(default)]
pub max_size_bytes: Option<u64>,
#[serde(default)]
pub expire_seconds: Option<u64>,
#[serde(default)]
pub success_action_status: Option<u16>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetReadUrlQuery {
#[serde(default)]
pub object_key: Option<String>,
#[serde(default)]
pub legacy_public_path: Option<String>,
#[serde(default)]
pub expire_seconds: Option<u64>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ConfirmAssetObjectRequest {
#[serde(default)]
pub bucket: Option<String>,
pub object_key: String,
#[serde(default)]
pub content_type: Option<String>,
#[serde(default)]
pub content_length: Option<u64>,
#[serde(default)]
pub content_hash: Option<String>,
pub asset_kind: String,
#[serde(default)]
pub access_policy: Option<ConfirmAssetObjectAccessPolicy>,
#[serde(default)]
pub source_job_id: Option<String>,
#[serde(default)]
pub owner_user_id: Option<String>,
#[serde(default)]
pub profile_id: Option<String>,
#[serde(default)]
pub entity_id: Option<String>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BindAssetObjectRequest {
pub asset_object_id: String,
pub entity_kind: String,
pub entity_id: String,
pub slot: String,
pub asset_kind: String,
#[serde(default)]
pub owner_user_id: Option<String>,
#[serde(default)]
pub profile_id: Option<String>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ConfirmAssetObjectAccessPolicy {
Private,
PublicRead,
}
pub async fn create_direct_upload_ticket(
State(state): State<AppState>,
Extension(request_context): Extension<RequestContext>,
@@ -141,9 +66,9 @@ pub async fn create_direct_upload_ticket(
Ok(json_success_body(
Some(&request_context),
json!({
"upload": signed,
}),
CreateDirectUploadTicketResponse {
upload: DirectUploadTicketPayload::from(signed),
},
))
}
@@ -180,9 +105,9 @@ pub async fn get_asset_read_url(
Ok(json_success_body(
Some(&request_context),
json!({
"read": signed,
}),
GetAssetReadUrlResponse {
read: AssetReadUrlPayload::from(signed),
},
))
}
@@ -223,25 +148,25 @@ pub async fn confirm_asset_object(
Ok(json_success_body(
Some(&request_context),
json!({
"assetObject": {
"assetObjectId": result.asset_object_id,
"bucket": result.bucket,
"objectKey": result.object_key,
"accessPolicy": result.access_policy.as_str(),
"contentType": result.content_type,
"contentLength": result.content_length,
"contentHash": result.content_hash,
"version": result.version,
"sourceJobId": result.source_job_id,
"ownerUserId": result.owner_user_id,
"profileId": result.profile_id,
"entityId": result.entity_id,
"assetKind": result.asset_kind,
"createdAt": result.created_at,
"updatedAt": result.updated_at,
}
}),
ConfirmAssetObjectResponse {
asset_object: AssetObjectPayload {
asset_object_id: result.asset_object_id,
bucket: result.bucket,
object_key: result.object_key,
access_policy: result.access_policy.as_str().to_string(),
content_type: result.content_type,
content_length: result.content_length,
content_hash: result.content_hash,
version: result.version,
source_job_id: result.source_job_id,
owner_user_id: result.owner_user_id,
profile_id: result.profile_id,
entity_id: result.entity_id,
asset_kind: result.asset_kind,
created_at: result.created_at,
updated_at: result.updated_at,
},
},
))
}
@@ -272,20 +197,20 @@ pub async fn bind_asset_object_to_entity(
Ok(json_success_body(
Some(&request_context),
json!({
"assetBinding": {
"bindingId": result.binding_id,
"assetObjectId": result.asset_object_id,
"entityKind": result.entity_kind,
"entityId": result.entity_id,
"slot": result.slot,
"assetKind": result.asset_kind,
"ownerUserId": result.owner_user_id,
"profileId": result.profile_id,
"createdAt": result.created_at,
"updatedAt": result.updated_at,
}
}),
BindAssetObjectResponse {
asset_binding: AssetBindingPayload {
binding_id: result.binding_id,
asset_object_id: result.asset_object_id,
entity_kind: result.entity_kind,
entity_id: result.entity_id,
slot: result.slot,
asset_kind: result.asset_kind,
owner_user_id: result.owner_user_id,
profile_id: result.profile_id,
created_at: result.created_at,
updated_at: result.updated_at,
},
},
))
}
@@ -355,7 +280,7 @@ async fn build_confirm_asset_object_upsert_input(
head.object_key,
payload
.access_policy
.map(Into::into)
.map(map_confirm_asset_object_access_policy)
.unwrap_or(AssetObjectAccessPolicy::Private),
head.content_type
.or_else(|| normalize_optional_value(payload.content_type)),
@@ -439,12 +364,12 @@ impl std::fmt::Display for ConfirmAssetObjectPrepareError {
}
}
impl From<ConfirmAssetObjectAccessPolicy> for AssetObjectAccessPolicy {
fn from(value: ConfirmAssetObjectAccessPolicy) -> Self {
match value {
ConfirmAssetObjectAccessPolicy::Private => Self::Private,
ConfirmAssetObjectAccessPolicy::PublicRead => Self::PublicRead,
}
fn map_confirm_asset_object_access_policy(
value: ConfirmAssetObjectAccessPolicy,
) -> AssetObjectAccessPolicy {
match value {
ConfirmAssetObjectAccessPolicy::Private => AssetObjectAccessPolicy::Private,
ConfirmAssetObjectAccessPolicy::PublicRead => AssetObjectAccessPolicy::PublicRead,
}
}
@@ -469,8 +394,8 @@ mod tests {
use reqwest::{Method, multipart};
use serde_json::{Value, json};
use sha1::Sha1;
use shared_kernel::new_uuid_simple_string;
use tower::ServiceExt;
use uuid::Uuid;
use crate::{app::build_router, config::AppConfig, state::AppState};
@@ -885,7 +810,7 @@ mod tests {
ensure_success_status(bucket_head.status().as_u16(), "bucket HEAD 应成功")?;
let app = build_router(AppState::new(config.clone()).expect("state should build"));
let run_id = Uuid::new_v4().simple().to_string();
let run_id = new_uuid_simple_string();
let file_name = format!("oss-live-{run_id}.txt");
let file_content = format!("Genarrative OSS Rust live test {run_id}");
@@ -1032,7 +957,7 @@ mod tests {
let test_result = async {
let app = build_router(AppState::new(config.clone()).expect("state should build"));
let run_id = Uuid::new_v4().simple().to_string();
let run_id = new_uuid_simple_string();
let file_content = format!("Genarrative confirm asset object live test {run_id}");
let ticket_response = app