Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2018 RumbleFrog
Copyright (c) 2018-2025 RumbleFrog

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
276 changes: 188 additions & 88 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,134 +1,234 @@
## Go DBL
# Top.gg Go SDK

The community-maintained Go library for Top.gg.

## Chapters

- [Installation](#installation)
- [Setting up](#setting-up)
- [Usage](#usage)
- [Getting a bot](#getting-a-bot)
- [Getting several bots](#getting-several-bots)
- [Getting your bot's voters](#getting-your-bots-voters)
- [Check if a user has voted for your bot](#check-if-a-user-has-voted-for-your-bot)
- [Getting your bot's server count](#getting-your-bots-server-count)
- [Posting your bot's server count](#posting-your-bots-server-count)
- [Automatically posting your bot's server count every few minutes](#automatically-posting-your-bots-server-count-every-few-minutes)
- [Checking if the weekend vote multiplier is active](#checking-if-the-weekend-vote-multiplier-is-active)
- [Generating widget URLs](#generating-widget-urls)
- [Webhooks](#webhooks)
- [Being notified whenever someone voted for your bot](#being-notified-whenever-someone-voted-for-your-bot)

## Installation

```sh
$ go get -u github.com/top-gg/go-dbl
```

## Setting up

[![Build Status](https://travis-ci.com/rumblefrog/go-dbl.svg?branch=master)](https://travis-ci.com/rumblefrog/go-dbl)
[![Go Report Card](https://goreportcard.com/badge/github.com/DiscordBotList/go-dbl)](https://goreportcard.com/report/github.com/DiscordBotList/go-dbl)
[![GoDoc](https://godoc.org/github.com/DiscordBotList/go-dbl?status.svg)](https://godoc.org/github.com/DiscordBotList/go-dbl)
### With defaults

An API wrapper for [Discord Bots](https://top.gg/)
```go
client, err := dbl.NewClient(os.Getenv("TOPGG_TOKEN"))

if err != nil {
log.Fatalf("Error creating new Top.gg client: %s", err)
}
```

Godoc is available here: https://godoc.org/github.com/DiscordBotList/go-dbl
### With explicit options

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
## Table of Contents
```go
clientTimeout := 5 * time.Second
httpClient := &http.Client{}

- [Go DBL](#go-dbl)
- [Table of Contents](#table-of-contents)
- [Guides](#guides)
- [Installing](#installing)
- [Posting Stats](#posting-stats)
- [Setting options](#setting-options)
- [Ratelimits](#ratelimits)
- [Webhook](#webhook)
- [More details](#more-details)
client, err := dbl.NewClient(
os.Getenv("TOPGG_TOKEN"),
dbl.HTTPClientOption(httpClient),
dbl.TimeoutOption(clientTimeout),
)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->
if err != nil {
log.Fatalf("Error creating new Top.gg client: %s", err)
}
```

## Guides
## Usage

### Installing
### Getting a bot

```bash
go get -u github.com/top-gg/go-dbl
```go
bot, err := client.GetBot("574652751745777665")

if err != nil {
log.Fatalf("Unable to get a bot: %s", err)
}
```

### Posting Stats
### Getting several bots

```go
package main
bots, err := client.GetBots(&GetBotsPayload{
Limit: 20,
})

import (
"log"
if err != nil {
log.Fatalf("Unable to get several bots: %s", err)
}
```

"github.com/top-gg/go-dbl"
)
### Getting your bot's voters

func main() {
dblClient, err := dbl.NewClient("token")
if err != nil {
log.Fatalf("Error creating new Discord Bot List client: %s", err)
}

err = dblClient.PostBotStats("botID", &dbl.BotStatsPayload{
Shards: []int{2500}, // If non-sharded, just pass total server count as the only integer element
})
if err != nil {
log.Printf("Error sending bot stats to Discord Bot List: %s", err)
}

// ...
#### First page

```go
firstPageVoters, err := client.GetVoters(1)

if err != nil {
log.Fatalf("Unable to get voters: %s", err)
}
```

### Setting options
#### Subsequent pages

```go
package main
secondPageVoters, err := client.GetVoters(2)

import (
"log"
"net/http"
"time"
if err != nil {
log.Fatalf("Unable to get voters: %s", err)
}
```

"github.com/top-gg/go-dbl"
)
### Check if a user has voted for your bot

const clientTimeout = 5 * time.Second
```go
has_voted, err := client.HasUserVoted("661200758510977084")

func main() {
httpClient := &http.Client{}

dblClient, err := dbl.NewClient(
"token",
dbl.HTTPClientOption(httpClient), // Setting a custom HTTP client. Default is *http.Client with default timeout.
dbl.TimeoutOption(clientTimeout), // Setting timeout option. Default is 3 seconds
)
if err != nil {
log.Fatalf("Error creating new Discord Bot List client: %s", err)
}

// ...
if err != nil {
log.Fatalf("Unable to check if a user has voted: %s", err)
}
```

### Getting your bot's server count

```go
serverCount, err := client.GetServerCount()

if err != nil {
log.Fatalf("Unable to get server count: %s", err)
}
```

### Posting your bot's server count

```go
err := client.PostServerCount(bot.GetServerCount())

if err != nil {
log.Fatalf("Unable to post server count: %s", err)
}
```

### Automatically posting your bot's server count every few minutes

```go
// Posts once every 30 minutes
autoposter, err := client.StartAutoposter(1800000, func() int {
return bot.GetServerCount()
})

if err != nil {
log.Fatalf("Unable to start autoposter: %s", err)
}

go func() {
for {
post_err := <-autoposter.Posted

if post_err != nil {
log.Fatalf("Unable to post server count: %s", post_err)
}
}
}()

// ...

autoposter.Stop() // Optional
```

### Checking if the weekend vote multiplier is active

```go
multiplierActive, err := client.IsMultiplierActive()

if err != nil {
log.Fatalf("Unable to check weekend vote multiplier: %s", err)
}
```

### Ratelimits
### Generating widget URLs

There's a local token bucket rate limiter, allowing for 60 requests a minute (single/burst)
#### Large

Upon reaching the local rate limit, `ErrLocalRatelimit` error will be returned
```go
widgetUrl := dbl.LargeWidget(dbl.DiscordBotWidget, "574652751745777665")
```

#### Votes

```go
widgetUrl := dbl.VotesWidget(dbl.DiscordBotWidget, "574652751745777665")
```

If remote rate limit is exceeded, `ErrRemoteRatelimit` error will be returned and `RetryAfter` in client fields will be updated with the retry time
#### Owner

### Webhook
```go
widgetUrl := dbl.OwnerWidget(dbl.DiscordBotWidget, "574652751745777665")
```

#### Social

```go
widgetUrl := dbl.SocialWidget(dbl.DiscordBotWidget, "574652751745777665")
```

### Webhooks

#### Being notified whenever someone voted for your bot

```go
package main

import (
"errors"
"log"
"net/http"
"errors"
"fmt"
"log"
"os"
"net/http"

"github.com/top-gg/go-dbl"
"github.com/top-gg/go-dbl"
)

const listenerPort = ":9090"

func main() {
listener := dbl.NewListener("token", handleVote)
listener := dbl.NewWebhookListener(os.Getenv("MY_TOPGG_WEBHOOK_SECRET"), "/votes", handleVote)

// Serve is a blocking call
err := listener.Serve(listenerPort)
if !errors.Is(err, http.ErrServerClosed) {
log.Fatalf("HTTP server error: %s", err)
}
}
// Serve is a blocking call
err := listener.Serve(":8080")

func handleVote(payload *dbl.WebhookPayload) {
// perform on payload
if !errors.Is(err, http.ErrServerClosed) {
log.Fatalf("HTTP server error: %s", err)
}
}
```

### More details
func handleVote(payload []byte) {
vote, err := dbl.NewWebhookVotePayload(payload)

For more details, Godoc and tests are available
if err != nil {
fmt.Fprintf(os.Stderr, "Error: Unable to parse webhook payload: %s", err)
return
}

fmt.Printf("A user with the ID of %s has voted us on Top.gg!", vote.VoterId)
}
```
27 changes: 27 additions & 0 deletions autoposter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package dbl

import (
"os"
"testing"

"github.com/stretchr/testify/assert"
)

func TestAutoposter(t *testing.T) {
client, err := NewClient(os.Getenv("TOPGG_TOKEN"))

assert.Nil(t, err, "Client should be created w/o error")

autoposter, err := client.StartAutoposter(900000, func() int {
return 2
})

assert.Nil(t, err, "Autoposter should be created w/o error")

for i := 0; i < 3; i++ {
err := <-autoposter.Posted
assert.Nil(t, err, "Posting should not error")
}

autoposter.Stop()
}
Loading