From 432828007664affd633e8681924a87e68f5bdd71 Mon Sep 17 00:00:00 2001 From: null <60427892+null8626@users.noreply.github.com> Date: Fri, 22 Mar 2024 07:36:43 +0700 Subject: [PATCH] feat: add Rust SDK documentation (#85) --- CODEOWNERS | 1 + content/libraries/javascript.mdx | 4 +- content/libraries/rust.mdx | 383 +++++++++++++++++++++++++++++++ 3 files changed, 386 insertions(+), 2 deletions(-) create mode 100644 content/libraries/rust.mdx diff --git a/CODEOWNERS b/CODEOWNERS index 7bd3da7..6a8b698 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -4,3 +4,4 @@ content/libraries/dotnet.mdx @velddev @faith-ie content/libraries/go.mdx @rumblefrog content/libraries/php.mdx @goverfl0w content/libraries/java.mdx @nikammerlaan +content/libraries/rust.mdx @null8626 diff --git a/content/libraries/javascript.mdx b/content/libraries/javascript.mdx index 5062de8..89e38b2 100644 --- a/content/libraries/javascript.mdx +++ b/content/libraries/javascript.mdx @@ -1,6 +1,6 @@ --- -title: Javascript -description: Official Top.gg Javascript library +title: JavaScript +description: Official Top.gg JavaScript library --- ## Links diff --git a/content/libraries/rust.mdx b/content/libraries/rust.mdx new file mode 100644 index 0000000..57f3821 --- /dev/null +++ b/content/libraries/rust.mdx @@ -0,0 +1,383 @@ +--- +title: Rust +description: Top.gg Rust library +--- + +# [topgg](https://crates.io/crates/topgg) [![crates.io][crates-io-image]][crates-io-url] [![crates.io downloads][crates-io-downloads-image]][crates-io-url] + +[crates-io-image]: https://img.shields.io/crates/v/topgg?style=flat-square +[crates-io-downloads-image]: https://img.shields.io/crates/d/topgg?style=flat-square +[crates-io-url]: https://crates.io/crates/topgg + +The official Rust SDK for the [Top.gg API](https://docs.top.gg). + +## Getting Started + +Make sure to have a [Top.gg API](https://docs.top.gg) token handy. If not, then [view this tutorial on how to retrieve yours](https://github.com/top-gg/rust-sdk/assets/60427892/d2df5bd3-bc48-464c-b878-a04121727bff). After that, add the following line to the `dependencies` section of your `Cargo.toml`: + +```toml +topgg = "1.4" +``` + +For more information, please read [the documentation](https://docs.rs/topgg)! + +## Features + +This library provides several feature flags that can be enabled/disabled in `Cargo.toml`. Such as: + +- **`api`**: Interacting with the [Top.gg API](https://docs.top.gg) and accessing the `top.gg/api/*` endpoints. (enabled by default) + - **`autoposter`**: Automating the process of periodically posting bot statistics to the [Top.gg API](https://docs.top.gg). +- **`webhook`**: Accessing the [serde deserializable](https://docs.rs/serde/latest/serde/de/trait.DeserializeOwned.html) `topgg::Vote` struct. + - **`actix-web`**: Wrapper for working with the [actix-web](https://actix.rs/) web framework. + - **`axum`**: Wrapper for working with the [axum](https://crates.io/crates/axum) web framework. + - **`rocket`**: Wrapper for working with the [rocket](https://rocket.rs/) web framework. + - **`warp`**: Wrapper for working with the [warp](https://crates.io/crates/warp) web framework. +- **`serenity`**: Extra helpers for working with [serenity](https://crates.io/crates/serenity) library (with bot caching disabled). + - **`serenity-cached`**: Extra helpers for working with [serenity](https://crates.io/crates/serenity) library (with bot caching enabled). +- **`twilight`**: Extra helpers for working with [twilight](https://twilight.rs) library (with bot caching disabled). + - **`twilight-cached`**: Extra helpers for working with [twilight](https://twilight.rs) library (with bot caching enabled). + +## Examples + +#### Fetching a single Discord user from it's Discord ID + +```rust,no_run +use topgg::Client; + +#[tokio::main] +async fn main() { + let client = Client::new(env!("TOPGG_TOKEN").to_string()); + let user = client.get_user(661200758510977084).await.unwrap(); + + assert_eq!(user.username, "null"); + assert_eq!(user.id, 661200758510977084); + + println!("{:?}", user); +} +``` + +#### Posting your Discord bot's statistics + +```rust,no_run +use topgg::{Client, Stats}; + +#[tokio::main] +async fn main() { + let client = Client::new(env!("TOPGG_TOKEN").to_string()); + + let server_count = 12345; + client + .post_stats(Stats::from(server_count)) + .await + .unwrap(); +} +``` + +#### Checking if a user has voted your Discord bot + +```rust,no_run +use topgg::Client; + +#[tokio::main] +async fn main() { + let client = Client::new(env!("TOPGG_TOKEN").to_string()); + + if client.has_voted(661200758510977084).await.unwrap() { + println!("checks out"); + } +} +``` + +#### Automating the process of periodically posting your Discord bot's statistics with the [serenity](https://crates.io/crates/serenity) library + +In your `Cargo.toml`: + +```toml +[dependencies] +# using serenity with guild caching disabled +topgg = { version = "1.4", features = ["autoposter", "serenity"] } + +# using serenity with guild caching enabled +topgg = { version = "1.4", features = ["autoposter", "serenity-cached"] } +``` + +In your code: + +```rust,no_run +use core::time::Duration; +use serenity::{client::{Client, Context, EventHandler}, model::{channel::Message, gateway::Ready}}; +use topgg::Autoposter; + +struct Handler; + +#[serenity::async_trait] +impl EventHandler for Handler { + async fn message(&self, ctx: Context, msg: Message) { + if msg.content == "!ping" { + if let Err(why) = msg.channel_id.say(&ctx.http, "Pong!").await { + println!("Error sending message: {why:?}"); + } + } + } + + async fn ready(&self, _: Context, ready: Ready) { + println!("{} is connected!", ready.user.name); + } +} + +#[tokio::main] +async fn main() { + let topgg_client = topgg::Client::new(env!("TOPGG_TOKEN").to_string()); + let autoposter = Autoposter::serenity(&topgg_client, Duration::from_secs(1800)); + + let bot_token = env!("DISCORD_TOKEN").to_string(); + let intents = GatewayIntents::GUILD_MESSAGES | GatewayIntents::GUILDS | GatewayIntents::MESSAGE_CONTENT; + + let mut client = Client::builder(&bot_token, intents) + .event_handler(Handler) + .event_handler_arc(autoposter.handler()) + .await + .unwrap(); + + if let Err(why) = client.start().await { + println!("Client error: {why:?}"); + } +} +``` + +#### Automating the process of periodically posting your Discord bot's statistics with the [twilight](https://twilight.rs) library + +In your `Cargo.toml`: + +```toml +[dependencies] +# using twilight with guild caching disabled +topgg = { version = "1.4", features = ["autoposter", "twilight"] } + +# using twilight with guild caching enabled +topgg = { version = "1.4", features = ["autoposter", "twilight-cached"] } +``` + +In your code: + +```rust,no_run +use core::time::Duration; +use topgg::Autoposter; +use twilight_gateway::{Event, Intents, Shard, ShardId}; + +#[tokio::main] +async fn main() { + let client = topgg::Client::new(env!("TOPGG_TOKEN").to_string()); + let autoposter = Autoposter::twilight(&client, Duration::from_secs(1800)); + + let mut shard = Shard::new( + ShardId::ONE, + env!("DISCORD_TOKEN").to_string(), + Intents::GUILD_MEMBERS | Intents::GUILDS, + ); + + loop { + let event = match shard.next_event().await { + Ok(event) => event, + Err(source) => { + if source.is_fatal() { + break; + } + + continue; + } + }; + + autoposter.handle(&event).await; + + match event { + Event::Ready(_) => { + println!("Bot is ready!"); + }, + + _ => {} + } + } +} +``` + +#### Writing an [actix-web](https://actix.rs) webhook for listening to your bot/server's vote events + +In your `Cargo.toml`: + +```toml +[dependencies] +topgg = { version = "1.4", default-features = false, features = ["actix-web"] } +``` + +In your code: + +```rust,no_run +use actix_web::{ + error::{Error, ErrorUnauthorized}, + get, post, App, HttpServer, +}; +use std::io; +use topgg::IncomingVote; + +#[get("/")] +async fn index() -> &'static str { + "Hello, World!" +} + +#[post("/webhook")] +async fn webhook(vote: IncomingVote) -> Result<&'static str, Error> { + match vote.authenticate(env!("TOPGG_WEBHOOK_PASSWORD")) { + Some(vote) => { + println!("{:?}", vote); + + Ok("ok") + } + _ => Err(ErrorUnauthorized("401")), + } +} + +#[actix_web::main] +async fn main() -> io::Result<()> { + HttpServer::new(|| App::new().service(index).service(webhook)) + .bind("127.0.0.1:8080")? + .run() + .await +} +``` + +#### Writing an [axum](https://crates.io/crates/axum) webhook for listening to your bot/server's vote events + +In your `Cargo.toml`: + +```toml +[dependencies] +topgg = { version = "1.4", default-features = false, features = ["axum"] } +``` + +In your code: + +```rust,no_run +use axum::{routing::get, Router, Server}; +use std::{net::SocketAddr, sync::Arc}; +use topgg::{Vote, VoteHandler}; + +struct MyVoteHandler {} + +#[axum::async_trait] +impl VoteHandler for MyVoteHandler { + async fn voted(&self, vote: Vote) { + println!("{:?}", vote); + } +} + +async fn index() -> &'static str { + "Hello, World!" +} + +#[tokio::main] +async fn main() { + let state = Arc::new(MyVoteHandler {}); + + let app = Router::new().route("/", get(index)).nest( + "/webhook", + topgg::axum::webhook(env!("TOPGG_WEBHOOK_PASSWORD").to_string(), Arc::clone(&state)), + ); + + let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap(); + + Server::bind(&addr) + .serve(app.into_make_service()) + .await + .unwrap(); +} +``` + +#### Writing a [rocket](https://rocket.rs) webhook for listening to your bot/server's vote events + +In your `Cargo.toml`: + +```toml +[dependencies] +topgg = { version = "1.4", default-features = false, features = ["rocket"] } +``` + +In your code: + +```rust,no_run +#![feature(decl_macro)] + +use rocket::{get, http::Status, post, routes}; +use topgg::IncomingVote; + +#[get("/")] +fn index() -> &'static str { + "Hello, World!" +} + +#[post("/webhook", data = "")] +fn webhook(vote: IncomingVote) -> Status { + match vote.authenticate(env!("TOPGG_WEBHOOK_PASSWORD")) { + Some(vote) => { + println!("{:?}", vote); + + Status::Ok + }, + _ => { + println!("found an unauthorized attacker."); + + Status::Unauthorized + } + } +} + +fn main() { + rocket::ignite() + .mount("/", routes![index, webhook]) + .launch(); +} +``` + +#### Writing a [warp](https://crates.io/crates/warp) webhook for listening to your bot/server's vote events + +In your `Cargo.toml`: + +```toml +[dependencies] +topgg = { version = "1.4", default-features = false, features = ["warp"] } +``` + +In your code: + +```rust,no_run +use std::{net::SocketAddr, sync::Arc}; +use topgg::{Vote, VoteHandler}; +use warp::Filter; + +struct MyVoteHandler {} + +#[async_trait::async_trait] +impl VoteHandler for MyVoteHandler { + async fn voted(&self, vote: Vote) { + println!("{:?}", vote); + } +} + +#[tokio::main] +async fn main() { + let state = Arc::new(MyVoteHandler {}); + + // POST /webhook + let webhook = topgg::warp::webhook( + "webhook", + env!("TOPGG_WEBHOOK_PASSWORD").to_string(), + Arc::clone(&state), + ); + + let routes = warp::get().map(|| "Hello, World!").or(webhook); + + let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap(); + + warp::serve(routes).run(addr).await +} +``` \ No newline at end of file