This commit is contained in:
Brandon Thomas committed 2025-12-16 22:11:59 -05:00
1 parent 11607b4fec
commit 3dfb320ef6
5 files changed
+102 -58

No files matched your search

@@ -1,4 +1,5 @@
pub mod run_object;
pub mod run_object_id;
pub mod upload_object_id;
pub mod upload_mime_type;
pub mod upload_object_id;
pub mod world_object_id;
@@ -0,0 +1,80 @@
use std::collections::HashMap;
use chrono::Utc;
use serde::{Deserialize, Serialize};
use serde_json::Value;
const RUN_MIME_TYPE: &str = "application/run+json";
const RUN_VERSION : &str = "0.0.1";
/// World Labs' API is very frontend driven
/// They send whole objects back to the frontend that the frontend is in charge of mutatingbjects or PATCH them back to the server (yuck):
/// - request #1 - create run
/// - request #6 - patch run after image upload
/// Gotta go fast?
#[derive(Serialize, Deserialize, Clone)]
pub struct RunObject {
/// The primary ID of the run.
/// This won't exist until we post it to the server.
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
pub metadata: RunObjectMetadata,
pub mime_type: String,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct RunObjectMetadata {
pub version: String,
#[serde(rename = "createdAt")]
pub created_at: u64,
#[serde(rename = "updatedAt")]
pub updated_at: u64,
#[serde(rename = "usesAdvancedEditing")]
pub uses_advanced_editing: bool,
#[serde(rename = "draftMode")]
pub draft_mode: bool,
/// Polymorphic set of ID-to-object mappings.
pub nodes: HashMap<String, Value>,
}
impl Default for RunObject {
fn default() -> Self {
let now = Utc::now();
let now = now.timestamp().unsigned_abs();
Self {
id: None,
metadata: RunObjectMetadata{
version: RUN_VERSION.to_string(),
created_at: now,
updated_at: now,
uses_advanced_editing: false,
draft_mode: false,
nodes: HashMap::new(),
},
mime_type: RUN_MIME_TYPE.to_string(),
}
}
}
#[cfg(test)]
mod tests {
use crate::api::api_types::run_object::RunObject;
#[test]
fn default_runobject() {
let object = RunObject::default();
assert!(object.id.is_none());
assert_eq!(&object.metadata.version, "0.0.1");
assert!(object.metadata.created_at > 1765433415549);
assert!(object.metadata.updated_at > 1765433415549);
assert_eq!(&object.mime_type, "application/run+json");
}
}
@@ -1,3 +1,4 @@
use crate::api::api_types::run_object::RunObject;
use crate::api::api_types::run_object_id::RunObjectId;
use crate::api::common::common_header_values::{ORIGIN_VALUE, REFERER_VALUE};
use crate::credentials::world_labs_bearer_token::WorldLabsBearerToken;
@@ -5,6 +6,7 @@ use crate::credentials::world_labs_cookies::WorldLabsCookies;
use crate::error::world_labs_client_error::WorldLabsClientError;
use crate::error::world_labs_error::WorldLabsError;
use crate::error::world_labs_generic_api_error::WorldLabsGenericApiError;
use crate::error::world_labs_specific_api_error::WorldLabsSpecificApiError;
use chrono::Utc;
use http_headers::names::{PRIORITY, SEC_FETCH_DEST, SEC_FETCH_MODE, SEC_FETCH_SITE, SEC_GPC};
use http_headers::values::accept::ACCEPT_ALL;
@@ -32,6 +34,7 @@ pub struct CreateRunObjectArgs<'a> {
pub struct CreateRunObjectResponse {
pub id: RunObjectId,
pub run_object: RunObject,
}
/// Marble Image-to-World
@@ -67,9 +70,9 @@ pub async fn create_run_object(args: CreateRunObjectArgs<'_>) -> Result<CreateRu
request_builder = request_builder.timeout(timeout);
}
let request_payload = RawRequest::default();
let new_run_object = RunObject::default();
let http_request = request_builder.json(&request_payload)
let http_request = request_builder.json(&new_run_object)
.build()
.map_err(|err| {
error!("Error building request: {:?}", err);
@@ -101,63 +104,18 @@ pub async fn create_run_object(args: CreateRunObjectArgs<'_>) -> Result<CreateRu
debug!("Response body (200): {}", response_body);
let response : RawResponse = serde_json::from_str(&response_body)
let response : RunObject = serde_json::from_str(&response_body)
.map_err(|err| WorldLabsGenericApiError::SerdeResponseParseErrorWithBody(err, response_body.to_string()))?;
let run_id = match &response.id {
Some(id) => RunObjectId(id.to_string()),
None => {
return Err(WorldLabsSpecificApiError::NoRunIdInResponse { response_body }.into())
}
};
Ok(CreateRunObjectResponse {
id: RunObjectId(response.id),
id: run_id,
run_object: response,
})
}
#[derive(Serialize)]
struct RawRequest {
pub metadata: RawRequestMetadata,
pub mime_type: String,
}
#[derive(Serialize)]
struct RawRequestMetadata {
pub version: String,
#[serde(rename = "createdAt")]
pub created_at: u64,
#[serde(rename = "updatedAt")]
pub updated_at: u64,
#[serde(rename = "usesAdvancedEditing")]
pub uses_advanced_editing: bool,
#[serde(rename = "draftMode")]
pub draft_mode: bool,
pub nodes: RawRequestNodes,
}
#[derive(Serialize)]
struct RawRequestNodes {
}
impl Default for RawRequest {
fn default() -> Self {
let now = Utc::now();
let now = now.timestamp().unsigned_abs();
Self {
metadata: RawRequestMetadata {
version: "0.0.1".to_string(),
created_at: now,
updated_at: now,
uses_advanced_editing: false,
draft_mode: false,
nodes: RawRequestNodes {},
},
mime_type: "application/run+json".to_string(),
}
}
}
#[derive(Deserialize)]
struct RawResponse {
pub id: String,
//pub owner_id: String,
}
@@ -3,6 +3,9 @@ use std::fmt::{Display, Formatter};
#[derive(Debug)]
pub enum WorldLabsSpecificApiError {
/// If the API drops run ids (unlikely)
NoRunIdInResponse { response_body: String },
/// The Google GCP upload failed because the signature does not match
GoogleUploadSignatureDoesNotMatch,
@@ -62,6 +65,7 @@ impl Error for WorldLabsSpecificApiError {}
impl Display for WorldLabsSpecificApiError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::NoRunIdInResponse { response_body } => write!(f, "no run.id found in response: {}", response_body),
Self::GoogleUploadSignatureDoesNotMatch => write!(f, "Google upload signature does not match"),
Self::AutomationBlocked => write!(f, "Automation blocked"),
Self::TooManyVideos => write!(f, "Too many videos are being generated"),
@@ -41,6 +41,7 @@ pub async fn upload_image_and_create_world_with_retry(args: UploadImageAndCreate
}).await?;
let run_object_id = response.id;
let run_object = response.run_object;
info!("Object id: {}", run_object_id.0);