Skip to content

Commit 3480065

Browse files
committed
new structure
1 parent a508362 commit 3480065

File tree

52 files changed

+443
-321
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+443
-321
lines changed

cmd/bot/bot.go

Lines changed: 0 additions & 78 deletions
This file was deleted.

cmd/bot/commands.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package main
22

33
import (
4-
_ "go.fm/commands/chart"
5-
_ "go.fm/commands/fm"
6-
_ "go.fm/commands/profile"
7-
_ "go.fm/commands/setuser"
8-
_ "go.fm/commands/stats"
9-
_ "go.fm/commands/update"
4+
_ "go.fm/internal/bot/commands/chart"
5+
_ "go.fm/internal/bot/commands/fm"
6+
_ "go.fm/internal/bot/commands/profile"
7+
_ "go.fm/internal/bot/commands/setuser"
8+
_ "go.fm/internal/bot/commands/stats"
9+
_ "go.fm/internal/bot/commands/update"
1010
)

cmd/bot/main.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"os"
6+
"os/signal"
7+
"syscall"
8+
9+
"go.fm/internal/bot/bot"
10+
"go.fm/internal/bot/logging"
11+
)
12+
13+
func getEnv(key, fallback string) string {
14+
if v := os.Getenv(key); v != "" {
15+
return v
16+
}
17+
return fallback
18+
}
19+
20+
func main() {
21+
token := os.Getenv("DISCORD_TOKEN")
22+
lastfmKey := os.Getenv("LASTFM_API_KEY")
23+
dbPath := getEnv("DATABASE_PATH", "file:database.db?_foreign_keys=on")
24+
25+
if token == "" || lastfmKey == "" {
26+
logging.Fatal("DISCORD_TOKEN and LASTFM_API_KEY must be set")
27+
}
28+
29+
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
30+
defer cancel()
31+
32+
b, err := bot.NewBot(ctx, token, dbPath, lastfmKey)
33+
if err != nil {
34+
logging.Fatalf("failed to create bot: %v", err)
35+
}
36+
37+
if err := b.Run(ctx); err != nil {
38+
logging.Fatalf("bot stopped with error: %v", err)
39+
}
40+
}

events/events.go

Lines changed: 0 additions & 23 deletions
This file was deleted.

internal/bot/bot/bot.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package bot
2+
3+
import (
4+
"context"
5+
"database/sql"
6+
"os"
7+
"os/signal"
8+
"syscall"
9+
10+
"github.com/nxtgo/arikawa/v3/api/cmdroute"
11+
"github.com/nxtgo/arikawa/v3/gateway"
12+
"github.com/nxtgo/arikawa/v3/state"
13+
"go.fm/internal/bot/bot/events"
14+
"go.fm/internal/bot/commands"
15+
"go.fm/internal/bot/lastfm"
16+
"go.fm/internal/bot/logging"
17+
"go.fm/internal/bot/persistence/sqlc"
18+
)
19+
20+
// package for bot stuff idk.
21+
// functions that open connections should also return
22+
// a function to close that connection :pray:
23+
24+
type Bot struct {
25+
State *state.State
26+
Query *sqlc.Queries
27+
Database *sql.DB
28+
LastFM *lastfm.Services
29+
Cache *lastfm.Cache
30+
Registry *events.Registry
31+
}
32+
33+
func NewBot(ctx context.Context, token, dbPath, lastfmKey string) (*Bot, error) {
34+
logging.Info("starting bot...")
35+
36+
// database
37+
q, db, err := sqlc.Start(ctx, dbPath)
38+
if err != nil {
39+
return nil, err
40+
}
41+
42+
// lastfm
43+
cache := lastfm.NewCache()
44+
lastfm := lastfm.NewServices(lastfmKey, cache)
45+
46+
// bot state
47+
st := state.New("Bot " + token)
48+
st.AddIntents(gateway.IntentGuilds)
49+
st.AddIntents(gateway.IntentGuildMessages)
50+
51+
// events
52+
reg := events.NewRegistry()
53+
events.RegisterDefaultEvents(reg)
54+
55+
// commands
56+
r := cmdroute.NewRouter()
57+
commands.RegisterCommands(r, st, q, cache)
58+
if err := commands.Sync(st); err != nil {
59+
logging.Fatalf("failed syncing commands: %v", err)
60+
}
61+
st.AddInteractionHandler(r)
62+
63+
return &Bot{
64+
State: st,
65+
Query: q,
66+
Database: db,
67+
LastFM: lastfm,
68+
Cache: cache,
69+
Registry: reg,
70+
}, nil
71+
}
72+
73+
func (b *Bot) Run(ctx context.Context) error {
74+
b.State.AddHandler(func(e *gateway.ReadyEvent) {
75+
b.Registry.Dispatch(events.TypeName(e), e)
76+
})
77+
78+
if err := b.State.Open(ctx); err != nil {
79+
return err
80+
}
81+
defer b.State.Close()
82+
defer b.Database.Close()
83+
defer b.Cache.Close()
84+
85+
logging.Info("bot is running")
86+
87+
stop := make(chan os.Signal, 1)
88+
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
89+
90+
select {
91+
case <-ctx.Done():
92+
case <-stop:
93+
}
94+
95+
logging.Info("shutting down")
96+
return nil
97+
}

internal/bot/bot/events/events.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package events
2+
3+
import (
4+
"reflect"
5+
6+
"github.com/nxtgo/arikawa/v3/gateway"
7+
"go.fm/internal/bot/logging"
8+
)
9+
10+
func TypeName(evt any) string {
11+
return reflect.TypeOf(evt).String()
12+
}
13+
14+
// Handler is a generic event handler signature.
15+
type Handler func(evt any)
16+
17+
// Registry holds all event handlers by event type.
18+
type Registry struct {
19+
Handlers map[string][]Handler
20+
logger func(name string) *logging.Logger
21+
}
22+
23+
// NewRegistry creates a new event registry.
24+
func NewRegistry() *Registry {
25+
return &Registry{
26+
Handlers: make(map[string][]Handler),
27+
logger: func(name string) *logging.Logger {
28+
return logging.WithFields(logging.F{"event_name": name})
29+
},
30+
}
31+
}
32+
33+
// On registers a handler for a given event type.
34+
func (r *Registry) On(eventName string, h Handler) {
35+
r.Handlers[eventName] = append(r.Handlers[eventName], h)
36+
}
37+
38+
// Dispatch executes all handlers for a given event.
39+
func (r *Registry) Dispatch(eventName string, evt any) {
40+
log := r.logger(eventName)
41+
for _, h := range r.Handlers[eventName] {
42+
func() {
43+
defer func() {
44+
if rec := recover(); rec != nil {
45+
log.Errorw("panic in event handler", logging.F{"recover": rec})
46+
}
47+
}()
48+
h(evt)
49+
}()
50+
}
51+
}
52+
53+
func RegisterDefaultEvents(r *Registry) {
54+
r.On(TypeName(&gateway.ReadyEvent{}), func(evt any) {
55+
if c, ok := evt.(*gateway.ReadyEvent); ok {
56+
r.logger("ready").Infow("client ready", logging.F{
57+
"tag": c.User.Tag(),
58+
"guilds": len(c.Guilds),
59+
})
60+
}
61+
})
62+
}

commands/chart/chart.go renamed to internal/bot/commands/chart/chart.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ import (
1414
"github.com/nxtgo/arikawa/v3/api"
1515
"github.com/nxtgo/arikawa/v3/discord"
1616
"github.com/nxtgo/arikawa/v3/utils/sendpart"
17-
"go.fm/bild/font"
18-
"go.fm/bild/imgio"
19-
"go.fm/bild/transform"
20-
"go.fm/commands"
21-
lastfm "go.fm/last.fm"
22-
"go.fm/pkg/reply"
17+
"go.fm/internal/bot/commands"
18+
"go.fm/internal/bot/discord/reply"
19+
"go.fm/internal/bot/image/font"
20+
"go.fm/internal/bot/image/imgio"
21+
"go.fm/internal/bot/image/transform"
22+
"go.fm/internal/bot/lastfm"
2323
)
2424

2525
var (

commands/commands.go renamed to internal/bot/commands/commands.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,32 @@ package commands
22

33
import (
44
"context"
5+
"os"
6+
"time"
7+
58
"github.com/nxtgo/arikawa/v3/api"
69
"github.com/nxtgo/arikawa/v3/api/cmdroute"
710
"github.com/nxtgo/arikawa/v3/state"
8-
"go.fm/db"
9-
lastfm "go.fm/last.fm"
10-
"go.fm/pkg/reply"
11-
"go.fm/zlog"
12-
"os"
13-
"time"
11+
"go.fm/internal/bot/discord/reply"
12+
"go.fm/internal/bot/lastfm"
13+
"go.fm/internal/bot/logging"
14+
"go.fm/internal/bot/persistence/sqlc"
1415
)
1516

1617
var allCommands = []api.CreateCommandData{}
1718
var registry = map[string]CommandHandler{}
1819

1920
func Register(meta api.CreateCommandData, handler CommandHandler) {
20-
zlog.Log.Debugf("registered command %s", meta.Name)
21+
logging.Debugf("registered command %s", meta.Name)
2122

2223
allCommands = append(allCommands, meta)
2324
registry[meta.Name] = handler
2425
}
2526

26-
func RegisterCommands(r *cmdroute.Router, st *state.State, q *db.Queries, c *lastfm.Cache) {
27+
func RegisterCommands(r *cmdroute.Router, st *state.State, q *sqlc.Queries, c *lastfm.Cache) {
2728
lastFMApiKey := os.Getenv("LASTFM_API_KEY")
2829
if lastFMApiKey == "" {
29-
zlog.Log.Fatal("missing LASTFM_API_KEY env")
30+
logging.Fatal("missing LASTFM_API_KEY env")
3031
}
3132

3233
for name, handler := range registry {
@@ -52,7 +53,7 @@ func RegisterCommands(r *cmdroute.Router, st *state.State, q *db.Queries, c *las
5253
// debugging purposes
5354
start := time.Now()
5455
err := h(commandContext)
55-
zlog.Log.Debugw("executed command %s", zlog.F{"time": time.Since(start)}, name)
56+
logging.Debugw("executed command %s", logging.F{"time": time.Since(start)}, name)
5657

5758
if err != nil {
5859
commandContext.Reply.QuickEmbed(reply.ErrorEmbed(err.Error()))
@@ -64,6 +65,6 @@ func RegisterCommands(r *cmdroute.Router, st *state.State, q *db.Queries, c *las
6465
}
6566

6667
func Sync(st *state.State) error {
67-
defer zlog.Log.Infow("synced commands", zlog.F{"count": len(allCommands)})
68+
defer logging.Infow("synced commands", logging.F{"count": len(allCommands)})
6869
return cmdroute.OverwriteCommands(st, allCommands)
6970
}

0 commit comments

Comments
 (0)