diff --git a/mantle/rbx_api/src/errors.rs b/mantle/rbx_api/src/errors.rs index 7ad5695..77ace00 100644 --- a/mantle/rbx_api/src/errors.rs +++ b/mantle/rbx_api/src/errors.rs @@ -13,8 +13,11 @@ pub enum RobloxApiError { #[error("Authorization has been denied for this request. Check your ROBLOSECURITY cookie.")] Authorization, - #[error("Roblox error: {0}")] - Roblox(String), + #[error("Roblox error ({status_code}): {reason}")] + Roblox { + status_code: StatusCode, + reason: String, + }, #[error("Failed to parse JSON response: {0}")] ParseJson(#[from] serde_json::Error), @@ -39,6 +42,18 @@ pub enum RobloxApiError { #[error("No create quotas found for asset type {0}")] MissingCreateQuota(AssetTypeId), + + #[error("Place file size is too large. Consider switching to the rbxl format.")] + RbxlxPlaceFileSizeTooLarge, + + #[error("Place file size may be too large. Consider switching to the rbxl format.")] + RbxlxPlaceFileSizeMayBeTooLarge, + + #[error("Place file size is too large.")] + RbxlPlaceFileSizeTooLarge, + + #[error("Place file size may be too large.")] + RbxlPlaceFileSizeMayBeTooLarge, } // Temporary to make the new errors backwards compatible with the String errors throughout the project. @@ -89,9 +104,4 @@ impl RobloxApiErrorResponse { None } } - - pub fn reason_or_status_code(self, status_code: StatusCode) -> String { - self.reason() - .unwrap_or_else(|| format!("Unknown error ({})", status_code)) - } } diff --git a/mantle/rbx_api/src/helpers.rs b/mantle/rbx_api/src/helpers.rs index b22175d..2db2ffd 100644 --- a/mantle/rbx_api/src/helpers.rs +++ b/mantle/rbx_api/src/helpers.rs @@ -9,13 +9,13 @@ use tokio_util::codec::{BytesCodec, FramedRead}; use crate::{errors::RobloxApiErrorResponse, RobloxApiError, RobloxApiResult}; -pub async fn get_roblox_api_error_message_from_response(response: reqwest::Response) -> String { +pub async fn get_roblox_api_error_from_response(response: reqwest::Response) -> RobloxApiError { let status_code = response.status(); let reason = { if let Some(content_type) = response.headers().get(reqwest::header::CONTENT_TYPE) { if content_type == "application/json" { match response.json::().await { - Ok(error) => Some(error.reason_or_status_code(status_code)), + Ok(error) => error.reason(), Err(_) => None, } } else if content_type == "text/html" @@ -41,7 +41,11 @@ pub async fn get_roblox_api_error_message_from_response(response: reqwest::Respo None } }; - reason.unwrap_or_else(|| format!("Unknown error (status {})", status_code)) + + RobloxApiError::Roblox { + status_code, + reason: reason.unwrap_or_else(|| "Unknown error".to_owned()), + } } pub async fn handle( @@ -60,9 +64,7 @@ pub async fn handle( if response.status().is_success() { Ok(response) } else { - Err(RobloxApiError::Roblox( - get_roblox_api_error_message_from_response(response).await, - )) + Err(get_roblox_api_error_from_response(response).await) } } Err(error) => Err(error.into()), @@ -90,9 +92,10 @@ where let data = response.bytes().await?; if let Ok(error) = serde_json::from_slice::(&data) { if !error.success.unwrap_or(false) { - return Err(RobloxApiError::Roblox( - error.reason_or_status_code(status_code), - )); + return Err(RobloxApiError::Roblox { + status_code, + reason: error.reason().unwrap_or_else(|| "Unknown error".to_owned()), + }); } } Ok(serde_json::from_slice::(&data)?) diff --git a/mantle/rbx_api/src/places/mod.rs b/mantle/rbx_api/src/places/mod.rs index eed43a2..4c04d82 100644 --- a/mantle/rbx_api/src/places/mod.rs +++ b/mantle/rbx_api/src/places/mod.rs @@ -2,7 +2,7 @@ pub mod models; use std::{fs, path::PathBuf}; -use reqwest::{header, Body}; +use reqwest::{header, Body, StatusCode}; use crate::{ errors::{RobloxApiError, RobloxApiResult}, @@ -51,9 +51,33 @@ impl RobloxApi { .header("Content-Type", content_type) .body(body); - handle(req).await?; - - Ok(()) + let result = handle(req).await; + + match result { + Err(RobloxApiError::Roblox { + status_code, + reason, + }) => match (file_format, status_code) { + (PlaceFileFormat::Xml, StatusCode::PAYLOAD_TOO_LARGE) => { + Err(RobloxApiError::RbxlxPlaceFileSizeTooLarge) + } + (PlaceFileFormat::Xml, StatusCode::NOT_FOUND) => { + Err(RobloxApiError::RbxlxPlaceFileSizeMayBeTooLarge) + } + (PlaceFileFormat::Binary, StatusCode::PAYLOAD_TOO_LARGE) => { + Err(RobloxApiError::RbxlPlaceFileSizeTooLarge) + } + (PlaceFileFormat::Binary, StatusCode::NOT_FOUND) => { + Err(RobloxApiError::RbxlPlaceFileSizeMayBeTooLarge) + } + _ => Err(RobloxApiError::Roblox { + status_code, + reason, + }), + }, + Err(e) => Err(e), + Ok(_) => Ok(()), + } } pub async fn get_place(&self, place_id: AssetId) -> RobloxApiResult {