feat: MessageSender

This commit is contained in:
Siwoo Jeon 2025-05-17 15:09:42 +09:00
parent 24254f0b6d
commit 63a820f946
Signed by: migan
GPG key ID: 036E9A8C5E8E48DA
11 changed files with 521 additions and 491 deletions

View file

@ -29,7 +29,7 @@ const (
userLearn userLearn
) )
var dataLengthCh chan chStruct = make(chan chStruct) // var dataLengthCh chan chStruct = make(chan chStruct)
var dataLengthWg sync.WaitGroup var dataLengthWg sync.WaitGroup
var DataLengthCommand *Command = &Command{ var DataLengthCommand *Command = &Command{
@ -44,14 +44,15 @@ var DataLengthCommand *Command = &Command{
}, },
Category: General, Category: General,
MessageRun: func(ctx *MsgContext) { MessageRun: func(ctx *MsgContext) {
dataLengthRun(ctx.Session, ctx.Msg) dataLengthRun(ctx.Msg, ctx.Msg.Author.Username, ctx.Msg.Author.ID)
}, },
ChatInputRun: func(ctx *ChatInputContext) { ChatInputRun: func(ctx *ChatInputContext) {
dataLengthRun(ctx.Session, ctx.Inter) ctx.Inter.DeferReply(true)
dataLengthRun(ctx.Inter, ctx.Inter.Member.User.Username, ctx.Inter.Member.User.ID)
}, },
} }
func getLength(dType dataType, coll *mongo.Collection, filter bson.D) { func getLength(ch chan chStruct, dType dataType, coll *mongo.Collection, filter bson.D) {
defer dataLengthWg.Done() defer dataLengthWg.Done()
var err error var err error
var cur *mongo.Cursor var cur *mongo.Cursor
@ -65,33 +66,21 @@ func getLength(dType dataType, coll *mongo.Collection, filter bson.D) {
defer cur.Close(context.TODO()) defer cur.Close(context.TODO())
cur.All(context.TODO(), &data) cur.All(context.TODO(), &data)
dataLengthCh <- chStruct{name: dType, length: len(data)} ch <- chStruct{name: dType, length: len(data)}
} }
func dataLengthRun(s *discordgo.Session, m any) { func dataLengthRun(m any, username, userId string) {
var username, userId, channelId string ch := make(chan chStruct)
var textLength, var textLength,
muffinLength, muffinLength,
nsfwLength, nsfwLength,
learnLength, learnLength,
userLearnLength int userLearnLength int
switch m := m.(type) {
case *discordgo.MessageCreate:
username = m.Author.Username
userId = m.Author.ID
channelId = m.ChannelID
case *utils.InteractionCreate:
m.DeferReply(true)
username = m.Member.User.Username
userId = m.Member.User.ID
channelId = m.ChannelID
}
dataLengthWg.Add(5) dataLengthWg.Add(5)
go getLength(text, databases.Database.Texts, bson.D{{}}) go getLength(ch, text, databases.Database.Texts, bson.D{{}})
go getLength(muffin, databases.Database.Texts, bson.D{{Key: "persona", Value: "muffin"}}) go getLength(ch, muffin, databases.Database.Texts, bson.D{{Key: "persona", Value: "muffin"}})
go getLength(nsfw, databases.Database.Texts, bson.D{ go getLength(ch, nsfw, databases.Database.Texts, bson.D{
{ {
Key: "persona", Key: "persona",
Value: bson.M{ Value: bson.M{
@ -99,15 +88,15 @@ func dataLengthRun(s *discordgo.Session, m any) {
}, },
}, },
}) })
go getLength(learn, databases.Database.Learns, bson.D{{}}) go getLength(ch, learn, databases.Database.Learns, bson.D{{}})
go getLength(userLearn, databases.Database.Learns, bson.D{{Key: "user_id", Value: userId}}) go getLength(ch, userLearn, databases.Database.Learns, bson.D{{Key: "user_id", Value: userId}})
go func() { go func() {
dataLengthWg.Wait() dataLengthWg.Wait()
close(dataLengthCh) close(ch)
}() }()
for resp := range dataLengthCh { for resp := range ch {
switch dataType(resp.name) { switch dataType(resp.name) {
case text: case text:
textLength = resp.length textLength = resp.length
@ -126,44 +115,38 @@ func dataLengthRun(s *discordgo.Session, m any) {
// 나중에 djs처럼 Embed 만들어 주는 함수 만들어야겠다 // 나중에 djs처럼 Embed 만들어 주는 함수 만들어야겠다
// 지금은 임시방편 // 지금은 임시방편
embed := &discordgo.MessageEmbed{ utils.NewMessageSender(m).
Title: "저장된 데이터량", AddEmbed(&discordgo.MessageEmbed{
Description: fmt.Sprintf("총합: %s개", utils.InlineCode(strconv.Itoa(sum))), Title: "저장된 데이터량",
Color: utils.EmbedDefault, Description: fmt.Sprintf("총합: %s개", utils.InlineCode(strconv.Itoa(sum))),
Fields: []*discordgo.MessageEmbedField{ Color: utils.EmbedDefault,
{ Fields: []*discordgo.MessageEmbedField{
Name: "총 채팅 데이터량", {
Value: utils.InlineCode(strconv.Itoa(textLength)) + "개", Name: "총 채팅 데이터량",
Inline: true, Value: utils.InlineCode(strconv.Itoa(textLength)) + "개",
Inline: true,
},
{
Name: "총 지식 데이터량",
Value: utils.InlineCode(strconv.Itoa(learnLength)) + "개",
Inline: true,
},
{
Name: "머핀 데이터량",
Value: utils.InlineCode(strconv.Itoa(muffinLength)) + "개",
},
{
Name: "nsfw 데이터량",
Value: utils.InlineCode(strconv.Itoa(nsfwLength)) + "개",
Inline: true,
},
{
Name: fmt.Sprintf("%s님이 가르쳐준 데이터량", username),
Value: utils.InlineCode(strconv.Itoa(userLearnLength)) + "개",
Inline: true,
},
}, },
{ }).
Name: "총 지식 데이터량", SetReply(true).
Value: utils.InlineCode(strconv.Itoa(learnLength)) + "개", Send()
Inline: true,
},
{
Name: "머핀 데이터량",
Value: utils.InlineCode(strconv.Itoa(muffinLength)) + "개",
},
{
Name: "nsfw 데이터량",
Value: utils.InlineCode(strconv.Itoa(nsfwLength)) + "개",
Inline: true,
},
{
Name: fmt.Sprintf("%s님이 가르쳐준 데이터량", username),
Value: utils.InlineCode(strconv.Itoa(userLearnLength)) + "개",
Inline: true,
},
},
}
switch m := m.(type) {
case *discordgo.MessageCreate:
s.ChannelMessageSendEmbedReply(channelId, embed, m.Reference())
case *utils.InteractionCreate:
m.EditReply(&discordgo.WebhookEdit{
Embeds: &[]*discordgo.MessageEmbed{embed},
})
}
} }

View file

@ -31,85 +31,71 @@ var DeleteLearnedDataCommand *Command = &Command{
}, },
Category: Chatting, Category: Chatting,
MessageRun: func(ctx *MsgContext) { MessageRun: func(ctx *MsgContext) {
deleteLearnedDataRun(ctx.Command, ctx.Session, ctx.Msg, ctx.Args) command := strings.Join(*ctx.Args, " ")
if command == "" {
utils.NewMessageSender(ctx.Msg).
AddEmbed(&discordgo.MessageEmbed{
Title: "❌ 오류",
Description: "올바르지 않ㅇ은 용법이에요.",
Fields: []*discordgo.MessageEmbedField{
{
Name: "사용법",
Value: utils.InlineCode(ctx.Command.DetailedDescription.Usage),
},
{
Name: "예시",
Value: utils.CodeBlock("md", strings.Join(addPrefix(ctx.Command.DetailedDescription.Examples), "\n")),
},
},
Color: utils.EmbedFail,
}).
SetReply(true).
Send()
}
deleteLearnedDataRun(ctx.Msg, strings.Join(*ctx.Args, " "), ctx.Msg.Author.ID)
}, },
ChatInputRun: func(ctx *ChatInputContext) { ChatInputRun: func(ctx *ChatInputContext) {
deleteLearnedDataRun(ctx.Command, ctx.Session, ctx.Inter, nil) ctx.Inter.DeferReply(true)
var command string
if opt, ok := ctx.Inter.Options["단어"]; ok {
command = opt.StringValue()
}
deleteLearnedDataRun(ctx.Inter, command, ctx.Inter.Member.User.ID)
}, },
} }
func deleteLearnedDataRun(c *Command, s *discordgo.Session, m any, args *[]string) { func deleteLearnedDataRun(m any, command, userId string) {
var command, userId, description string var description string
var data []databases.Learn var data []databases.Learn
var options []discordgo.SelectMenuOption var options []discordgo.SelectMenuOption
switch m := m.(type) {
case *discordgo.MessageCreate:
command = strings.Join(*args, " ")
userId = m.Author.ID
if command == "" {
s.ChannelMessageSendEmbedReply(m.ChannelID, &discordgo.MessageEmbed{
Title: "❌ 오류",
Description: "올바르지 않ㅇ은 용법이에요.",
Fields: []*discordgo.MessageEmbedField{
{
Name: "사용법",
Value: utils.InlineCode(c.DetailedDescription.Usage),
},
{
Name: "예시",
Value: utils.CodeBlock("md", strings.Join(addPrefix(c.DetailedDescription.Examples), "\n")),
},
},
Color: utils.EmbedFail,
}, m.Reference())
}
case *utils.InteractionCreate:
m.DeferReply(true)
if opt, ok := m.Options["단어"]; ok {
command = opt.StringValue()
}
userId = m.Member.User.ID
}
cur, err := databases.Database.Learns.Find(context.TODO(), bson.M{"user_id": userId, "command": command}) cur, err := databases.Database.Learns.Find(context.TODO(), bson.M{"user_id": userId, "command": command})
if err != nil { if err != nil {
embed := &discordgo.MessageEmbed{ utils.NewMessageSender(m).
Title: "❌ 오류", AddEmbed(&discordgo.MessageEmbed{
Description: "데이터를 가져오는데 실패했어요.", Title: "❌ 오류",
Color: utils.EmbedFail, Description: "데이터를 가져오는데 실패했어요.",
} Color: utils.EmbedFail,
}).
switch m := m.(type) { SetReply(true).
case *discordgo.MessageCreate: Send()
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference())
case *utils.InteractionCreate:
m.EditReply(&discordgo.WebhookEdit{
Embeds: &[]*discordgo.MessageEmbed{embed},
})
}
return return
} }
cur.All(context.TODO(), &data) cur.All(context.TODO(), &data)
if len(data) < 1 { if len(data) < 1 {
embed := &discordgo.MessageEmbed{ utils.NewMessageSender(m).
Title: "❌ 오류", AddEmbed(&discordgo.MessageEmbed{
Description: "해당 하는 지식ㅇ을 찾을 수 없어요.", Title: "❌ 오류",
Color: utils.EmbedFail, Description: "해당 하는 지식ㅇ을 찾을 수 없어요.",
} Color: utils.EmbedFail,
}).
switch m := m.(type) { SetReply(true).
case *discordgo.MessageCreate: Send()
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference())
case *utils.InteractionCreate:
m.EditReply(&discordgo.WebhookEdit{
Embeds: &[]*discordgo.MessageEmbed{embed},
})
}
return return
} }
@ -124,14 +110,13 @@ func deleteLearnedDataRun(c *Command, s *discordgo.Session, m any, args *[]strin
description += fmt.Sprintf("%d. %s\n", i+1, data.Result) description += fmt.Sprintf("%d. %s\n", i+1, data.Result)
} }
embed := &discordgo.MessageEmbed{ utils.NewMessageSender(m).
Title: fmt.Sprintf("%s 삭제", command), AddEmbed(&discordgo.MessageEmbed{
Description: utils.CodeBlock("md", fmt.Sprintf("# %s에 대한 대답 중 하나를 선ㅌ택하여 삭제해주세요.\n%s", command, description)), Title: fmt.Sprintf("%s 삭제", command),
Color: utils.EmbedDefault, Description: utils.CodeBlock("md", fmt.Sprintf("# %s에 대한 대답 중 하나를 선ㅌ택하여 삭제해주세요.\n%s", command, description)),
} Color: utils.EmbedDefault,
}).
components := []discordgo.MessageComponent{ AddComponent(discordgo.ActionsRow{
discordgo.ActionsRow{
Components: []discordgo.MessageComponent{ Components: []discordgo.MessageComponent{
discordgo.SelectMenu{ discordgo.SelectMenu{
MenuType: discordgo.StringSelectMenu, MenuType: discordgo.StringSelectMenu,
@ -140,8 +125,8 @@ func deleteLearnedDataRun(c *Command, s *discordgo.Session, m any, args *[]strin
Placeholder: "ㅈ지울 응답을 선택해주세요.", Placeholder: "ㅈ지울 응답을 선택해주세요.",
}, },
}, },
}, }).
discordgo.ActionsRow{ AddComponent(discordgo.ActionsRow{
Components: []discordgo.MessageComponent{ Components: []discordgo.MessageComponent{
discordgo.Button{ discordgo.Button{
CustomID: utils.MakeDeleteLearnedDataCancel(userId), CustomID: utils.MakeDeleteLearnedDataCancel(userId),
@ -150,20 +135,6 @@ func deleteLearnedDataRun(c *Command, s *discordgo.Session, m any, args *[]strin
Disabled: false, Disabled: false,
}, },
}, },
}, }).
} Send()
switch m := m.(type) {
case *discordgo.MessageCreate:
s.ChannelMessageSendComplex(m.ChannelID, &discordgo.MessageSend{
Embeds: []*discordgo.MessageEmbed{embed},
Components: components,
Reference: m.Reference(),
})
case *utils.InteractionCreate:
m.EditReply(&discordgo.WebhookEdit{
Embeds: &[]*discordgo.MessageEmbed{embed},
Components: &components,
})
}
} }

View file

@ -39,20 +39,17 @@ type DiscommandStruct struct {
} }
type MsgContext struct { type MsgContext struct {
Session *discordgo.Session Msg *utils.MessageCreate
Msg *discordgo.MessageCreate
Args *[]string Args *[]string
Command *Command Command *Command
} }
type ChatInputContext struct { type ChatInputContext struct {
Session *discordgo.Session
Inter *utils.InteractionCreate Inter *utils.InteractionCreate
Command *Command Command *Command
} }
type ComponentContext struct { type ComponentContext struct {
Session *discordgo.Session
Inter *utils.InteractionCreate Inter *utils.InteractionCreate
Component *Component Component *Component
} }
@ -118,13 +115,16 @@ func (d *DiscommandStruct) LoadModal(m *Modal) {
func (d *DiscommandStruct) MessageRun(name string, s *discordgo.Session, m *discordgo.MessageCreate, args []string) { func (d *DiscommandStruct) MessageRun(name string, s *discordgo.Session, m *discordgo.MessageCreate, args []string) {
if command, ok := d.Commands[name]; ok { if command, ok := d.Commands[name]; ok {
command.MessageRun(&MsgContext{s, m, &args, command}) command.MessageRun(&MsgContext{&utils.MessageCreate{
MessageCreate: m,
Session: s,
}, &args, command})
} }
} }
func (d *DiscommandStruct) ChatInputRun(name string, s *discordgo.Session, i *discordgo.InteractionCreate) { func (d *DiscommandStruct) ChatInputRun(name string, s *discordgo.Session, i *discordgo.InteractionCreate) {
if command, ok := d.Commands[name]; ok { if command, ok := d.Commands[name]; ok {
command.ChatInputRun(&ChatInputContext{s, &utils.InteractionCreate{ command.ChatInputRun(&ChatInputContext{&utils.InteractionCreate{
InteractionCreate: i, InteractionCreate: i,
Session: s, Session: s,
Options: utils.GetInteractionOptions(i), Options: utils.GetInteractionOptions(i),
@ -134,7 +134,6 @@ func (d *DiscommandStruct) ChatInputRun(name string, s *discordgo.Session, i *di
func (d *DiscommandStruct) ComponentRun(s *discordgo.Session, i *discordgo.InteractionCreate) { func (d *DiscommandStruct) ComponentRun(s *discordgo.Session, i *discordgo.InteractionCreate) {
data := &ComponentContext{ data := &ComponentContext{
Session: s,
Inter: &utils.InteractionCreate{ Inter: &utils.InteractionCreate{
InteractionCreate: i, InteractionCreate: i,
Session: s, Session: s,

View file

@ -30,10 +30,16 @@ var HelpCommand *Command = &Command{
}, },
Category: General, Category: General,
MessageRun: func(ctx *MsgContext) { MessageRun: func(ctx *MsgContext) {
helpRun(ctx.Session, ctx.Msg, ctx.Args) helpRun(ctx.Msg.Session, ctx.Msg, strings.Join(*ctx.Args, " "))
}, },
ChatInputRun: func(ctx *ChatInputContext) { ChatInputRun: func(ctx *ChatInputContext) {
helpRun(ctx.Session, ctx.Inter, nil) var command string
if opt, ok := ctx.Inter.Options["명령어"]; ok {
command = opt.StringValue()
}
helpRun(ctx.Inter.Session, ctx.Inter, command)
}, },
} }
@ -47,8 +53,7 @@ func getCommandsByCategory(d *DiscommandStruct, category Category) []string {
return commands return commands
} }
func helpRun(s *discordgo.Session, m any, args *[]string) { func helpRun(s *discordgo.Session, m any, commandName string) {
var commandName string
embed := &discordgo.MessageEmbed{ embed := &discordgo.MessageEmbed{
Color: utils.EmbedDefault, Color: utils.EmbedDefault,
Footer: &discordgo.MessageEmbedFooter{ Footer: &discordgo.MessageEmbedFooter{
@ -59,16 +64,7 @@ func helpRun(s *discordgo.Session, m any, args *[]string) {
}, },
} }
switch m := m.(type) { commandName = Discommand.Aliases[commandName]
case *discordgo.MessageCreate:
commandName = Discommand.Aliases[strings.Join(*args, " ")]
case *utils.InteractionCreate:
if opt, ok := m.Options["명령어"]; ok {
commandName = opt.StringValue()
} else {
commandName = ""
}
}
if commandName == "" || Discommand.Commands[commandName] == nil { if commandName == "" || Discommand.Commands[commandName] == nil {
embed.Title = fmt.Sprintf("%s의 도움말", s.State.User.Username) embed.Title = fmt.Sprintf("%s의 도움말", s.State.User.Username)
@ -79,14 +75,7 @@ func helpRun(s *discordgo.Session, m any, args *[]string) {
strings.Join(getCommandsByCategory(Discommand, Chatting), "\n")), strings.Join(getCommandsByCategory(Discommand, Chatting), "\n")),
) )
switch m := m.(type) { utils.NewMessageSender(m).AddEmbed(embed).SetReply(true).Send()
case *discordgo.MessageCreate:
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference())
case *utils.InteractionCreate:
m.Reply(&discordgo.InteractionResponseData{
Embeds: []*discordgo.MessageEmbed{embed},
})
}
return return
} }
@ -137,12 +126,5 @@ func helpRun(s *discordgo.Session, m any, args *[]string) {
}) })
} }
switch m := m.(type) { utils.NewMessageSender(m).AddEmbed(embed).SetReply(true).Send()
case *discordgo.MessageCreate:
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference())
case *utils.InteractionCreate:
m.Reply(&discordgo.InteractionResponseData{
Embeds: []*discordgo.MessageEmbed{embed},
})
}
} }

View file

@ -19,53 +19,56 @@ var InformationCommand *Command = &Command{
}, },
Category: General, Category: General,
MessageRun: func(ctx *MsgContext) { MessageRun: func(ctx *MsgContext) {
informationRun(ctx.Session, ctx.Msg) informationRun(ctx.Msg.Session, ctx.Msg)
}, },
ChatInputRun: func(ctx *ChatInputContext) { ChatInputRun: func(ctx *ChatInputContext) {
informationRun(ctx.Session, ctx.Inter) informationRun(ctx.Inter.Session, ctx.Inter)
}, },
} }
func informationRun(s *discordgo.Session, m any) { func informationRun(s *discordgo.Session, m any) {
owner, _ := s.User(configs.Config.Bot.OwnerId) owner, _ := s.User(configs.Config.Bot.OwnerId)
embed := &discordgo.MessageEmbed{ utils.NewMessageSender(m).
Title: fmt.Sprintf("%s의 정보", s.State.User.Username), AddEmbed(&discordgo.MessageEmbed{
Fields: []*discordgo.MessageEmbedField{ Title: fmt.Sprintf("%s의 정보", s.State.User.Username),
{ Fields: []*discordgo.MessageEmbedField{
Name: "운영 체제", {
Value: utils.InlineCode(fmt.Sprintf("%s %s", runtime.GOARCH, runtime.GOOS)), Name: "운영 체제",
Value: utils.InlineCode(fmt.Sprintf("%s %s", runtime.GOARCH, runtime.GOOS)),
},
{
Name: "제작자",
Value: utils.InlineCode(owner.Username),
},
{
Name: "버전",
Value: utils.InlineCode(configs.MUFFIN_VERSION),
},
{
Name: "최근에 업데이트된 날짜",
Value: utils.Time(configs.UpdatedAt, utils.RelativeTime),
Inline: true,
},
{
Name: "시작한 시각",
Value: utils.Time(configs.StartedAt, utils.RelativeTime),
Inline: true,
},
}, },
{ Color: utils.EmbedDefault,
Name: "제작자", Thumbnail: &discordgo.MessageEmbedThumbnail{
Value: utils.InlineCode(owner.Username), URL: s.State.User.AvatarURL("512"),
}, },
{ }).
Name: "버전", SetReply(true).
Value: utils.InlineCode(configs.MUFFIN_VERSION), Send()
},
{
Name: "최근에 업데이트된 날짜",
Value: utils.Time(configs.UpdatedAt, utils.RelativeTime),
Inline: true,
},
{
Name: "시작한 시각",
Value: utils.Time(configs.StartedAt, utils.RelativeTime),
Inline: true,
},
},
Color: utils.EmbedDefault,
Thumbnail: &discordgo.MessageEmbedThumbnail{
URL: s.State.User.AvatarURL("512"),
},
}
switch m := m.(type) { // switch m := m.(type) {
case *discordgo.MessageCreate: // case *discordgo.MessageCreate:
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference()) // s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference())
case *utils.InteractionCreate: // case *utils.InteractionCreate:
m.Reply(&discordgo.InteractionResponseData{ // m.Reply(&discordgo.InteractionResponseData{
Embeds: []*discordgo.MessageEmbed{embed}, // Embeds: []*discordgo.MessageEmbed{embed},
}) // })
} // }
} }

View file

@ -3,6 +3,7 @@ package commands
import ( import (
"context" "context"
"fmt" "fmt"
"log"
"strings" "strings"
"time" "time"
@ -57,10 +58,50 @@ var LearnCommand *Command = &Command{
}, },
Category: Chatting, Category: Chatting,
MessageRun: func(ctx *MsgContext) { MessageRun: func(ctx *MsgContext) {
learnRun(ctx.Command, ctx.Session, ctx.Msg, ctx.Args) if len(*ctx.Args) < 2 {
utils.NewMessageSender(ctx.Msg).
AddEmbed(&discordgo.MessageEmbed{
Title: "❌ 오류",
Description: "올바르지 않ㅇ은 용법이에요.",
Fields: []*discordgo.MessageEmbedField{
{
Name: "사용법",
Value: utils.InlineCode(ctx.Command.DetailedDescription.Usage),
Inline: true,
},
{
Name: "사용 가능한 인자",
Value: learnArguments,
Inline: true,
},
{
Name: "예시",
Value: utils.CodeBlock("md", strings.Join(addPrefix(ctx.Command.DetailedDescription.Examples), "\n")),
},
},
Color: utils.EmbedFail,
}).
SetReply(true).
Send()
return
}
learnRun(ctx.Msg, ctx.Msg.Author.ID, strings.ReplaceAll((*ctx.Args)[0], "_", " "), strings.ReplaceAll((*ctx.Args)[1], "_", " "))
}, },
ChatInputRun: func(ctx *ChatInputContext) { ChatInputRun: func(ctx *ChatInputContext) {
learnRun(ctx.Command, ctx.Session, ctx.Inter, nil) ctx.Inter.DeferReply(true)
var command, result string
if opt, ok := ctx.Inter.Options["단어"]; ok {
command = opt.StringValue()
}
if opt, ok := ctx.Inter.Options["대답"]; ok {
result = opt.StringValue()
}
learnRun(ctx.Inter, ctx.Inter.Member.User.ID, command, result)
}, },
} }
@ -71,54 +112,8 @@ func addPrefix(arr []string) (newArr []string) {
return return
} }
func learnRun(c *Command, s *discordgo.Session, m any, args *[]string) { func learnRun(m any, userId, command, result string) {
var userId, command, result string
igCommands := []string{} igCommands := []string{}
switch m := m.(type) {
case *discordgo.MessageCreate:
userId = m.Author.ID
if len(*args) < 2 {
s.ChannelMessageSendEmbedReply(m.ChannelID, &discordgo.MessageEmbed{
Title: "❌ 오류",
Description: "올바르지 않ㅇ은 용법이에요.",
Fields: []*discordgo.MessageEmbedField{
{
Name: "사용법",
Value: utils.InlineCode(c.DetailedDescription.Usage),
Inline: true,
},
{
Name: "사용 가능한 인자",
Value: learnArguments,
Inline: true,
},
{
Name: "예시",
Value: utils.CodeBlock("md", strings.Join(addPrefix(c.DetailedDescription.Examples), "\n")),
},
},
Color: utils.EmbedFail,
}, m.Reference())
return
}
command = strings.ReplaceAll((*args)[0], "_", " ")
result = strings.ReplaceAll((*args)[1], "_", " ")
case *utils.InteractionCreate:
m.DeferReply(true)
userId = m.Member.User.ID
if opt, ok := m.Options["단어"]; ok {
command = opt.StringValue()
}
if opt, ok := m.Options["대답"]; ok {
result = opt.StringValue()
}
}
for _, command := range Discommand.Commands { for _, command := range Discommand.Commands {
igCommands = append(igCommands, command.Name) igCommands = append(igCommands, command.Name)
@ -136,40 +131,31 @@ func learnRun(c *Command, s *discordgo.Session, m any, args *[]string) {
for _, ig := range ignores { for _, ig := range ignores {
if strings.Contains(command, ig) { if strings.Contains(command, ig) {
embed := &discordgo.MessageEmbed{ utils.NewMessageSender(m).
Title: "❌ 오류", AddEmbed(
Description: "해ㄷ당 단어는 배우기 껄끄ㄹ럽네요.", &discordgo.MessageEmbed{
Color: utils.EmbedFail, Title: "❌ 오류",
} Description: "해ㄷ당 단어는 배우기 껄끄ㄹ럽네요.",
Color: utils.EmbedFail,
switch m := m.(type) { }).
case *discordgo.MessageCreate: SetReply(true).
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference()) Send()
case *utils.InteractionCreate:
m.EditReply(&discordgo.WebhookEdit{
Embeds: &[]*discordgo.MessageEmbed{embed},
})
}
return return
} }
} }
for _, di := range disallows { for _, di := range disallows {
if strings.Contains(result, di) { if strings.Contains(result, di) {
embed := &discordgo.MessageEmbed{ utils.NewMessageSender(m).
Title: "❌ 오류", AddEmbed(
Description: "해당 단ㅇ어의 대답으로 하기 좀 그렇ㄴ네요.", &discordgo.MessageEmbed{
Color: utils.EmbedFail, Title: "❌ 오류",
} Description: "해당 단ㅇ어의 대답으로 하기 좀 그렇ㄴ네요.",
Color: utils.EmbedFail,
switch m := m.(type) { }).
case *discordgo.MessageCreate: SetReply(true).
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference()) Send()
case *utils.InteractionCreate: return
m.EditReply(&discordgo.WebhookEdit{
Embeds: &[]*discordgo.MessageEmbed{embed},
})
}
} }
} }
@ -180,36 +166,25 @@ func learnRun(c *Command, s *discordgo.Session, m any, args *[]string) {
CreatedAt: time.Now(), CreatedAt: time.Now(),
}) })
if err != nil { if err != nil {
fmt.Println(err) log.Println(err)
embed := &discordgo.MessageEmbed{
Title: "❌ 오류",
Description: "단어를 배우는데 오류가 생겼어요.",
Color: utils.EmbedFail,
}
switch m := m.(type) { utils.NewMessageSender(m).
case *discordgo.MessageCreate: AddEmbed(&discordgo.MessageEmbed{
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference()) Title: "❌ 오류",
case *utils.InteractionCreate: Description: "단어를 배우는데 오류가 생겼어요.",
m.EditReply(&discordgo.WebhookEdit{ Color: utils.EmbedFail,
Embeds: &[]*discordgo.MessageEmbed{embed}, }).
}) SetReply(true).
} Send()
return return
} }
embed := &discordgo.MessageEmbed{ utils.NewMessageSender(m).
Title: "✅ 성공", AddEmbed(&discordgo.MessageEmbed{
Description: fmt.Sprintf("%s 배웠어요.", hangul.GetJosa(command, hangul.EUL_REUL)), Title: "✅ 성공",
Color: utils.EmbedSuccess, Description: fmt.Sprintf("%s 배웠어요.", hangul.GetJosa(command, hangul.EUL_REUL)),
} Color: utils.EmbedSuccess,
}).
switch m := m.(type) { SetReply(true).
case *discordgo.MessageCreate: Send()
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference())
case *utils.InteractionCreate:
m.EditReply(&discordgo.WebhookEdit{
Embeds: &[]*discordgo.MessageEmbed{embed},
})
}
} }

View file

@ -58,10 +58,100 @@ var LearnedDataListCommand *Command = &Command{
}, },
Category: Chatting, Category: Chatting,
MessageRun: func(ctx *MsgContext) { MessageRun: func(ctx *MsgContext) {
learnedDataListRun(ctx.Session, ctx.Msg, ctx.Args) var length int
filter := bson.D{{Key: "user_id", Value: ctx.Msg.Author.ID}}
query := strings.Join(*ctx.Args, " ")
if match := utils.RegexpLearnQueryCommand.FindStringSubmatch(query); match != nil {
filter = append(filter, bson.E{
Key: "command",
Value: bson.M{
"$regex": match[1],
},
})
}
if match := utils.RegexpLearnQueryResult.FindStringSubmatch(query); match != nil {
filter = append(filter, bson.E{
Key: "result",
Value: bson.M{
"$regex": match[1],
},
})
}
if match := utils.RegexpLearnQueryLength.FindStringSubmatch(query); match != nil {
var err error
length, err := strconv.Atoi(match[1])
if err != nil {
utils.NewMessageSender(ctx.Msg).
AddEmbed(&discordgo.MessageEmbed{
Title: "❌ 오류",
Description: "개수의 값은 숫자여야해요.",
Color: utils.EmbedFail,
}).
SetReply(true).
Send()
return
}
if float64(length) < LIST_MIN_VALUE {
utils.NewMessageSender(ctx.Msg).
AddEmbed(&discordgo.MessageEmbed{
Title: "❌ 오류",
Description: fmt.Sprintf("개수의 값은 %d보다 커야해요.", int(LIST_MIN_VALUE)),
Color: utils.EmbedFail,
}).
SetReply(true).
Send()
return
}
if float64(length) > LIST_MAX_VALUE {
utils.NewMessageSender(ctx.Msg).
AddEmbed(&discordgo.MessageEmbed{
Title: "❌ 오류",
Description: fmt.Sprintf("개수의 값은 %d보다 작아야해요.", int(LIST_MAX_VALUE)),
Color: utils.EmbedFail,
}).
SetReply(true).
Send()
return
}
}
learnedDataListRun(ctx.Msg.Session, ctx.Msg, ctx.Msg.Author.GlobalName, ctx.Msg.Author.AvatarURL("512"), filter, length)
}, },
ChatInputRun: func(ctx *ChatInputContext) { ChatInputRun: func(ctx *ChatInputContext) {
learnedDataListRun(ctx.Session, ctx.Inter, nil) ctx.Inter.DeferReply(true)
var length int
filter := bson.D{{Key: "user_id", Value: ctx.Inter.Member.User.ID}}
if opt, ok := ctx.Inter.Options["단어"]; ok {
filter = append(filter, bson.E{
Key: "command",
Value: bson.M{
"$regex": opt.StringValue(),
},
})
}
if opt, ok := ctx.Inter.Options["대답"]; ok {
filter = append(filter, bson.E{
Key: "result",
Value: bson.M{
"$regex": opt.StringValue(),
},
})
}
if opt, ok := ctx.Inter.Options["개수"]; ok {
length = int(opt.IntValue())
}
learnedDataListRun(ctx.Inter.Session, ctx.Inter, ctx.Inter.Member.User.GlobalName, ctx.Inter.Member.User.AvatarURL("512"), filter, length)
}, },
} }
@ -105,134 +195,33 @@ func getDescriptions(data *[]databases.Learn, length int) (descriptions []string
return return
} }
func learnedDataListRun(s *discordgo.Session, m any, args *[]string) { func learnedDataListRun(s *discordgo.Session, m any, globalName, avatarUrl string, filter bson.D, length int) {
var globalName, avatarUrl string
var data []databases.Learn var data []databases.Learn
var filter bson.D
var length int
switch m := m.(type) {
case *discordgo.MessageCreate:
filter = bson.D{{Key: "user_id", Value: m.Author.ID}}
globalName = m.Author.GlobalName
avatarUrl = m.Author.AvatarURL("512")
query := strings.Join(*args, " ")
if match := utils.RegexpLearnQueryCommand.FindStringSubmatch(query); match != nil {
filter = append(filter, bson.E{
Key: "command",
Value: bson.M{
"$regex": match[1],
},
})
}
if match := utils.RegexpLearnQueryResult.FindStringSubmatch(query); match != nil {
filter = append(filter, bson.E{
Key: "result",
Value: bson.M{
"$regex": match[1],
},
})
}
if match := utils.RegexpLearnQueryLength.FindStringSubmatch(query); match != nil {
var err error
length, err = strconv.Atoi(match[1])
if err != nil {
s.ChannelMessageSendEmbedReply(m.ChannelID, &discordgo.MessageEmbed{
Title: "❌ 오류",
Description: "개수의 값은 숫자여야해요.",
Color: utils.EmbedFail,
}, m.Reference())
return
}
if float64(length) < LIST_MIN_VALUE {
s.ChannelMessageSendEmbedReply(m.ChannelID, &discordgo.MessageEmbed{
Title: "❌ 오류",
Description: fmt.Sprintf("개수의 값은 %d보다 커야해요.", int(LIST_MIN_VALUE)),
Color: utils.EmbedFail,
}, m.Reference())
return
}
if float64(length) > LIST_MAX_VALUE {
s.ChannelMessageSendEmbedReply(m.ChannelID, &discordgo.MessageEmbed{
Title: "❌ 오류",
Description: fmt.Sprintf("개수의 값은 %d보다 작아야해요.", int(LIST_MAX_VALUE)),
Color: utils.EmbedFail,
}, m.Reference())
return
}
}
case *utils.InteractionCreate:
m.DeferReply(true)
filter = bson.D{{Key: "user_id", Value: m.Member.User.ID}}
globalName = m.Member.User.GlobalName
avatarUrl = m.Member.User.AvatarURL("512")
if opt, ok := m.Options["단어"]; ok {
filter = append(filter, bson.E{
Key: "command",
Value: bson.M{
"$regex": opt.StringValue(),
},
})
}
if opt, ok := m.Options["대답"]; ok {
filter = append(filter, bson.E{
Key: "result",
Value: bson.M{
"$regex": opt.StringValue(),
},
})
}
if opt, ok := m.Options["개수"]; ok {
length = int(opt.IntValue())
}
}
cur, err := databases.Database.Learns.Find(context.TODO(), filter) cur, err := databases.Database.Learns.Find(context.TODO(), filter)
if err != nil { if err != nil {
if err == mongo.ErrNoDocuments { if err == mongo.ErrNoDocuments {
embed := &discordgo.MessageEmbed{ utils.NewMessageSender(m).
Title: "❌ 오류", AddEmbed(&discordgo.MessageEmbed{
Description: "당신은 지식ㅇ을 가르쳐준 적이 없어요!", Title: "❌ 오류",
Color: utils.EmbedFail, Description: "당신은 지식ㅇ을 가르쳐준 적이 없어요!",
} Color: utils.EmbedFail,
}).
switch m := m.(type) { SetReply(true).
case *discordgo.MessageCreate: Send()
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference())
case *utils.InteractionCreate:
m.EditReply(&discordgo.WebhookEdit{
Embeds: &[]*discordgo.MessageEmbed{embed},
})
}
return return
} }
fmt.Println(err) fmt.Println(err)
embed := &discordgo.MessageEmbed{
Title: "❌ 오류",
Description: "데이터를 가져오는데 실패했어요.",
Color: utils.EmbedFail,
}
switch m := m.(type) { utils.NewMessageSender(m).
case *discordgo.MessageCreate: AddEmbed(&discordgo.MessageEmbed{
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference()) Title: "❌ 오류",
case *utils.InteractionCreate: Description: "데이터를 가져오는데 실패했어요.",
m.EditReply(&discordgo.WebhookEdit{ Color: utils.EmbedFail,
Embeds: &[]*discordgo.MessageEmbed{embed}, }).
}) SetReply(true).
} Send()
return return
} }
@ -240,13 +229,14 @@ func learnedDataListRun(s *discordgo.Session, m any, args *[]string) {
cur.All(context.TODO(), &data) cur.All(context.TODO(), &data)
embed := &discordgo.MessageEmbed{ utils.NewPaginationEmbedBuilder(m, getDescriptions(&data, length)).
Title: fmt.Sprintf("%s님이 알려주신 지식", globalName), SetEmbed(&discordgo.MessageEmbed{
Color: utils.EmbedDefault, Title: fmt.Sprintf("%s님이 알려주신 지식", globalName),
Thumbnail: &discordgo.MessageEmbedThumbnail{ Color: utils.EmbedDefault,
URL: avatarUrl, Thumbnail: &discordgo.MessageEmbedThumbnail{
}, URL: avatarUrl,
} },
}).
utils.StartPaginationEmbed(s, m, embed, getDescriptions(&data, length), utils.CodeBlock("md", fmt.Sprintf("# 총 %d개에요.\n", len(data))+"%s")) SetDefaultDesc(utils.CodeBlock("md", fmt.Sprintf("# 총 %d개에요.\n", len(data))+"%s")).
Start()
} }

View file

@ -7,7 +7,7 @@ import (
"git.wh64.net/muffin/goMuffin/utils" "git.wh64.net/muffin/goMuffin/utils"
) )
const MUFFIN_VERSION = "5.1.0-gopher_dev.250517c" const MUFFIN_VERSION = "0.0.0-souffle_canary.250517a-fix_the_spaghetti"
var updatedString string = utils.RegexpDecimals.FindAllStringSubmatch(MUFFIN_VERSION, -1)[3][0] var updatedString string = utils.RegexpDecimals.FindAllStringSubmatch(MUFFIN_VERSION, -1)[3][0]

View file

@ -21,7 +21,9 @@ type InteractionCreate struct {
*discordgo.InteractionCreate *discordgo.InteractionCreate
Session *discordgo.Session Session *discordgo.Session
// NOTE: It's only can ApplicationCommand // NOTE: It's only can ApplicationCommand
Options map[string]*discordgo.ApplicationCommandInteractionDataOption Options map[string]*discordgo.ApplicationCommandInteractionDataOption
Deferred bool
Replied bool
} }
// Reply to this interaction. // Reply to this interaction.
@ -30,6 +32,8 @@ func (i *InteractionCreate) Reply(data *discordgo.InteractionResponseData) {
Type: discordgo.InteractionResponseChannelMessageWithSource, Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: data, Data: data,
}) })
i.Replied = true
} }
// GetInteractionOptions to this interaction. // GetInteractionOptions to this interaction.
@ -55,6 +59,8 @@ func (i *InteractionCreate) DeferReply(ephemeral bool) {
Flags: flags, Flags: flags,
}, },
}) })
i.Deferred = true
} }
// DeferUpdate to this interaction. // DeferUpdate to this interaction.
@ -62,11 +68,15 @@ func (i *InteractionCreate) DeferUpdate() {
i.Session.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ i.Session.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseDeferredMessageUpdate, Type: discordgo.InteractionResponseDeferredMessageUpdate,
}) })
i.Deferred = true
} }
// EditReply to this interaction. // EditReply to this interaction.
func (i *InteractionCreate) EditReply(data *discordgo.WebhookEdit) { func (i *InteractionCreate) EditReply(data *discordgo.WebhookEdit) {
i.Session.InteractionResponseEdit(i.Interaction, data) i.Session.InteractionResponseEdit(i.Interaction, data)
i.Replied = true
} }
// Update to this interaction. // Update to this interaction.
@ -75,6 +85,8 @@ func (i *InteractionCreate) Update(data *discordgo.InteractionResponseData) {
Type: discordgo.InteractionResponseUpdateMessage, Type: discordgo.InteractionResponseUpdateMessage,
Data: data, Data: data,
}) })
i.Replied = true
} }
func (i *InteractionCreate) ShowModal(data *ModalData) error { func (i *InteractionCreate) ShowModal(data *ModalData) error {
@ -115,5 +127,7 @@ func (i *InteractionCreate) ShowModal(data *ModalData) error {
} }
defer resp.Body.Close() defer resp.Body.Close()
i.Replied = true
return nil return nil
} }

97
utils/messageBuilder.go Normal file
View file

@ -0,0 +1,97 @@
package utils
import "github.com/bwmarrin/discordgo"
type MessageCreate struct {
*discordgo.MessageCreate
Session *discordgo.Session
}
type MessageSender struct {
Embeds []*discordgo.MessageEmbed
Content string
Components []discordgo.MessageComponent
Ephemeral bool
Reply bool
m any
}
func NewMessageSender(m any) *MessageSender {
return &MessageSender{m: m}
}
func (s *MessageSender) AddEmbed(embed *discordgo.MessageEmbed) *MessageSender {
s.Embeds = append(s.Embeds, embed)
return s
}
func (s *MessageSender) SetEmbeds(embeds []*discordgo.MessageEmbed) *MessageSender {
s.Embeds = embeds
return s
}
func (s *MessageSender) AddComponent(cmp discordgo.MessageComponent) *MessageSender {
s.Components = append(s.Components, cmp)
return s
}
func (s *MessageSender) SetComponents(components []discordgo.MessageComponent) *MessageSender {
s.Components = components
return s
}
func (s *MessageSender) SetContent(content string) *MessageSender {
s.Content = content
return s
}
func (s *MessageSender) SetEphemeral(ephemeral bool) *MessageSender {
s.Ephemeral = ephemeral
return s
}
func (s *MessageSender) SetReply(reply bool) *MessageSender {
s.Reply = reply
return s
}
func (s *MessageSender) Send() {
switch m := s.m.(type) {
case *MessageCreate:
var reference *discordgo.MessageReference = nil
if s.Reply {
reference = m.Reference()
}
m.Session.ChannelMessageSendComplex(m.ChannelID, &discordgo.MessageSend{
Content: s.Content,
Embeds: s.Embeds,
Components: s.Components,
Reference: reference,
})
return
case *InteractionCreate:
var flags discordgo.MessageFlags
if s.Ephemeral {
flags = discordgo.MessageFlagsEphemeral
}
if m.Replied || m.Deferred {
m.EditReply(&discordgo.WebhookEdit{
Content: &s.Content,
Embeds: &s.Embeds,
Components: &s.Components,
})
return
}
m.Reply(&discordgo.InteractionResponseData{
Content: s.Content,
Embeds: s.Embeds,
Components: s.Components,
Flags: flags,
})
}
}

View file

@ -17,8 +17,41 @@ type PaginationEmbed struct {
desc string desc string
} }
type PaginationEmbedBuilder struct {
Embed *discordgo.MessageEmbed
Data []string
DefaultDesc string
m any
}
var PaginationEmbeds = make(map[string]*PaginationEmbed) var PaginationEmbeds = make(map[string]*PaginationEmbed)
func NewPaginationEmbedBuilder(m any, data []string) *PaginationEmbedBuilder {
return &PaginationEmbedBuilder{
m: m,
Data: data,
}
}
func (b *PaginationEmbedBuilder) SetEmbed(embed *discordgo.MessageEmbed) *PaginationEmbedBuilder {
b.Embed = embed
return b
}
func (b *PaginationEmbedBuilder) SetDefaultDesc(desc string) *PaginationEmbedBuilder {
b.DefaultDesc = desc
return b
}
func (b *PaginationEmbedBuilder) Start() {
switch m := b.m.(type) {
case *MessageCreate:
startPaginationEmbed(m, m.Author.ID, b.Embed, b.Data, b.DefaultDesc)
case *InteractionCreate:
startPaginationEmbed(m, m.Member.User.ID, b.Embed, b.Data, b.DefaultDesc)
}
}
func makeComponents(id string, current, total int) *[]discordgo.MessageComponent { func makeComponents(id string, current, total int) *[]discordgo.MessageComponent {
disabled := false disabled := false
@ -63,18 +96,8 @@ func makeDesc(desc, item string) string {
return newDesc return newDesc
} }
// StartPaginationEmbed starts new PaginationEmbed struct func startPaginationEmbed(m any, userId string, e *discordgo.MessageEmbed, data []string, defaultDesc string) {
func StartPaginationEmbed(s *discordgo.Session, m any, e *discordgo.MessageEmbed, data []string, defaultDesc string) { id := fmt.Sprintf("%s/%d", userId, rand.Intn(100))
var userId string
switch m := m.(type) {
case *discordgo.MessageCreate:
userId = m.Author.ID
case *InteractionCreate:
userId = m.Member.User.ID
}
id := fmt.Sprintf("%s/%d", userId, rand.Intn(12))
p := &PaginationEmbed{ p := &PaginationEmbed{
Embed: e, Embed: e,
Data: data, Data: data,
@ -91,19 +114,12 @@ func StartPaginationEmbed(s *discordgo.Session, m any, e *discordgo.MessageEmbed
p.Embed.Description = makeDesc(p.desc, data[0]) p.Embed.Description = makeDesc(p.desc, data[0])
} }
switch m := m.(type) { NewMessageSender(m).
case *discordgo.MessageCreate: AddEmbed(e).
s.ChannelMessageSendComplex(m.ChannelID, &discordgo.MessageSend{ SetComponents(*makeComponents(id, p.Current, p.Total)).
Reference: m.Reference(), SetReply(true).
Embeds: []*discordgo.MessageEmbed{p.Embed}, SetEphemeral(true).
Components: *makeComponents(id, p.Current, p.Total), Send()
})
case *InteractionCreate:
m.EditReply(&discordgo.WebhookEdit{
Embeds: &[]*discordgo.MessageEmbed{p.Embed},
Components: makeComponents(id, p.Current, p.Total),
})
}
PaginationEmbeds[id] = p PaginationEmbeds[id] = p
} }