use axum::{ Json, extract::{Extension, Path, State, rejection::JsonRejection}, http::{HeaderName, StatusCode, header}, response::Response, }; use module_assets::{ AssetObjectAccessPolicy, build_asset_entity_binding_input, build_asset_object_upsert_input, generate_asset_binding_id, generate_asset_object_id, }; use platform_oss::{LegacyAssetPrefix, OssHeadObjectRequest, OssObjectAccess}; use serde_json::{Value, json}; use shared_contracts::jump_hop::{ JumpHopActionRequest, JumpHopActionType, JumpHopCharacterAsset, JumpHopDraftResponse, JumpHopGalleryDetailResponse, JumpHopGenerationStatus, JumpHopJumpRequest, JumpHopJumpResponse, JumpHopRestartRunRequest, JumpHopRunResponse, JumpHopSessionResponse, JumpHopSessionSnapshotResponse, JumpHopStartRunRequest, JumpHopTileAsset, JumpHopTileType, JumpHopWorkDetailResponse, JumpHopWorkMutationResponse, JumpHopWorksResponse, JumpHopWorkspaceCreateRequest, }; use shared_kernel::{build_prefixed_uuid_id, format_timestamp_micros}; use spacetime_client::SpacetimeClientError; use std::{collections::BTreeMap, time::{SystemTime, UNIX_EPOCH}}; use crate::{ api_response::json_success_body, auth::{AuthenticatedAccessToken, RuntimePrincipal}, http_error::AppError, generated_asset_sheets::{ GeneratedAssetSheetPromptInput, build_generated_asset_sheet_prompt, slice_generated_asset_sheet, }, generated_image_assets::{ GeneratedImageAssetAdapter, GeneratedImageAssetDataUrl, adapter::{GeneratedImageAssetAdapterMetadata, GeneratedImageAssetPersistInput}, normalize_generated_image_asset_mime, }, openai_image_generation::{ build_openai_image_http_client, create_openai_image_generation, require_openai_image_settings, }, request_context::RequestContext, state::AppState, work_play_tracking::{record_work_play_start_after_success, WorkPlayTrackingDraft}, }; const JUMP_HOP_TILE_ITEM_NAMES: [&str; 6] = ["start", "normal", "target", "finish", "bonus", "accent"]; const JUMP_HOP_PROVIDER: &str = "jump-hop"; const JUMP_HOP_CREATION_PROVIDER: &str = "jump-hop-creation"; const JUMP_HOP_RUNTIME_PROVIDER: &str = "jump-hop-runtime"; const JUMP_HOP_TEMPLATE_ID: &str = "jump-hop"; const JUMP_HOP_TEMPLATE_NAME: &str = "跳一跳"; const JUMP_HOP_RUNTIME_RUNS_ROUTE: &str = "/api/runtime/jump-hop/runs"; pub async fn create_jump_hop_session( State(state): State, Extension(request_context): Extension, Extension(authenticated): Extension, payload: Result, JsonRejection>, ) -> Result, Response> { let Json(payload) = jump_hop_json(payload, &request_context, JUMP_HOP_CREATION_PROVIDER)?; validate_workspace_request(&request_context, &payload)?; let owner_user_id = authenticated.claims().user_id().to_string(); let session_id = build_prefixed_uuid_id("jump-hop-session-"); let now = current_utc_micros(); let draft = build_jump_hop_draft(&payload); let session = JumpHopSessionSnapshotResponse { session_id, owner_user_id, status: JumpHopGenerationStatus::Draft, draft: Some(draft), created_at: format_timestamp_micros(now), updated_at: format_timestamp_micros(now), }; Ok(json_success_body( Some(&request_context), JumpHopSessionResponse { session: state .spacetime_client() .create_jump_hop_session(session) .await .map_err(|error| { jump_hop_error_response( &request_context, JUMP_HOP_CREATION_PROVIDER, map_jump_hop_client_error(error), ) })?, }, )) } pub async fn get_jump_hop_session( State(state): State, Path(session_id): Path, Extension(request_context): Extension, Extension(authenticated): Extension, ) -> Result, Response> { ensure_non_empty(&request_context, &session_id, "sessionId")?; let owner_user_id = authenticated.claims().user_id().to_string(); let session = state .spacetime_client() .get_jump_hop_session(session_id, owner_user_id) .await .map_err(|error| { jump_hop_error_response( &request_context, JUMP_HOP_CREATION_PROVIDER, map_jump_hop_client_error(error), ) })?; Ok(json_success_body( Some(&request_context), JumpHopSessionResponse { session }, )) } pub async fn execute_jump_hop_action( State(state): State, Path(session_id): Path, Extension(request_context): Extension, Extension(authenticated): Extension, payload: Result, JsonRejection>, ) -> Result, Response> { ensure_non_empty(&request_context, &session_id, "sessionId")?; let Json(payload) = jump_hop_json(payload, &request_context, JUMP_HOP_CREATION_PROVIDER)?; let owner_user_id = authenticated.claims().user_id().to_string(); let mut payload = payload; maybe_generate_jump_hop_assets( &state, &request_context, session_id.as_str(), owner_user_id.as_str(), &mut payload, ) .await?; let response = state .spacetime_client() .execute_jump_hop_action(session_id, owner_user_id, payload) .await .map_err(|error| { jump_hop_error_response( &request_context, JUMP_HOP_CREATION_PROVIDER, map_jump_hop_client_error(error), ) })?; Ok(json_success_body(Some(&request_context), response)) } pub async fn publish_jump_hop_work( State(state): State, Path(profile_id): Path, Extension(request_context): Extension, Extension(authenticated): Extension, ) -> Result, Response> { ensure_non_empty(&request_context, &profile_id, "profileId")?; let work = state .spacetime_client() .publish_jump_hop_work(profile_id, authenticated.claims().user_id().to_string()) .await .map_err(|error| { jump_hop_error_response( &request_context, JUMP_HOP_CREATION_PROVIDER, map_jump_hop_client_error(error), ) })?; Ok(json_success_body( Some(&request_context), JumpHopWorkMutationResponse { item: work }, )) } pub async fn list_jump_hop_works( State(state): State, Extension(request_context): Extension, Extension(authenticated): Extension, ) -> Result, Response> { let works = state .spacetime_client() .list_jump_hop_works(authenticated.claims().user_id().to_string()) .await .map_err(|error| { jump_hop_error_response( &request_context, JUMP_HOP_CREATION_PROVIDER, map_jump_hop_client_error(error), ) })?; Ok(json_success_body( Some(&request_context), JumpHopWorksResponse { items: works.into_iter().map(|work| work.summary).collect(), }, )) } pub async fn get_jump_hop_runtime_work( State(state): State, Path(profile_id): Path, Extension(request_context): Extension, ) -> Result, Response> { ensure_non_empty(&request_context, &profile_id, "profileId")?; let work = state .spacetime_client() .get_jump_hop_runtime_work(profile_id) .await .map_err(|error| { jump_hop_error_response( &request_context, JUMP_HOP_RUNTIME_PROVIDER, map_jump_hop_client_error(error), ) })?; Ok(json_success_body( Some(&request_context), JumpHopWorkDetailResponse { item: work }, )) } pub async fn start_jump_hop_run( State(state): State, Extension(request_context): Extension, Extension(principal): Extension, payload: Result, JsonRejection>, ) -> Result, Response> { let Json(payload) = jump_hop_json(payload, &request_context, JUMP_HOP_RUNTIME_PROVIDER)?; ensure_non_empty(&request_context, &payload.profile_id, "profileId")?; let owner_user_id = principal.subject().to_string(); let principal_kind = principal.kind().as_str(); let run = state .spacetime_client() .start_jump_hop_run(payload, owner_user_id.clone()) .await .map_err(|error| { jump_hop_error_response( &request_context, JUMP_HOP_RUNTIME_PROVIDER, map_jump_hop_client_error(error), ) })?; record_work_play_start_after_success( &state, &request_context, build_jump_hop_work_play_tracking_draft( &principal, run.profile_id.clone(), JUMP_HOP_RUNTIME_RUNS_ROUTE, ) .owner_user_id(run.owner_user_id.clone()) .run_id(run.run_id.clone()) .profile_id(run.profile_id.clone()) .extra(json!({ "runStatus": run.status, "principalKind": principal_kind, })), ) .await; Ok(json_success_body( Some(&request_context), JumpHopRunResponse { run }, )) } pub async fn jump_hop_run_jump( State(state): State, Path(run_id): Path, Extension(request_context): Extension, Extension(principal): Extension, payload: Result, JsonRejection>, ) -> Result, Response> { ensure_non_empty(&request_context, &run_id, "runId")?; let Json(payload) = jump_hop_json(payload, &request_context, JUMP_HOP_RUNTIME_PROVIDER)?; let owner_user_id = principal.subject().to_string(); let run = state .spacetime_client() .jump_hop_run_jump(run_id, owner_user_id, payload) .await .map_err(|error| { jump_hop_error_response( &request_context, JUMP_HOP_RUNTIME_PROVIDER, map_jump_hop_client_error(error), ) })?; Ok(json_success_body( Some(&request_context), JumpHopJumpResponse { run }, )) } pub async fn restart_jump_hop_run( State(state): State, Path(run_id): Path, Extension(request_context): Extension, Extension(principal): Extension, payload: Result, JsonRejection>, ) -> Result, Response> { ensure_non_empty(&request_context, &run_id, "runId")?; let Json(payload) = jump_hop_json(payload, &request_context, JUMP_HOP_RUNTIME_PROVIDER)?; let owner_user_id = principal.subject().to_string(); let run = state .spacetime_client() .restart_jump_hop_run(run_id, owner_user_id, payload) .await .map_err(|error| { jump_hop_error_response( &request_context, JUMP_HOP_RUNTIME_PROVIDER, map_jump_hop_client_error(error), ) })?; Ok(json_success_body( Some(&request_context), JumpHopRunResponse { run }, )) } pub async fn list_jump_hop_gallery( State(state): State, Extension(request_context): Extension, ) -> Result, Response> { let gallery = state .spacetime_client() .list_jump_hop_gallery() .await .map_err(|error| { jump_hop_error_response( &request_context, JUMP_HOP_RUNTIME_PROVIDER, map_jump_hop_client_error(error), ) })?; Ok(json_success_body(Some(&request_context), gallery)) } pub async fn get_jump_hop_gallery_detail( State(state): State, Path(public_work_code): Path, Extension(request_context): Extension, ) -> Result, Response> { ensure_non_empty(&request_context, &public_work_code, "publicWorkCode")?; let work = state .spacetime_client() .get_jump_hop_gallery_detail(public_work_code) .await .map_err(|error| { jump_hop_error_response( &request_context, JUMP_HOP_RUNTIME_PROVIDER, map_jump_hop_client_error(error), ) })?; Ok(json_success_body( Some(&request_context), JumpHopGalleryDetailResponse { item: work }, )) } async fn maybe_generate_jump_hop_assets( state: &AppState, request_context: &RequestContext, session_id: &str, owner_user_id: &str, payload: &mut JumpHopActionRequest, ) -> Result<(), Response> { if !matches!(payload.action_type, JumpHopActionType::CompileDraft) { return Ok(()); } if payload.character_asset.is_some() && payload.tile_atlas_asset.is_some() && payload.tile_assets.as_ref().is_some_and(|assets| !assets.is_empty()) { return Ok(()); } let profile_id = payload .profile_id .as_ref() .map(|value| value.trim()) .filter(|value| !value.is_empty()) .map(ToString::to_string) .unwrap_or_else(|| build_prefixed_uuid_id("jump-hop-profile-")); payload.profile_id = Some(profile_id.clone()); let settings = require_openai_image_settings(state) .map_err(|error| jump_hop_error_response(request_context, JUMP_HOP_CREATION_PROVIDER, error))?; let http_client = build_openai_image_http_client(&settings) .map_err(|error| jump_hop_error_response(request_context, JUMP_HOP_CREATION_PROVIDER, error))?; let character_prompt = payload .character_prompt .as_deref() .unwrap_or("俯视角可爱主角,透明背景"); let tile_prompt = payload .tile_prompt .as_deref() .unwrap_or("等距立体地块图集"); let character_generated = create_openai_image_generation( &http_client, &settings, character_prompt, Some("文字、Logo、水印、按钮、UI 字、低清晰度、畸形肢体、多余角色、裁切主体"), "1024*1024", 1, &[], "跳一跳角色资产生成失败", ) .await .map_err(|error| jump_hop_error_response(request_context, JUMP_HOP_CREATION_PROVIDER, error))?; let character_image = character_generated.images.into_iter().next().ok_or_else(|| { jump_hop_error_response( request_context, JUMP_HOP_CREATION_PROVIDER, AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({ "provider": "vector-engine", "message": "跳一跳角色资产生成成功但未返回图片。", })), ) })?; let character_asset = persist_jump_hop_generated_image_asset( state, owner_user_id, profile_id.as_str(), "character", character_prompt, character_image, LegacyAssetPrefix::JumpHopAssets, 768, 768, request_context, ) .await?; let sheet_prompt = build_generated_asset_sheet_prompt(&GeneratedAssetSheetPromptInput { subject_text: tile_prompt, item_names: &vec!["start".to_string(), "normal".to_string(), "target".to_string(), "finish".to_string(), "bonus".to_string(), "accent".to_string()], grid_size: 3, item_name_prompt_template: Some("第{row_index}行:{item_name} 的 {view_count} 个不同视图"), special_prompt: Some("每个格子对应一个 tile 类型,供跳一跳地块裁切使用。"), }) .map_err(|error| jump_hop_error_response(request_context, JUMP_HOP_CREATION_PROVIDER, error))?; let tile_generated = create_openai_image_generation( &http_client, &settings, sheet_prompt.as_str(), Some("文字、Logo、水印、按钮、UI 字、低清晰度、畸形肢体、多余角色、裁切主体"), "1024*1024", 1, &[], "跳一跳地块图集生成失败", ) .await .map_err(|error| jump_hop_error_response(request_context, JUMP_HOP_CREATION_PROVIDER, error))?; let tile_image = tile_generated.images.into_iter().next().ok_or_else(|| { jump_hop_error_response( request_context, JUMP_HOP_CREATION_PROVIDER, AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({ "provider": "vector-engine", "message": "跳一跳地块图集生成成功但未返回图片。", })), ) })?; let tile_slices = slice_generated_asset_sheet( &tile_image, &vec!["start".to_string(), "normal".to_string(), "target".to_string(), "finish".to_string(), "bonus".to_string(), "accent".to_string()], 3, ) .map_err(|error| jump_hop_error_response(request_context, JUMP_HOP_CREATION_PROVIDER, error))?; let tile_atlas_asset = persist_jump_hop_generated_image_asset( state, owner_user_id, profile_id.as_str(), "tile-atlas", tile_prompt, tile_image, LegacyAssetPrefix::JumpHopAssets, 1024, 1024, request_context, ) .await?; let tile_assets = tile_slices .into_iter() .enumerate() .map(|(index, row)| JumpHopTileAsset { tile_type: match index { 0 => JumpHopTileType::Start, 1 => JumpHopTileType::Normal, 2 => JumpHopTileType::Target, 3 => JumpHopTileType::Finish, 4 => JumpHopTileType::Bonus, _ => JumpHopTileType::Accent, }, image_src: format!("/generated-jump-hop-assets/{profile_id}/tiles/{index}.png"), image_object_key: format!("generated-jump-hop-assets/{profile_id}/tiles/{index}.png"), asset_object_id: format!("{profile_id}-tile-{index}-object"), source_atlas_cell: format!("cell-{index}"), visual_width: 256, visual_height: 192, top_surface_radius: 42.0, landing_radius: 34.0, }) .collect::>(); payload.character_asset = Some(character_asset); payload.tile_atlas_asset = Some(tile_atlas_asset); payload.tile_assets = Some(tile_assets); payload.cover_composite = payload .cover_composite .clone() .or_else(|| Some(format!("/generated-jump-hop-assets/{profile_id}/cover-composite.png"))); Ok(()) } async fn persist_jump_hop_generated_image_asset( state: &AppState, owner_user_id: &str, profile_id: &str, slot: &str, prompt: &str, image: crate::openai_image_generation::DownloadedOpenAiImage, prefix: LegacyAssetPrefix, width: u32, height: u32, request_context: &RequestContext, ) -> Result { let image_format = normalize_generated_image_asset_mime(image.mime_type.as_str()); let prepared = GeneratedImageAssetAdapter::prepare_put_object(GeneratedImageAssetPersistInput { prefix, path_segments: vec![profile_id.to_string(), slot.to_string()], file_stem: "image".to_string(), image: GeneratedImageAssetDataUrl { format: image_format, bytes: image.bytes, }, access: OssObjectAccess::Private, metadata: GeneratedImageAssetAdapterMetadata { asset_kind: Some(format!("jump-hop-{slot}")), owner_user_id: Some(owner_user_id.to_string()), entity_kind: Some("jump_hop_work".to_string()), entity_id: Some(profile_id.to_string()), slot: Some(slot.to_string()), provider: Some("vector-engine".to_string()), task_id: None, }, extra_metadata: BTreeMap::new(), }) .map_err(|error| { jump_hop_error_response( request_context, JUMP_HOP_CREATION_PROVIDER, AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR).with_details(json!({ "provider": "generated-image-assets", "message": format!("准备跳一跳图片资产上传请求失败:{error:?}"), })), ) })?; let persisted_mime_type = prepared.format.mime_type.clone(); let oss_client = state.oss_client().ok_or_else(|| { jump_hop_error_response( request_context, JUMP_HOP_CREATION_PROVIDER, AppError::from_status(StatusCode::SERVICE_UNAVAILABLE).with_details(json!({ "provider": "aliyun-oss", "reason": "OSS 未完成环境变量配置", })), ) })?; let http_client = reqwest::Client::new(); let put_result = oss_client .put_object(&http_client, prepared.request) .await .map_err(|error| { jump_hop_error_response( request_context, JUMP_HOP_CREATION_PROVIDER, AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({ "provider": "aliyun-oss", "message": error.to_string(), })), ) })?; let head = oss_client .head_object( &http_client, OssHeadObjectRequest { object_key: put_result.object_key.clone(), }, ) .await .map_err(|error| { jump_hop_error_response( request_context, JUMP_HOP_CREATION_PROVIDER, AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({ "provider": "aliyun-oss", "message": error.to_string(), })), ) })?; let now_micros = current_utc_micros(); let asset_object_input = build_asset_object_upsert_input( generate_asset_object_id(now_micros), head.bucket, head.object_key.clone(), AssetObjectAccessPolicy::Private, head.content_type.or(Some(persisted_mime_type)), head.content_length, head.etag, format!("jump-hop-{slot}"), None, Some(owner_user_id.to_string()), Some(profile_id.to_string()), Some(profile_id.to_string()), now_micros, ) .map_err(|error| { jump_hop_error_response( request_context, JUMP_HOP_CREATION_PROVIDER, AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({ "provider": "asset-object", "message": error.to_string(), })), ) })?; let asset_object = state .spacetime_client() .confirm_asset_object(asset_object_input) .await .map_err(|error| { jump_hop_error_response( request_context, JUMP_HOP_CREATION_PROVIDER, AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({ "provider": "spacetimedb", "message": error.to_string(), })), ) })?; let binding_input = build_asset_entity_binding_input( generate_asset_binding_id(now_micros), asset_object.asset_object_id.clone(), "jump_hop_work".to_string(), profile_id.to_string(), slot.to_string(), format!("jump-hop-{slot}"), Some(owner_user_id.to_string()), Some(profile_id.to_string()), now_micros, ) .map_err(|error| { jump_hop_error_response( request_context, JUMP_HOP_CREATION_PROVIDER, AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({ "provider": "asset-entity-binding", "message": error.to_string(), })), ) })?; state .spacetime_client() .bind_asset_object_to_entity(binding_input) .await .map_err(|error| { jump_hop_error_response( request_context, JUMP_HOP_CREATION_PROVIDER, AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({ "provider": "spacetimedb", "message": error.to_string(), })), ) })?; Ok(JumpHopCharacterAsset { asset_id: format!("{profile_id}-{slot}-{now_micros}"), image_src: put_result.legacy_public_path, image_object_key: head.object_key, asset_object_id: asset_object.asset_object_id, generation_provider: "vector-engine".to_string(), prompt: prompt.to_string(), width, height, }) } fn build_jump_hop_work_play_tracking_draft( principal: &RuntimePrincipal, work_id: impl Into, source_route: &'static str, ) -> WorkPlayTrackingDraft { WorkPlayTrackingDraft::runtime_principal("jump-hop", work_id, principal, source_route) } fn build_jump_hop_draft(payload: &JumpHopWorkspaceCreateRequest) -> JumpHopDraftResponse { JumpHopDraftResponse { template_id: JUMP_HOP_TEMPLATE_ID.to_string(), template_name: JUMP_HOP_TEMPLATE_NAME.to_string(), profile_id: None, work_title: payload.work_title.trim().to_string(), work_description: payload.work_description.trim().to_string(), theme_tags: normalize_tags(payload.theme_tags.clone()), difficulty: payload.difficulty.clone(), style_preset: payload.style_preset.clone(), character_prompt: payload.character_prompt.trim().to_string(), tile_prompt: payload.tile_prompt.trim().to_string(), end_mood_prompt: payload .end_mood_prompt .as_ref() .map(|value| value.trim().to_string()) .filter(|value| !value.is_empty()), character_asset: None, tile_atlas_asset: None, tile_assets: Vec::new(), path: None, cover_composite: None, generation_status: JumpHopGenerationStatus::Draft, } } fn validate_workspace_request( request_context: &RequestContext, payload: &JumpHopWorkspaceCreateRequest, ) -> Result<(), Response> { ensure_non_empty(request_context, &payload.work_title, "workTitle")?; ensure_non_empty( request_context, &payload.character_prompt, "characterPrompt", )?; ensure_non_empty(request_context, &payload.tile_prompt, "tilePrompt")?; if payload.template_id.trim() != JUMP_HOP_TEMPLATE_ID { return Err(jump_hop_error_response( request_context, JUMP_HOP_CREATION_PROVIDER, AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({ "provider": JUMP_HOP_PROVIDER, "message": "templateId 必须为 jump-hop", })), )); } Ok(()) } fn ensure_non_empty( request_context: &RequestContext, value: &str, field: &str, ) -> Result<(), Response> { if value.trim().is_empty() { return Err(jump_hop_error_response( request_context, JUMP_HOP_PROVIDER, AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({ "provider": JUMP_HOP_PROVIDER, "field": field, "message": format!("{field} 不能为空"), })), )); } Ok(()) } fn normalize_tags(tags: Vec) -> Vec { let mut normalized = Vec::new(); for tag in tags { let tag = tag.trim(); if tag.is_empty() || normalized.iter().any(|item| item == tag) { continue; } normalized.push(tag.to_string()); if normalized.len() >= 6 { break; } } normalized } fn jump_hop_json( payload: Result, JsonRejection>, request_context: &RequestContext, provider: &str, ) -> Result, Response> { payload.map_err(|error| { jump_hop_error_response( request_context, provider, AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({ "provider": provider, "message": error.to_string(), })), ) }) } fn map_jump_hop_client_error(error: SpacetimeClientError) -> AppError { let status = match &error { SpacetimeClientError::Runtime(_) => StatusCode::BAD_REQUEST, SpacetimeClientError::Procedure(message) if message.contains("不存在") || message.contains("not found") || message.contains("does not exist") => { StatusCode::NOT_FOUND } SpacetimeClientError::Procedure(message) if message.contains("发布需要") || message.contains("不能为空") || message.contains("必须") => { StatusCode::BAD_REQUEST } _ => StatusCode::BAD_GATEWAY, }; AppError::from_status(status).with_details(json!({ "provider": "spacetimedb", "message": error.to_string(), })) } fn jump_hop_error_response( request_context: &RequestContext, provider: &str, error: AppError, ) -> Response { let mut response = error.into_response_with_context(Some(request_context)); response.headers_mut().insert( HeaderName::from_static("x-genarrative-provider"), header::HeaderValue::from_str(provider) .unwrap_or_else(|_| header::HeaderValue::from_static("jump-hop")), ); response } fn current_utc_micros() -> i64 { SystemTime::now() .duration_since(UNIX_EPOCH) .map(|duration| duration.as_micros().min(i64::MAX as u128) as i64) .unwrap_or(0) }