Skip to content

Commit

Permalink
feat: add Rust SDK documentation (#85)
Browse files Browse the repository at this point in the history
  • Loading branch information
null8626 authored Mar 22, 2024
1 parent bf13f99 commit 4328280
Show file tree
Hide file tree
Showing 3 changed files with 386 additions and 2 deletions.
1 change: 1 addition & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 2 additions & 2 deletions content/libraries/javascript.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Javascript
description: Official Top.gg Javascript library
title: JavaScript
description: Official Top.gg JavaScript library
---

## Links
Expand Down
383 changes: 383 additions & 0 deletions content/libraries/rust.mdx
Original file line number Diff line number Diff line change
@@ -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 = "<vote>")]
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
}
```

0 comments on commit 4328280

Please sign in to comment.