Skip to content

Commit b99cc40

Browse files
committed
use slog, add ping roles & allow for reddit post proxies
1 parent b6f4abd commit b99cc40

12 files changed

+298
-162
lines changed

README.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Invite the bot [here](https://discord.com/oauth2/authorize?client_id=84639624924
3636
To add a new subreddit run
3737

3838
```bash
39-
/reddit add <subreddit-name> (new/hot/top/rising) (embed/text)
39+
/reddit add <subreddit-name> (new/hot/top/rising) (embed/text/link) (role) (proxy)
4040
```
4141

4242
and click the returned link
@@ -48,7 +48,7 @@ select the server & channel in the discord popup & hit okay that's all!
4848
To update a subreddit run
4949

5050
```bash
51-
/reddit update <subreddit-name> (new/hot/top/rising) (embed/text)
51+
/reddit update <subreddit-name> (new/hot/top/rising) (embed/text/link) (role) (proxy)
5252
```
5353

5454
### Remove Subreddit
@@ -92,7 +92,7 @@ Prerequisites:
9292
```bash
9393
$ git clone [email protected]:topi314/Reddit-Discord-Bot.git
9494
$ cd Reddit-Discord-Bot
95-
$ go build -o reddit-discord-bot .
95+
$ go build -o reddit-discord-bot github.com/topi314/reddit-discord-bot/v2
9696
```
9797

9898
You can now run the bot with
@@ -167,7 +167,7 @@ If you encounter any problems feel free to open an issue or reach out to me(`to
167167

168168
# License
169169

170-
Reddit-Discord-Bot is licensed under the [Apache License 2.0](/LICENSE).
170+
Reddit-Discord-Bot is licensed under the [Apache License 2.0](LICENSE).
171171

172172
# Contributing
173173

config.example.yml

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
test_mode: false
33

44
log:
5-
# 0: trace, 1: debug, 2: info, 3: warn, 4: error, 5: fatal, 6: panic
6-
level: 2
5+
# debug, info, warn, error
6+
level: info
7+
format: text
78
add_source: true
89

910
# disable the server if you don't want to rely on an oauth2 flow to create the webhook

go.mod

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ go 1.23
55
require (
66
github.com/disgoorg/disgo v0.18.13
77
github.com/disgoorg/json v1.2.0
8-
github.com/disgoorg/log v1.2.1
98
github.com/disgoorg/snowflake/v2 v2.0.3
109
github.com/jackc/pgx/v5 v5.7.1
1110
github.com/jmoiron/sqlx v1.4.0

go.sum

-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ github.com/disgoorg/disgo v0.18.13 h1:RswLnakVS+RbCACBfK7mLv3YGdZh625N2SMnngnqd+
1111
github.com/disgoorg/disgo v0.18.13/go.mod h1:wZ/ZW6x43QivIVrYrJxwSeFbIbrMqpi5vAU1ovsod8o=
1212
github.com/disgoorg/json v1.2.0 h1:6e/j4BCfSHIvucG1cd7tJPAOp1RgnnMFSqkvZUtEd1Y=
1313
github.com/disgoorg/json v1.2.0/go.mod h1:BHDwdde0rpQFDVsRLKhma6Y7fTbQKub/zdGO5O9NqqA=
14-
github.com/disgoorg/log v1.2.1 h1:kZYAWkUBcGy4LbZcgYtgYu49xNVLy+xG5Uq3yz5VVQs=
15-
github.com/disgoorg/log v1.2.1/go.mod h1:hhQWYTFTnIGzAuFPZyXJEi11IBm9wq+/TVZt/FEwX0o=
1614
github.com/disgoorg/snowflake/v2 v2.0.3 h1:3B+PpFjr7j4ad7oeJu4RlQ+nYOTadsKapJIzgvSI2Ro=
1715
github.com/disgoorg/snowflake/v2 v2.0.3/go.mod h1:W6r7NUA7DwfZLwr00km6G4UnZ0zcoLBRufhkFWgAc4c=
1816
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=

main.go

+55-41
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ package main
33
import (
44
"context"
55
_ "embed"
6-
"math/rand"
6+
"fmt"
7+
"log/slog"
78
"net/http"
89
"os"
910
"os/signal"
@@ -12,10 +13,7 @@ import (
1213

1314
"github.com/disgoorg/disgo"
1415
"github.com/disgoorg/disgo/bot"
15-
"github.com/disgoorg/disgo/discord"
16-
"github.com/disgoorg/log"
1716
"github.com/prometheus/client_golang/prometheus/promhttp"
18-
"golang.org/x/oauth2"
1917

2018
"github.com/topi314/reddit-discord-bot/v2/redditbot"
2119
)
@@ -34,59 +32,44 @@ var (
3432
)
3533

3634
func main() {
37-
log.Infof("starting reddit-discord-bot version: %s (%s)", Version, Commit)
35+
slog.Info("starting reddit-discord-bot...", slog.String("version", Version), slog.String("commit", Commit))
3836
cfg, err := redditbot.ReadConfig()
3937
if err != nil {
40-
log.Fatal("error reading config:", err.Error())
38+
slog.Error("error reading config", slog.Any("err", err))
39+
return
4140
}
4241

43-
log.SetLevel(cfg.Log.Level)
44-
log.SetFlags(cfg.Log.Flags())
42+
if err = setupLogger(cfg.Log); err != nil {
43+
slog.Error("error setting up logger", slog.Any("err", err))
44+
return
45+
}
4546

46-
log.Info("Config:", cfg)
47+
slog.Info("loaded config", slog.String("config", cfg.String()))
4748
if err = cfg.Validate(); err != nil {
48-
log.Fatalf(err.Error())
49+
slog.Error("error validating config", slog.Any("err", err))
50+
return
4951
}
5052

5153
client, err := disgo.New(cfg.Discord.Token,
5254
bot.WithDefaultGateway(),
5355
)
5456
if err != nil {
55-
log.Fatal("error creating client:", err.Error())
57+
slog.Error("error creating client", slog.Any("err", err))
58+
return
5659
}
5760

58-
reddit, err := redditbot.NewReddit(cfg.Reddit)
61+
reddit, err := redditbot.NewReddit(cfg.Reddit, Version)
5962
if err != nil {
60-
log.Fatal("error creating reddit client:", err.Error())
63+
slog.Error("error creating reddit client", slog.Any("err", err))
64+
return
6165
}
6266

6367
db, err := redditbot.NewDB(cfg.Database, schema)
6468
if err != nil {
65-
log.Fatal("error creating database client:", err.Error())
69+
slog.Error("error creating database client", slog.Any("err", err))
6670
}
6771

68-
b := redditbot.Bot{
69-
Cfg: cfg,
70-
RedditIcon: redditIcon,
71-
Client: client,
72-
Reddit: reddit,
73-
DB: db,
74-
Rand: rand.New(rand.NewSource(time.Now().UnixNano())),
75-
DiscordConfig: &oauth2.Config{
76-
ClientID: client.ApplicationID().String(),
77-
ClientSecret: cfg.Discord.ClientSecret,
78-
Endpoint: oauth2.Endpoint{
79-
AuthURL: "https://discord.com/api/oauth2/authorize",
80-
TokenURL: "https://discord.com/api/oauth2/token",
81-
AuthStyle: oauth2.AuthStyleInParams,
82-
},
83-
RedirectURL: cfg.Server.RedirectURL,
84-
Scopes: []string{
85-
string(discord.OAuth2ScopeWebhookIncoming),
86-
},
87-
},
88-
States: map[string]redditbot.SetupState{},
89-
}
72+
b := redditbot.New(cfg, redditIcon, client, reddit, db)
9073
defer b.Close()
9174

9275
if cfg.Metrics.Enabled {
@@ -111,31 +94,62 @@ func main() {
11194

11295
if cfg.Discord.SyncCommands {
11396
if _, err = client.Rest().SetGlobalCommands(client.ApplicationID(), redditbot.Commands); err != nil {
114-
log.Fatal("error setting global commands:", err.Error())
97+
slog.Error("error setting global commands", slog.Any("err", err))
11598
}
11699
}
117100

118101
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
119102
defer cancel()
120103
if err = client.OpenGateway(ctx); err != nil {
121-
log.Fatal("error opening gateway:", err.Error())
104+
slog.Error("error opening discord gateway", slog.Any("err", err))
122105
}
123106

124107
go b.ListenSubreddits()
125108

126109
if cfg.Server.Enabled {
127110
go b.ListenAndServe()
128-
defer b.Server.Shutdown(context.Background())
111+
defer func() {
112+
sCtx, sCancel := context.WithTimeout(context.Background(), 5*time.Second)
113+
defer sCancel()
114+
if sErr := b.Server.Shutdown(sCtx); sErr != nil {
115+
slog.Error("error shutting down server", slog.Any("err", sErr))
116+
}
117+
}()
129118
}
130119

131120
if cfg.Metrics.Enabled {
132121
go b.ListenAndServeMetrics()
133-
defer b.MetricsServer.Shutdown(context.Background())
122+
defer func() {
123+
mCtx, mCancel := context.WithTimeout(context.Background(), 5*time.Second)
124+
defer mCancel()
125+
if mErr := b.MetricsServer.Shutdown(mCtx); mErr != nil {
126+
slog.Error("error shutting down metrics server", slog.Any("err", mErr))
127+
}
128+
}()
134129
}
135130

136-
defer log.Info("exiting...")
131+
defer slog.Info("stopping reddit-discord-bot...")
137132

138133
s := make(chan os.Signal, 1)
139134
signal.Notify(s, syscall.SIGINT, syscall.SIGTERM)
140135
<-s
141136
}
137+
138+
func setupLogger(cfg redditbot.LogConfig) error {
139+
options := &slog.HandlerOptions{
140+
AddSource: cfg.AddSource,
141+
Level: cfg.Level,
142+
}
143+
144+
var sHandler slog.Handler
145+
switch cfg.Format {
146+
case "json":
147+
sHandler = slog.NewJSONHandler(os.Stdout, options)
148+
case "text":
149+
sHandler = slog.NewTextHandler(os.Stdout, options)
150+
default:
151+
return fmt.Errorf("unknown log format: %s", cfg.Format)
152+
}
153+
slog.SetDefault(slog.New(sHandler))
154+
return nil
155+
}

redditbot/bot.go

+49-13
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,26 @@ package redditbot
33
import (
44
"context"
55
"errors"
6+
"log/slog"
67
"math/rand"
78
"net/http"
9+
"os"
10+
"sync"
11+
"time"
812

913
"github.com/disgoorg/disgo/bot"
1014
"github.com/disgoorg/disgo/discord"
11-
"github.com/disgoorg/log"
15+
"github.com/disgoorg/snowflake/v2"
1216
"github.com/prometheus/client_golang/prometheus"
1317
"github.com/prometheus/client_golang/prometheus/promauto"
1418
"golang.org/x/oauth2"
1519
)
1620

17-
const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
21+
const (
22+
letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
23+
authURL = "https://discord.com/api/oauth2/authorize"
24+
tokenURL = "https://discord.com/api/oauth2/token"
25+
)
1826

1927
var postsSent = promauto.NewCounterVec(prometheus.CounterOpts{
2028
Name: "redditbot_posts_sent",
@@ -35,46 +43,74 @@ type SetupState struct {
3543
Subreddit string
3644
PostType string
3745
FormatType FormatType
46+
RoleID snowflake.ID
47+
RedditProxy string
3848
Interaction discord.ApplicationCommandInteraction
3949
}
4050

51+
func New(cfg Config, redditIcon []byte, client bot.Client, reddit *Reddit, db *DB) *Bot {
52+
return &Bot{
53+
cfg: cfg,
54+
redditIcon: redditIcon,
55+
Client: client,
56+
reddit: reddit,
57+
db: db,
58+
rand: rand.New(rand.NewSource(time.Now().UnixNano())),
59+
discordConfig: &oauth2.Config{
60+
ClientID: client.ApplicationID().String(),
61+
ClientSecret: cfg.Discord.ClientSecret,
62+
Endpoint: oauth2.Endpoint{
63+
AuthURL: authURL,
64+
TokenURL: tokenURL,
65+
AuthStyle: oauth2.AuthStyleInParams,
66+
},
67+
RedirectURL: cfg.Server.RedirectURL,
68+
Scopes: []string{string(discord.OAuth2ScopeWebhookIncoming)},
69+
},
70+
states: make(map[string]SetupState),
71+
}
72+
}
73+
4174
type Bot struct {
42-
Cfg Config
43-
RedditIcon []byte
75+
cfg Config
76+
redditIcon []byte
4477
Client bot.Client
45-
Reddit *Reddit
46-
DB *DB
78+
reddit *Reddit
79+
db *DB
4780
Server *http.Server
4881
MetricsServer *http.Server
49-
DiscordConfig *oauth2.Config
50-
Rand *rand.Rand
82+
discordConfig *oauth2.Config
83+
rand *rand.Rand
5184

52-
States map[string]SetupState
85+
states map[string]SetupState
86+
statesMu sync.Mutex
5387
}
5488

5589
func (b *Bot) randomString(length int) string {
5690
bb := make([]byte, length)
5791
for i := range bb {
58-
bb[i] = letters[b.Rand.Intn(len(letters))]
92+
bb[i] = letters[b.rand.Intn(len(letters))]
5993
}
6094
return string(bb)
6195
}
6296

6397
func (b *Bot) ListenAndServe() {
6498
if err := b.Server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
65-
log.Fatal("error starting server:", err.Error())
99+
slog.Error("error starting server", slog.Any("err", err))
100+
os.Exit(-1)
66101
}
67102
}
68103

69104
func (b *Bot) ListenAndServeMetrics() {
70105
if err := b.MetricsServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
71-
log.Fatal("error starting server:", err.Error())
106+
slog.Error("error starting metrics server", slog.Any("err", err))
107+
os.Exit(-1)
72108
}
73109
}
74110

75111
func (b *Bot) Close() {
76112
b.Client.Close(context.Background())
77-
_ = b.DB.Close()
113+
_ = b.db.Close()
78114
_ = b.Server.Shutdown(context.Background())
79115
if b.MetricsServer != nil {
80116
_ = b.MetricsServer.Shutdown(context.Background())

0 commit comments

Comments
 (0)