Skip to content

Commit

Permalink
Merge pull request #36 from Chloe-Woahie/dev-main
Browse files Browse the repository at this point in the history
v0.13.0
  • Loading branch information
fekie authored Apr 8, 2023
2 parents 3710618 + be7d343 commit 5807319
Show file tree
Hide file tree
Showing 11 changed files with 328 additions and 34 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ license = "MIT"
name = "roboat"
readme = "README.md"
repository = "https://github.com/Chloe-Woahie/roboat"
version = "0.12.0"
version = "0.13.0"

[dependencies]
reqwest = { version = "0.11.14", default-features=false, features = ["rustls-tls", "json"] }
Expand Down
34 changes: 21 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,37 @@ A high performance interface for the Roblox API.
This library is designed to be high-performance capable, meaning that it supports proxies
and is capable of making requests in parallel.

Note that this crate is currently economy-focused, meaning that endpoints related to items and trades are currently prioritized.

# Documentation
Extensive documentation is used throughout this crate.
All public methods in this crate are documented and have at least one corresponding example.

Documentation can be found [here](https://docs.rs/roboat/).

# Covered Endpoints
# Coverage
* Catalog API - [`catalog.roblox.com/*`]
- Item Details - `/v1/catalog/items/details`
- Fetch Item Details - [`Client::item_details`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.item_details)
- Fetch Product ID - [`Client::product_id`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.product_id)
- Fetch Product ID Bulk - [`Client::product_id_bulk`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.product_id_bulk)
- Fetch Collectible Item ID - [`Client::collectible_item_id`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.collectible_item_id)
- Fetch Collectible Item ID Bulk - [`Client::collectible_item_id_bulk`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.collectible_item_id_bulk)
* Economy API - [`economy.roblox.com/*`]
- Robux Balance - `/v1/users/{user_id}/currency`
- Resellers - `/v1/assets/{item_id}/resellers`
- User Sales - `/v2/users/{user_id}/transactions?transactionType=Sale`
- Put Limited On Sale - `/v1/assets/{item_id}/resellable-copies/{uaid}`
- Take Limited Off Sale - `/v1/assets/{item_id}/resellable-copies/{uaid}`
- Purchase Limited - `/v1/purchases/products/{product_id}`
- Fetch Robux Balance - [`Client::robux`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.robux)
- Fetch Resellers - [`Client::resellers`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.resellers)
- Fetch User Sales - [`Client::user_sales`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.user_sales)
- Put Limited On Sale - [`Client::put_limited_on_sale`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.put_limited_on_sale)
- Take Limited Off Sale - [`Client::take_limited_off_sale`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.take_limited_off_sale)
- Purchase Tradable Limited - [`Client::purchase_tradable_limited`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.purchase_tradable_limited)
* Users API - [`users.roblox.com/*`]
- User Information - `/v1/users/authenticated`
- User Search - `/v1/users/search`
- Fetch User ID - [`Client::user_id`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.user_id)
- Fetch Username - [`Client::username`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.username)
- Fetch Display Name - [`Client::display_name`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.display_name)
- User Search - [`Client::user_search`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.user_search)
* Presence API - [`presence.roblox.com/*`]
- Register Presence - `/v1/presence/register-app-presence`
- Register Presence - [`Client::register_presence`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.register_presence)
* Trades API - [`trades.roblox.com/*`]
- Trades List - `/v1/trades/{trade_type}`
- Fetch Trades List - [`Client::trades`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.trades)

# Setup
You can add the latest version of roboat to your project by running:
Expand All @@ -46,7 +54,7 @@ Alternatively, you can add a specific version of roboat to your project by addin

```toml
[dependencies]
roboat = "0.12"
roboat = "0.13.0"
```

# Quick Start Examples
Expand Down
12 changes: 12 additions & 0 deletions examples/get_product_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use roboat::ClientBuilder;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = ClientBuilder::new().build();

let product_id = client.product_id(1365767).await?;

println!("Ugc Limited Product ID: {}", product_id);

Ok(())
}
12 changes: 12 additions & 0 deletions examples/get_ugc_limited_collectible_item_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use roboat::ClientBuilder;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = ClientBuilder::new().build();

let collectible_item_id = client.collectible_item_id(13032232281).await?;

println!("Ugc Limited Product ID: {}", collectible_item_id);

Ok(())
}
2 changes: 1 addition & 1 deletion examples/purchase_limited.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.expect("Item cannot be a \"new\" limited. Run purchase_ugc_limited instead.");

let result = client
.purchase_limited(product_id, seller_id, uaid, price)
.purchase_tradable_limited(product_id, seller_id, uaid, price)
.await;

match result {
Expand Down
233 changes: 227 additions & 6 deletions src/catalog/avatar_catalog/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,9 @@ pub struct PremiumPricing {
pub premium_price_in_robux: u64,
}

/// The details of an item. Retrieved from <https://catalog.roblox.com/v1/catalog/items/details>.
/// A struct containing all the fields possibly returned from <https://catalog.roblox.com/v1/catalog/items/details>.
///
/// This struct can be parsed into details structs.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize)]
pub struct ItemDetails {
/// Either the asset id, or the bundle id, depending on the [`Self::item_type`].
Expand Down Expand Up @@ -282,8 +284,8 @@ pub struct ItemDetails {
pub creator_has_verified_badge: bool,
/// The type of creator that created the item (User or Group).
pub creator_type: CreatorType,
/// The id of the creator. The value is 1 if the creator is Roblox.
pub creator_user_id: u64,
/// The id (group or user) of the creator. The value is 1 if the creator is Roblox.
pub creator_id: u64,
/// The name of the creator. The value is "Roblox" if the creator is Roblox.
pub creator_name: String,
/// Coincides with price if the item is a non-limited,
Expand Down Expand Up @@ -410,7 +412,7 @@ impl TryFrom<request_types::ItemDetailsRaw> for ItemDetails {
.creator_has_verified_badge
.ok_or(RoboatError::MalformedResponse)?;

let creator_user_id = value
let creator_id = value
.creator_target_id
.ok_or(RoboatError::MalformedResponse)?;

Expand Down Expand Up @@ -449,7 +451,7 @@ impl TryFrom<request_types::ItemDetailsRaw> for ItemDetails {
item_restrictions,
creator_has_verified_badge,
creator_type,
creator_user_id,
creator_id,
creator_name,
price,
favorite_count,
Expand All @@ -476,6 +478,10 @@ impl Client {
/// If the `item_type` is [`ItemType::Asset`], then `id` is the item ID.
/// Otherwise, if the `item_type` is [`ItemType::Bundle`], then `id` is the bundle ID.
///
/// # Errors
/// * All errors under [Standard Errors](#standard-errors).
/// * All errors under [X-CSRF-TOKEN Required Errors](#x-csrf-token-required-errors).
///
/// # Examples
///
/// ```no_run
Expand Down Expand Up @@ -529,15 +535,230 @@ impl Client {
},
}
}

/// Fetches the product ID of an item (must be an asset). Uses [`Client::item_details`] internally
/// (which fetches from <https://catalog.roblox.com/v1/catalog/items/details>)
///
/// # Notes
/// * Does not require a valid roblosecurity.
/// * Will repeat once if the x-csrf-token is invalid.
///
/// # Errors
/// * All errors under [Standard Errors](#standard-errors).
/// * All errors under [X-CSRF-TOKEN Required Errors](#x-csrf-token-required-errors).
///
/// # Example
/// ```no_run
/// use roboat::ClientBuilder;
///
/// const ROBLOSECURITY: &str = "roblosecurity";
///
/// # #[tokio::main]
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let client = ClientBuilder::new().build();
///
/// let item_id = 12345679;
///
/// let product_id = client.product_id(item_id).await?;
/// # Ok(())
/// # }
/// ```
pub async fn product_id(&self, item_id: u64) -> Result<u64, RoboatError> {
let item = ItemArgs {
item_type: ItemType::Asset,
id: item_id,
};

let details = self.item_details(vec![item]).await?;

details
.get(0)
.ok_or(RoboatError::MalformedResponse)?
.product_id
.ok_or(RoboatError::MalformedResponse)
}

/// Fetches the product ID of multiple items (must be an asset). More efficient than calling [`Client::product_id`] repeatedly.
/// Uses [`Client::item_details`] internally
/// (which fetches from <https://catalog.roblox.com/v1/catalog/items/details>).
///
/// # Notes
/// * Does not require a valid roblosecurity.
/// * This endpoint will accept up to 120 items at a time.
/// * Will repeat once if the x-csrf-token is invalid.
///
/// # Errors
/// * All errors under [Standard Errors](#standard-errors).
/// * All errors under [X-CSRF-TOKEN Required Errors](#x-csrf-token-required-errors).
///
/// # Example
/// ```no_run
/// use roboat::ClientBuilder;
///
/// const ROBLOSECURITY: &str = "roblosecurity";
///
/// # #[tokio::main]
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let client = ClientBuilder::new().build();
///
/// let item_id_1 = 12345679;
/// let item_id_2 = 987654321;
///
/// let product_ids = client.product_id_bulk(vec![item_id_1, item_id_2]).await?;
///
/// let product_id_1 = product_ids.get(0).ok_or("No product ID 1")?;
/// let product_id_2 = product_ids.get(1).ok_or("No product ID 2")?;
///
/// # Ok(())
/// # }
/// ```
pub async fn product_id_bulk(&self, item_ids: Vec<u64>) -> Result<Vec<u64>, RoboatError> {
let item_ids_len = item_ids.len();

let mut items = Vec::new();

for item_id in item_ids {
let item = ItemArgs {
item_type: ItemType::Asset,
id: item_id,
};

items.push(item);
}

let details = self.item_details(items).await?;

let product_ids = details
.iter()
.filter_map(|x| x.product_id)
.collect::<Vec<u64>>();

if product_ids.len() != item_ids_len {
return Err(RoboatError::MalformedResponse);
}

Ok(product_ids)
}

/// Fetches the collectible item id of a multiple non-tradeable limited (including ugc limiteds).
/// More efficient than calling [`Client::product_id`] repeatedly.
/// Uses [`Client::item_details`] internally
/// (which fetches from <https://catalog.roblox.com/v1/catalog/items/details>).
///
/// # Notes
/// * Does not require a valid roblosecurity.
/// * Will repeat once if the x-csrf-token is invalid.
///
/// # Errors
/// * All errors under [Standard Errors](#standard-errors).
/// * All errors under [X-CSRF-TOKEN Required Errors](#x-csrf-token-required-errors).
///
/// # Example
/// ```no_run
/// use roboat::ClientBuilder;
///
/// const ROBLOSECURITY: &str = "roblosecurity";
///
/// # #[tokio::main]
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let client = ClientBuilder::new().build();
///
/// let item_id = 12345679;
///
/// let collectible_item_id = client.collectible_item_id(item_id).await?;
/// # Ok(())
/// # }
/// ```
pub async fn collectible_item_id(&self, item_id: u64) -> Result<String, RoboatError> {
let item = ItemArgs {
item_type: ItemType::Asset,
id: item_id,
};

let details = self.item_details(vec![item]).await?;

details
.get(0)
.ok_or(RoboatError::MalformedResponse)?
.collectible_item_id
.clone()
.ok_or(RoboatError::MalformedResponse)
}

/// Fetches the collectible item ids of multiple non-tradeable limiteds (including ugc limiteds).
/// More efficient than calling [`Client::collectible_item_id`] repeatedly.
/// Uses [`Client::item_details`] internally
/// (which fetches from <https://catalog.roblox.com/v1/catalog/items/details>).
///
/// # Notes
/// * Does not require a valid roblosecurity.
/// * This endpoint will accept up to 120 items at a time.
/// * Will repeat once if the x-csrf-token is invalid.
///
/// # Errors
/// * All errors under [Standard Errors](#standard-errors).
/// * All errors under [X-CSRF-TOKEN Required Errors](#x-csrf-token-required-errors).
///
/// # Example
/// ```no_run
/// use roboat::ClientBuilder;
///
/// const ROBLOSECURITY: &str = "roblosecurity";
///
/// # #[tokio::main]
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let client = ClientBuilder::new().build();
///
/// let item_id_1 = 12345679;
/// let item_id_2 = 987654321;
///
/// let collectible_item_ids = client.collectible_item_id_bulk(vec![item_id_1, item_id_2]).await?;
///
/// let collectible_item_id_1 = collectible_item_ids.get(0).ok_or("No collectible item ID 1")?;
/// let collectible_item_id_2 = collectible_item_ids.get(1).ok_or("No collectible item ID 2")?;
///
/// # Ok(())
/// # }
/// ```
pub async fn collectible_item_id_bulk(
&self,
item_ids: Vec<u64>,
) -> Result<Vec<String>, RoboatError> {
let item_ids_len = item_ids.len();

let mut items = Vec::new();

for item_id in item_ids {
let item = ItemArgs {
item_type: ItemType::Asset,
id: item_id,
};

items.push(item);
}

let details = self.item_details(items).await?;

let collectible_item_ids = details
.iter()
.filter_map(|x| x.collectible_item_id.clone())
.collect::<Vec<String>>();

if collectible_item_ids.len() != item_ids_len {
return Err(RoboatError::MalformedResponse);
}

Ok(collectible_item_ids)
}
}

mod internal {
use super::{request_types, ItemArgs, ItemDetails, ITEM_DETAILS_API};
use crate::XCSRF_HEADER;
use crate::{Client, RoboatError};
use std::convert::TryFrom;

impl Client {
/// Used internally to fetch the details of one or more items from <https://catalog.roblox.com/v1/catalog/items/details>.
pub(super) async fn item_details_internal(
&self,
items: Vec<ItemArgs>,
Expand Down
Loading

0 comments on commit 5807319

Please sign in to comment.