Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions kite-service/internal/core/engine/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,29 @@ func (a *App) HandleEvent(appID string, session *state.State, event gateway.Even
return
}

go instance.HandleEvent(appID, session, event)
case *discord.StringSelectInteraction:
messageID := e.Message.ID.String()
messageInstnace, err := a.env.MessageInstanceStore.MessageInstanceByDiscordMessageID(context.TODO(), messageID)
if err != nil {
if errors.Is(err, store.ErrNotFound) {
return
}

slog.With("error", err).Error("failed to get message instance by discord message ID")
return
}

instance, err := NewMessageInstance(
a.id,
messageInstnace,
a.env,
)
if err != nil {
slog.With("error", err).Error("failed to create message instance")
return
}

go instance.HandleEvent(appID, session, event)
case *discord.ModalInteraction:
customID := string(d.CustomID)
Expand Down
35 changes: 22 additions & 13 deletions kite-service/internal/core/engine/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,23 @@ func NewMessageInstance(
flows := make(map[string]*flow.CompiledFlowNode, len(msg.FlowSources))

for id, flowSource := range msg.FlowSources {
flow, err := flow.CompileComponentButton(flowSource)
// Try to compile as button first, then as select menu
compiledFlow, err := flow.CompileComponentButton(flowSource)
if err != nil {
slog.Error(
"Failed to compile component button flow",
slog.String("app_id", appID),
slog.String("message_id", msg.MessageID),
slog.String("error", err.Error()),
)
continue
// Try compiling as select menu
compiledFlow, err = flow.CompileComponentSelect(flowSource)
if err != nil {
slog.Error(
"Failed to compile component flow",
slog.String("app_id", appID),
slog.String("message_id", msg.MessageID),
slog.String("error", err.Error()),
)
continue
}
}

flows[id] = flow
flows[id] = compiledFlow
}

return &MessageInstance{
Expand All @@ -55,13 +60,17 @@ func (m *MessageInstance) HandleEvent(appID string, session *state.State, event
return
}

d, ok := i.InteractionEvent.Data.(*discord.ButtonInteraction)
if !ok {
var flowSourceID string

switch d := i.InteractionEvent.Data.(type) {
case *discord.ButtonInteraction:
flowSourceID = string(d.CustomID)
case *discord.StringSelectInteraction:
flowSourceID = string(d.CustomID)
default:
return
}

flowSourceID := string(d.CustomID)

links := entityLinks{
MessageID: null.NewString(m.msg.MessageID, true),
MessageInstanceID: null.NewInt(int64(m.msg.ID), true),
Expand Down
14 changes: 14 additions & 0 deletions kite-service/pkg/eval/ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type InteractionEnv struct {
Member any `expr:"member" json:"member"`
Command *CommandEnv `expr:"command" json:"command"`
Components map[string]*ComponentEnv `expr:"components" json:"components"`
Values []string `expr:"values" json:"values"`
}

func NewInteractionEnv(i *discord.InteractionEvent) *InteractionEnv {
Expand All @@ -39,6 +40,7 @@ func NewInteractionEnv(i *discord.InteractionEvent) *InteractionEnv {
ID: i.ID.String(),
Channel: NewSnowflakeEnv(i.ChannelID),
Components: NewComponentsEnv(i),
Values: []string{},
}

if i.Member != nil {
Expand All @@ -57,6 +59,11 @@ func NewInteractionEnv(i *discord.InteractionEvent) *InteractionEnv {
e.Command = NewCommandEnv(i)
}

// Extract selected values from select menu interactions
if selectData, ok := i.Data.(*discord.StringSelectInteraction); ok {
e.Values = selectData.Values
}

return e
}

Expand All @@ -72,6 +79,7 @@ func NewContextFromInteraction(i *discord.InteractionEvent, session *state.State
"user": interactionEnv.User,
"member": interactionEnv.Member,
"app": NewAppEnv(session),
"values": interactionEnv.Values,

"arg": func(name string) any {
if interactionEnv.Command == nil {
Expand All @@ -90,6 +98,12 @@ func NewContextFromInteraction(i *discord.InteractionEvent, session *state.State
}
return nil
},
"value": func(index int) any {
if index < 0 || index >= len(interactionEnv.Values) {
return nil
}
return interactionEnv.Values[index]
},
},
}
}
Expand Down
9 changes: 9 additions & 0 deletions kite-service/pkg/flow/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ func CompileComponentButton(data FlowData) (*CompiledFlowNode, error) {
return compile(data, FlowNodeTypeEntryComponentButton)
}

func CompileComponentSelect(data FlowData) (*CompiledFlowNode, error) {
return compile(data, FlowNodeTypeEntryComponentSelect)
}

func CompileEventListener(data FlowData) (*CompiledFlowNode, error) {
return compile(data, FlowNodeTypeEntryEvent)
}
Expand Down Expand Up @@ -105,13 +109,18 @@ type ConnectedFlowNodes struct {
func (n *CompiledFlowNode) IsEntry() bool {
return n.Type == FlowNodeTypeEntryCommand ||
n.Type == FlowNodeTypeEntryComponentButton ||
n.Type == FlowNodeTypeEntryComponentSelect ||
n.Type == FlowNodeTypeEntryEvent
}

func (n *CompiledFlowNode) IsComponentButtonEntry() bool {
return n.Type == FlowNodeTypeEntryComponentButton
}

func (n *CompiledFlowNode) IsComponentSelectEntry() bool {
return n.Type == FlowNodeTypeEntryComponentSelect
}

func (n *CompiledFlowNode) IsEventListenerEntry() bool {
return n.Type == FlowNodeTypeEntryEvent
}
Expand Down
1 change: 1 addition & 0 deletions kite-service/pkg/flow/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const (
FlowNodeTypeEntryCommand FlowNodeType = "entry_command"
FlowNodeTypeEntryEvent FlowNodeType = "entry_event"
FlowNodeTypeEntryComponentButton FlowNodeType = "entry_component_button"
FlowNodeTypeEntryComponentSelect FlowNodeType = "entry_component_select"

FlowNodeTypeOptionCommandArgument FlowNodeType = "option_command_argument"
FlowNodeTypeOptionCommandPermissions FlowNodeType = "option_command_permissions"
Expand Down
2 changes: 1 addition & 1 deletion kite-service/pkg/flow/execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func (n *CompiledFlowNode) Execute(ctx *FlowContext) error {
defer ctx.endOperation()

switch n.Type {
case FlowNodeTypeEntryCommand, FlowNodeTypeEntryComponentButton:
case FlowNodeTypeEntryCommand, FlowNodeTypeEntryComponentButton, FlowNodeTypeEntryComponentSelect:
if !ctx.IsEntry() {
return fmt.Errorf("command entry isn't the entry node")
}
Expand Down
39 changes: 39 additions & 0 deletions kite-service/pkg/message/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,11 +226,50 @@ func (c *ComponentData) ToComponent(opts ConvertOptions) discord.InteractiveComp
Disabled: c.Disabled,
CustomID: customID,
}
case int(discord.StringSelectComponentType):
var customID discord.ComponentID
if opts.ComponentIDFactory != nil {
customID = opts.ComponentIDFactory(c)
} else {
customID = discord.ComponentID(c.FlowSourceID)
}

options := make([]discord.SelectOption, len(c.Options))
for i, opt := range c.Options {
options[i] = opt.ToSelectOption()
}

return &discord.StringSelectComponent{
CustomID: customID,
Placeholder: c.Placeholder,
Disabled: c.Disabled,
Options: options,
ValueLimits: [2]int{c.MinValues, c.MaxValues},
}
}

return nil
}

func (o *ComponentSelectOptionData) ToSelectOption() discord.SelectOption {
if o == nil {
return discord.SelectOption{}
}

var emoji *discord.ComponentEmoji
if o.Emoji != nil {
emoji = o.Emoji.ToEmoji()
}

return discord.SelectOption{
Label: o.Label,
Value: o.FlowSourceID,
Description: o.Description,
Emoji: emoji,
Default: o.Default,
}
}

func (e *ComponentEmojiData) ToEmoji() *discord.ComponentEmoji {
if e == nil {
return nil
Expand Down
Loading