cmd/horsebot: allow acting only as api server

This commit is contained in:
2026-06-02 17:26:34 -04:00
parent e3dd37f515
commit 871fd5fdcc

View File

@@ -27,7 +27,6 @@ import (
"zombiezen.com/go/sqlite" "zombiezen.com/go/sqlite"
"zombiezen.com/go/sqlite/sqlitex" "zombiezen.com/go/sqlite/sqlitex"
"git.sunturtle.xyz/zephyr/horse"
"git.sunturtle.xyz/zephyr/horse/mdb" "git.sunturtle.xyz/zephyr/horse/mdb"
) )
@@ -67,6 +66,7 @@ func main() {
} }
slog.SetDefault(slog.New(lh)) slog.SetDefault(slog.New(lh))
if public != "" {
stat, err := os.Stat(public) stat, err := os.Stat(public)
if err != nil { if err != nil {
slog.Error("public", slog.Any("err", err)) slog.Error("public", slog.Any("err", err))
@@ -76,6 +76,7 @@ func main() {
slog.Error("public", slog.String("err", "not a directory")) slog.Error("public", slog.String("err", "not a directory"))
os.Exit(1) os.Exit(1)
} }
}
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
@@ -85,6 +86,8 @@ func main() {
os.Exit(1) os.Exit(1)
} }
var client *bot.Client
if tokenFile != "" {
skills, err := mdb.Skills(ctx, db) skills, err := mdb.Skills(ctx, db)
slog.Info("loaded skills", slog.Int("count", len(skills))) slog.Info("loaded skills", slog.Int("count", len(skills)))
groups, err2 := mdb.SkillGroups(ctx, db) groups, err2 := mdb.SkillGroups(ctx, db)
@@ -96,13 +99,6 @@ func main() {
skillSrv := newSkillServer(skills, groups) skillSrv := newSkillServer(skills, groups)
slog.Info("skill server ready") slog.Info("skill server ready")
token, err := os.ReadFile(tokenFile)
if err != nil {
slog.Error("reading token", slog.Any("err", err))
os.Exit(1)
}
token = bytes.TrimSuffix(token, []byte{'\n'})
r := handler.New() r := handler.New()
r.DefaultContext(func() context.Context { return ctx }) r.DefaultContext(func() context.Context { return ctx })
r.Use(middleware.Go) r.Use(middleware.Go)
@@ -113,15 +109,25 @@ func main() {
r.SelectMenuComponent("/swap", skillSrv.menu) r.SelectMenuComponent("/swap", skillSrv.menu)
r.ButtonComponent("/swap/{id}", skillSrv.button) r.ButtonComponent("/swap/{id}", skillSrv.button)
}) })
slog.Info("connect", slog.String("disgo", disgo.Version)) slog.Info("connect", slog.String("disgo", disgo.Version))
client, err := disgo.New(string(token), bot.WithDefaultGateway(), bot.WithEventListeners(r)) token, err := os.ReadFile(tokenFile)
if err != nil {
slog.Error("reading token", slog.Any("err", err))
os.Exit(1)
}
token = bytes.TrimSuffix(token, []byte{'\n'})
client, err = disgo.New(string(token), bot.WithDefaultGateway(), bot.WithEventListeners(r))
if err != nil { if err != nil {
slog.Error("building bot", slog.Any("err", err)) slog.Error("building bot", slog.Any("err", err))
os.Exit(1) os.Exit(1)
} }
}
mux := http.NewServeMux() mux := http.NewServeMux()
if public != "" {
mux.Handle("GET /", httpmiddle.Compress(5)(http.FileServerFS(os.DirFS(public)))) mux.Handle("GET /", httpmiddle.Compress(5)(http.FileServerFS(os.DirFS(public))))
}
mux.Handle("GET /api/global/affinity", httpmiddle.Compress(5)(dataroute(ctx, db, mdb.AffinitySummary))) mux.Handle("GET /api/global/affinity", httpmiddle.Compress(5)(dataroute(ctx, db, mdb.AffinitySummary)))
mux.Handle("GET /api/global/character", httpmiddle.Compress(5)(dataroute(ctx, db, mdb.Characters))) mux.Handle("GET /api/global/character", httpmiddle.Compress(5)(dataroute(ctx, db, mdb.Characters)))
mux.Handle("GET /api/global/conversation", httpmiddle.Compress(5)(dataroute(ctx, db, mdb.Conversations))) mux.Handle("GET /api/global/conversation", httpmiddle.Compress(5)(dataroute(ctx, db, mdb.Conversations)))
@@ -162,6 +168,7 @@ func main() {
slog.Error("HTTP server closed", slog.Any("err", err)) slog.Error("HTTP server closed", slog.Any("err", err))
}() }()
if client != nil {
if err := handler.SyncCommands(client, commands, nil, rest.WithCtx(ctx)); err != nil { if err := handler.SyncCommands(client, commands, nil, rest.WithCtx(ctx)); err != nil {
slog.Error("syncing commands", slog.Any("err", err)) slog.Error("syncing commands", slog.Any("err", err))
os.Exit(1) os.Exit(1)
@@ -172,13 +179,17 @@ func main() {
slog.Error("starting gateway", slog.Any("err", err)) slog.Error("starting gateway", slog.Any("err", err))
stop() stop()
} }
}
slog.Info("ready") slog.Info("ready")
<-ctx.Done() <-ctx.Done()
stop() stop()
ctx, stop = context.WithTimeout(context.Background(), 5*time.Second) ctx, stop = context.WithTimeout(context.Background(), 5*time.Second)
defer stop() defer stop()
if client != nil {
client.Close(ctx) client.Close(ctx)
}
if err := srv.Shutdown(ctx); err != nil { if err := srv.Shutdown(ctx); err != nil {
slog.Error("HTTP API shutdown", slog.Any("err", err)) slog.Error("HTTP API shutdown", slog.Any("err", err))
os.Exit(1) os.Exit(1)
@@ -204,30 +215,6 @@ var commands = []discord.ApplicationCommandCreate{
}, },
} }
func loadSkills(file string) ([]horse.Skill, error) {
b, err := os.ReadFile(file)
if err != nil {
return nil, err
}
var skills []horse.Skill
if err := json.Unmarshal(b, &skills); err != nil {
return nil, err
}
return skills, nil
}
func loadSkillGroups(file string) ([]horse.SkillGroup, error) {
b, err := os.ReadFile(file)
if err != nil {
return nil, err
}
var groups []horse.SkillGroup
if err := json.Unmarshal(b, &groups); err != nil {
return nil, err
}
return groups, nil
}
func dataroute[T any](ctx context.Context, db *sqlitex.Pool, f func(context.Context, *sqlitex.Pool) ([]T, error)) http.HandlerFunc { func dataroute[T any](ctx context.Context, db *sqlitex.Pool, f func(context.Context, *sqlitex.Pool) ([]T, error)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
data, err := f(ctx, db) data, err := f(ctx, db)