The official Rust SDK for the Top.gg API.
Make sure to have a Top.gg API token handy, you can have an API token if you own a listed Discord bot on Top.gg (open the edit page, see in Webhooks
section) then add the following to your Cargo.toml
's dependencies:
toml
topgg = "1.1"
This library provides several feature flags that can be enabled/disabled in Cargo.toml
. Such as:
api
: Interacting with the Top.gg API and accessing the top.gg/api/*
endpoints. (enabled by default)
autoposter
: Automating the process of periodically posting bot statistics to the Top.gg API.webhook
: Accessing the serde
deserializable topgg::Vote
struct.
More things can be read in the documentation.
api
: Fetching a single Discord user from it's Discord ID
```rust,no_run use topgg::Client;
async fn main() { let client = Client::new(env!("TOPGG_TOKEN"));
let user = client.get_user(661200758510977084).await.unwrap();
asserteq!(user.username, "null"); asserteq!(user.id, 661200758510977084);
println!("{:?}", user); } ```
api
: Fetching a single Discord bot from it's Discord ID
```rust,no_run use topgg::Client;
async fn main() { let client = Client::new(env!("TOPGG_TOKEN"));
let bot = client.get_bot(264811613708746752).await.unwrap();
asserteq!(bot.username, "Luca"); asserteq!(bot.id, 264811613708746752);
println!("{:?}", bot); } ```
api
: Querying several Discord bots
```rust,no_run use topgg::{Client, Filter, Query};
async fn main() { let client = Client::new(env!("TOPGG_TOKEN"));
// inputting a string searches a bot that matches that username. for bot in client.get_bots("shiro").await.unwrap() { println!("{:?}", bot); }
// advanced query with filters... let filter = Filter::new() .username("shiro") .certified(true);
let query = Query::new() .limit(250) .skip(50) .filter(filter);
for bot in client.get_bots(query).await.unwrap() { println!("{:?}", bot); } } ```
api
: Posting your Discord bot's statistics
```rust,no_run use topgg::{Client, NewStats};
async fn main() { let client = Client::new(env!("TOPGG_TOKEN"));
let servercount = 1234; // be TRUTHFUL! let shardcount = 10;
let stats = NewStats::countbased(servercount, Some(shard_count));
client.post_stats(stats).await.unwrap(); } ```
api
: Checking if a user has voted for your Discord bot
```rust,no_run use topgg::Client;
async fn main() { let client = Client::new(env!("TOPGG_TOKEN"));
if client.has_voted(661200758510977084).await.unwrap() { println!("checks out"); } } ```
autoposter
: Automating the process of periodically posting your Discord bot's statistics
In your Cargo.toml
:
toml
[dependencies]
topgg = { version = "1.1", features = ["autoposter"] }
In your code:
```rust,no_run use core::time::Duration; use topgg::{Autoposter, Client, NewStats};
async fn main() { let client = Client::new(env!("TOPGG_TOKEN"));
// creates an autoposter that posts data to Top.gg every 1800 seconds (15 minutes). // the autopost thread will stop once it's dropped. let autoposter = client.newautoposter(Duration::fromsecs(1800));
// ... then in some on ready/new guild event ... let servercount = 12345; let stats = NewStats::countbased(server_count, None); autoposter.feed(stats).await; } ```
actix
: Writing an actix-web
webhook for listening to your bot/server's vote events
In your Cargo.toml
:
toml
[dependencies]
topgg = { version = "1.1", default-features = false, features = ["actix"] }
In your code:
```rust,norun use actixweb::{ error::{Error, ErrorUnauthorized}, get, post, App, HttpServer, }; use std::io; use topgg::IncomingVote;
async fn index() -> &'static str { "Hello, World!" }
async fn webhook(vote: IncomingVote) -> Result<&'static str, Error> { match vote.authenticate(env!("TOPGGWEBHOOKPASSWORD")) { Some(vote) => { println!("{:?}", vote);
Ok("ok")
},
_ => Err(ErrorUnauthorized("401")),
} }
async fn main() -> io::Result<()> { HttpServer::new(|| App::new().service(index).service(webhook)) .bind("127.0.0.1:8080")? .run() .await } ```
axum
: Writing an axum
webhook for listening to your bot/server's vote events
In your Cargo.toml
:
toml
[dependencies]
topgg = { version = "1.1", default-features = false, features = ["axum"] }
In your code:
```rust,no_run use axum::{routing::get, Router, Server}; use topgg::{Vote, VoteHandler};
struct MyVoteHandler {}
impl VoteHandler for MyVoteHandler { async fn voted(&self, vote: Vote) { println!("{:?}", vote); } }
async fn index() -> &'static str { "Hello, World!" }
async fn main() { let password = env!("TOPGGWEBHOOKPASSWORD").to_owned(); let state = MyVoteHandler {};
let app = Router::new() .route("/", get(index)) .nest("/webhook", topgg::axum::webhook(password, state));
// this will always be a valid SocketAddr syntax, // therefore we can safely unwrapunchecked this. let addr = unsafe { "127.0.0.1:8080".parse().unwrapunchecked() };
Server::bind(&addr) .serve(app.intomakeservice()) .await .unwrap(); } ```
rocket
: Writing a rocket
webhook for listening to your bot/server's vote events
In your Cargo.toml
:
toml
[dependencies]
topgg = { version = "1.1", default-features = false, features = ["rocket"] }
In your code:
```rust,no_run
use rocket::{get, http::Status, post, routes}; use topgg::IncomingVote;
fn index() -> &'static str { "Hello, World!" }
fn webhook(vote: IncomingVote) -> Status { match vote.authenticate(env!("TOPGGWEBHOOKPASSWORD")) { Some(vote) => { println!("{:?}", vote);
// 200 and 401 will always be a valid status code,
// therefore we can safely unwrap_unchecked these.
unsafe { Status::from_code(200).unwrap_unchecked() }
},
_ => {
println!("found an unauthorized attacker.");
unsafe { Status::from_code(401).unwrap_unchecked() }
},
} }
fn main() { rocket::ignite() .mount("/", routes![index, webhook]) .launch(); } ```
warp
: Writing a warp
webhook for listening to your bot/server's vote events
In your Cargo.toml
:
toml
[dependencies]
topgg = { version = "1.1", default-features = false, features = ["warp"] }
In your code:
```rust,no_run use std::net::SocketAddr; use topgg::{Vote, VoteHandler}; use warp::Filter;
struct MyVoteHandler {}
impl VoteHandler for MyVoteHandler { async fn voted(&self, vote: Vote) { println!("{:?}", vote); } }
async fn main() { let password = env!("TOPGGWEBHOOKPASSWORD").to_owned(); let state = MyVoteHandler {};
// POST /webhook let webhook = topgg::warp::webhook("webhook", password, state);
let routes = warp::get() .map(|| "Hello, World!") .or(webhook);
// this will always be a valid SocketAddr syntax, // therefore we can safely unwrapunchecked this. let addr: SocketAddr = unsafe { "127.0.0.1:8080".parse().unwrapunchecked() };
warp::serve(routes) .run(addr) .await } ```