Skip to content

Commit

Permalink
delete & list command, always ensure response from bot, remove cache …
Browse files Browse the repository at this point in the history
…deadlock, remove db panic on error
  • Loading branch information
jokil123 committed Dec 25, 2023
1 parent 73756fd commit f718e03
Show file tree
Hide file tree
Showing 15 changed files with 238 additions and 58 deletions.
43 changes: 41 additions & 2 deletions EsefexApi/bot/commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package commands

import (
"esefexapi/sounddb"
"fmt"
"log"

"github.com/bwmarrin/discordgo"
)
Expand All @@ -22,10 +24,47 @@ func NewCommandHandlers(db sounddb.ISoundDB, domain string) *CommandHandlers {
}

ch.Commands["upload"] = UploadCommand
ch.Handlers["upload"] = ch.Upload
ch.Handlers["upload"] = WithErrorHandling(ch.Upload)

ch.Commands["session"] = SessionCommand
ch.Handlers["session"] = ch.Session
ch.Handlers["session"] = WithErrorHandling(ch.Session)

ch.Commands["list"] = ListCommand
ch.Handlers["list"] = WithErrorHandling(ch.List)

ch.Commands["delete"] = DeleteCommand
ch.Handlers["delete"] = WithErrorHandling(ch.Delete)

return ch
}

func WithErrorHandling(h func(s *discordgo.Session, i *discordgo.InteractionCreate) (*discordgo.InteractionResponse, error)) func(s *discordgo.Session, i *discordgo.InteractionCreate) {
return func(s *discordgo.Session, i *discordgo.InteractionCreate) {
r, err := h(s, i)
if err != nil {
log.Printf("Cannot execute command: %v", err)

s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: fmt.Sprintf("An error has occurred while executing the command: %v", err),
},
})
}

if r != nil {
s.InteractionRespond(i.Interaction, r)
}
}
}

func OptionsMap(i *discordgo.InteractionCreate) map[string]*discordgo.ApplicationCommandInteractionDataOption {
options := i.ApplicationCommandData().Options

optionMap := make(map[string]*discordgo.ApplicationCommandInteractionDataOption, len(options))
for _, opt := range options {
optionMap[opt.Name] = opt
}

return optionMap
}
61 changes: 61 additions & 0 deletions EsefexApi/bot/commands/delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package commands

import (
"esefexapi/sounddb"
"fmt"
"log"

"github.com/bwmarrin/discordgo"
)

var (
DeleteCommand = &discordgo.ApplicationCommand{
Name: "delete",
Description: "Delete a sound effect",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "sound-id",
Description: "The sound effect to delete",
Required: true,
},
},
}
)

func (c *CommandHandlers) Delete(s *discordgo.Session, i *discordgo.InteractionCreate) (*discordgo.InteractionResponse, error) {
options := OptionsMap(i)
soundID := options["sound-id"]

uid := sounddb.SuidFromStrings(i.GuildID, fmt.Sprint(soundID.Value))

exists, err := c.db.SoundExists(uid)
if err != nil {
return nil, err
}
if !exists {
return &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: fmt.Sprintf("Sound effect `%s` does not exist", soundID.Value),
},
}, nil
}

log.Print("a")

err = c.db.DeleteSound(uid)
if err != nil {
log.Println(err)
return nil, err
}

log.Printf("Deleted sound effect %v from server %v", soundID.Value, i.GuildID)

return &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: fmt.Sprintf("Deleted sound effect `%s`", soundID.Value),
},
}, nil
}
68 changes: 68 additions & 0 deletions EsefexApi/bot/commands/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package commands

import (
"esefexapi/sounddb"
"fmt"

"github.com/bwmarrin/discordgo"
)

var (
ListCommand = &discordgo.ApplicationCommand{
Name: "list",
Description: "List all sound effects in the server",
}
)

func (c *CommandHandlers) List(s *discordgo.Session, i *discordgo.InteractionCreate) (*discordgo.InteractionResponse, error) {
uids, err := c.db.GetSoundUIDs(i.GuildID)
if err != nil {
return nil, err
}
// log.Printf("List: %v", uids)

var metas = make([]sounddb.SoundMeta, 0, len(uids))
for _, uid := range uids {
meta, err := c.db.GetSoundMeta(uid)
if err != nil {
return nil, err
}
metas = append(metas, meta)
}

if len(metas) == 0 {
return &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "There are no sounds in this server",
},
}, nil
}

if len(metas) == 1 {
return &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: fmt.Sprintf("There is 1 sound in this server: \n%s", fmtMetaList(metas)),
},
}, nil
}

return &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: fmt.Sprintf("There are %d sounds in this server: \n%s", len(metas), fmtMetaList(metas)),
},
}, nil
}

func fmtMetaList(metas []sounddb.SoundMeta) string {
// log.Printf("fmtMetaList: %v", metas)
var str string
for _, meta := range metas {
str += fmt.Sprintf("- %s `%s`\n", meta.Name, meta.SoundID)
}

// log.Println(str)
return str
}
20 changes: 9 additions & 11 deletions EsefexApi/bot/commands/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package commands
import (
"esefexapi/bot/actions"
"fmt"
"log"

"github.com/bwmarrin/discordgo"
)
Expand All @@ -15,10 +14,10 @@ var (
}
)

func (c *CommandHandlers) Session(s *discordgo.Session, i *discordgo.InteractionCreate) {
func (c *CommandHandlers) Session(s *discordgo.Session, i *discordgo.InteractionCreate) (*discordgo.InteractionResponse, error) {
g, err := s.State.Guild(i.GuildID)
if err != nil {
log.Printf("Cannot get guild: %v", err)
return nil, err
}

var userChannel string
Expand All @@ -29,27 +28,26 @@ func (c *CommandHandlers) Session(s *discordgo.Session, i *discordgo.Interaction
userChannel = vs.ChannelID
}
}

if !userConnected {
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
return &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "You must be connected to a voice channel to get the session link.",
},
})
return
}}, nil
}

route := "joinsession"

// https://esefex.com/joinsession/1234567890
url := fmt.Sprintf("https://%s/%s/%s", c.domain, route, i.GuildID)

s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
actions.JoinChannelVoice(s, i.GuildID, userChannel)

return &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: url,
},
})

actions.JoinChannelVoice(s, i.GuildID, userChannel)
}, nil
}
25 changes: 9 additions & 16 deletions EsefexApi/bot/commands/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,34 +35,27 @@ var (
}
)

func (c *CommandHandlers) Upload(s *discordgo.Session, i *discordgo.InteractionCreate) {
options := i.ApplicationCommandData().Options
func (c *CommandHandlers) Upload(s *discordgo.Session, i *discordgo.InteractionCreate) (*discordgo.InteractionResponse, error) {
options := OptionsMap(i)

optionMap := make(map[string]*discordgo.ApplicationCommandInteractionDataOption, len(options))
for _, opt := range options {
optionMap[opt.Name] = opt
}

icon := optionMap["icon"]
icon := options["icon"]
iconURL := util.ExtractIconUrl(icon)

soundFile := optionMap["sound-file"]
soundFile := options["sound-file"]
soundFileUrl := i.ApplicationCommandData().Resolved.Attachments[fmt.Sprint(soundFile.Value)].URL

pcm, err := util.Download2PCM(soundFileUrl)
if err != nil {
log.Printf("Cannot download sound file: %v", err)
return
return nil, err
}

c.db.AddSound(i.GuildID, fmt.Sprint(optionMap["name"].Value), iconURL, pcm)
c.db.AddSound(i.GuildID, fmt.Sprint(options["name"].Value), iconURL, pcm)

log.Printf("Uploaded sound effect %v to server %v", optionMap["name"].Value, i.GuildID)
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
log.Printf("Uploaded sound effect %v to server %v", options["name"].Value, i.GuildID)
return &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "Uploaded sound effect",
},
})

}, nil
}
6 changes: 6 additions & 0 deletions EsefexApi/sounddb/apimockdb/apimockdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,9 @@ func (*ApiMockDB) GetSoundUIDs(serverID string) ([]sounddb.SoundUID, error) {
}
return uids, nil
}

// SoundExists implements sounddb.ISoundDB.
func (*ApiMockDB) SoundExists(uid sounddb.SoundUID) (bool, error) {
_, ok := mockData[uid.ServerID][uid.SoundID]
return ok, nil
}
1 change: 1 addition & 0 deletions EsefexApi/sounddb/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ type ISoundDB interface {
GetSoundPcm(uid SoundUID) ([]int16, error)
GetSoundUIDs(serverID string) ([]SoundUID, error)
GetServerIDs() ([]string, error)
SoundExists(uid SoundUID) (bool, error)
}

type SoundUID struct {
Expand Down
24 changes: 16 additions & 8 deletions EsefexApi/sounddb/dbcache/dbcache.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ func NewDBCache(db sounddb.ISoundDB) *DBCache {

// AddSound implements db.SoundDB.
func (c *DBCache) AddSound(serverID string, name string, icon string, pcm []int16) (sounddb.SoundUID, error) {
c.rw.Lock()
defer c.rw.Unlock()

uid, err := c.db.AddSound(serverID, name, icon, pcm)
if err != nil {
return sounddb.SoundUID{}, err
}

c.rw.Lock()
defer c.rw.Unlock()

c.sounds[uid] = &CachedSound{
Data: pcm,
Meta: sounddb.SoundMeta{
Expand All @@ -55,17 +55,14 @@ func (c *DBCache) AddSound(serverID string, name string, icon string, pcm []int1

// DeleteSound implements db.SoundDB.
func (c *DBCache) DeleteSound(uid sounddb.SoundUID) error {
c.rw.RLock()
defer c.rw.RUnlock()
c.rw.Lock()
defer c.rw.Unlock()

err := c.db.DeleteSound(uid)
if err != nil {
return err
}

c.rw.Lock()
defer c.rw.Unlock()

delete(c.sounds, uid)

return nil
Expand Down Expand Up @@ -193,3 +190,14 @@ func (c *DBCache) LoadSound(uid sounddb.SoundUID) (*CachedSound, error) {
return &s, nil

}

func (c *DBCache) SoundExists(uid sounddb.SoundUID) (bool, error) {
c.rw.RLock()
defer c.rw.RUnlock()

if _, ok := c.sounds[uid]; ok {
return true, nil
}

return c.db.SoundExists(uid)
}
8 changes: 4 additions & 4 deletions EsefexApi/sounddb/filedb/addsound.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ func (f *FileDB) AddSound(serverID string, name string, iconUrl string, pcm []in
path = fmt.Sprintf("%s/%s/%s_meta.json", f.location, serverID, sound.SoundID)
metaFile, err := os.Create(path)
if err != nil {
log.Fatal(err)
log.Print(err)
return sounddb.SoundUID{}, err
}

metaJson, err := json.Marshal(sound)
if err != nil {
log.Fatal(err)
log.Print(err)
return sounddb.SoundUID{}, err
}

Expand All @@ -50,13 +50,13 @@ func (f *FileDB) AddSound(serverID string, name string, iconUrl string, pcm []in

soundFile, err := os.Create(path)
if err != nil {
log.Fatal(err)
log.Print(err)
return sounddb.SoundUID{}, err
}

err = binary.Write(soundFile, binary.LittleEndian, pcm)
if err != nil {
log.Fatal(err)
log.Print(err)
return sounddb.SoundUID{}, err
}

Expand Down
Loading

0 comments on commit f718e03

Please sign in to comment.