discrawl/internal/cli/messages.go
2026-05-05 10:07:56 +01:00

139 lines
3.4 KiB
Go

package cli
import (
"errors"
"flag"
"fmt"
"io"
"strings"
"time"
"github.com/openclaw/discrawl/internal/store"
)
const defaultMessageLimit = 200
func (r *runtime) runMessages(args []string) error {
fs := flag.NewFlagSet("messages", flag.ContinueOnError)
fs.SetOutput(io.Discard)
channel := fs.String("channel", "", "")
author := fs.String("author", "", "")
hours := fs.Int("hours", 0, "")
days := fs.Int("days", 0, "")
since := fs.String("since", "", "")
before := fs.String("before", "", "")
limit := fs.Int("limit", defaultMessageLimit, "")
last := fs.Int("last", 0, "")
all := fs.Bool("all", false, "")
syncNow := fs.Bool("sync", false, "")
includeEmpty := fs.Bool("include-empty", false, "")
dm := fs.Bool("dm", false, "")
guildsFlag := fs.String("guilds", "", "")
guildFlag := fs.String("guild", "", "")
if err := fs.Parse(args); err != nil {
return usageErr(err)
}
if fs.NArg() != 0 {
return usageErr(errors.New("messages takes flags only"))
}
if *hours < 0 {
return usageErr(errors.New("--hours must be >= 0"))
}
if *days < 0 {
return usageErr(errors.New("--days must be >= 0"))
}
if countNonZero(*hours > 0, *days > 0, strings.TrimSpace(*since) != "") > 1 {
return usageErr(errors.New("use only one of --hours, --days, or --since"))
}
if *limit < 0 {
return usageErr(errors.New("--limit must be >= 0"))
}
if *last < 0 {
return usageErr(errors.New("--last must be >= 0"))
}
limitSet := flagPassed(fs, "limit")
if *all && *last > 0 {
return usageErr(errors.New("use either --all or --last"))
}
if limitSet && *last > 0 {
return usageErr(errors.New("use either --limit or --last"))
}
if *last > 0 {
*limit = 0
}
var sinceTime time.Time
var beforeTime time.Time
var err error
if *hours > 0 {
now := time.Now().UTC()
if r.now != nil {
now = r.now().UTC()
}
sinceTime = now.Add(-time.Duration(*hours) * time.Hour)
}
if *days > 0 {
now := time.Now().UTC()
if r.now != nil {
now = r.now().UTC()
}
sinceTime = now.Add(-time.Duration(*days) * 24 * time.Hour)
}
if strings.TrimSpace(*since) != "" {
sinceTime, err = time.Parse(time.RFC3339, *since)
if err != nil {
return usageErr(fmt.Errorf("invalid --since: %w", err))
}
}
if strings.TrimSpace(*before) != "" {
beforeTime, err = time.Parse(time.RFC3339, *before)
if err != nil {
return usageErr(fmt.Errorf("invalid --before: %w", err))
}
}
guildIDs, err := directMessageGuildScope(*dm, *guildFlag, *guildsFlag)
if err != nil {
return usageErr(err)
}
if *dm && *syncNow {
return usageErr(errors.New("messages --sync is not supported with --dm; run wiretap or sync --source wiretap first"))
}
if strings.TrimSpace(*channel) == "" && strings.TrimSpace(*author) == "" && sinceTime.IsZero() && beforeTime.IsZero() && len(guildIDs) == 0 {
return usageErr(errors.New("messages needs at least one filter"))
}
if *all {
*limit = 0
}
if *syncNow {
if err := r.syncMessagesQuery(*channel, *guildFlag, *guildsFlag); err != nil {
return err
}
}
rows, err := r.store.ListMessages(r.ctx, store.MessageListOptions{
GuildIDs: guildIDs,
Channel: *channel,
Author: *author,
Since: sinceTime,
Before: beforeTime,
Limit: *limit,
Last: *last,
IncludeEmpty: *includeEmpty,
})
if err != nil {
return err
}
return r.print(rows)
}
func countNonZero(values ...bool) int {
count := 0
for _, value := range values {
if value {
count++
}
}
return count
}