-
-
Notifications
You must be signed in to change notification settings - Fork 70
How would I go about retrieving the voice channel of the author of a message? #288
Comments
Line 1382 in 0b361f3
Looks like a bit more of a faff than the python implementation but you could configure the cache then access it with the GetVoiceState method passing it your user[/author] id. It should return any states matching the filters you've passed. |
Here's my attempt: // 1
cache, ok := client.Cache().(*disgord.Cache)
if !ok {
log.Println("Failed to get cache...")
return
}
// 2
state, err := cache.GetVoiceState(m.Message.GuildID, nil)
if err != nil {
log.Printf("Cache Voice State error: %+v\n", err)
return
}
log.Printf("state: %+v\n", state) Problems I ran into:
|
Voice have been neglected when it comes the caching. The interaction with the cache is a bit iffy, and I'm open to rewriting it. Right now I have a lot on my plate, so I'm open to suggestions. |
It's been a while, so I thought I would update this issue with the current strategy I have employed in order to receive the current voice channel ID of the author of a message in case it can help other people out. There are two pieces of information that directed my implementation:
The The First thing I needed was a custom cache for storing and handling all of this information. I personally only needed an in-memory solution without the need for a database due to my bot's scope, however I designed a consistent API interface in case my needs grew. Here is what that looked like: Interface: // VoiceStateCache caches Disgord voice states.
type VoiceStateCache interface {
Handle(disgord.Session, *disgord.VoiceState) error
AddVoiceState(*disgord.VoiceState)
GetVoiceState(disgord.Snowflake) (int, *disgord.VoiceState)
UpdateVoiceState(disgord.Snowflake, *disgord.VoiceState)
DeleteVoiceState(disgord.Snowflake)
} In-memory cache implementation: // VoiceStateCache is a cache.
type VoiceStateCache struct {
voiceStates []*disgord.VoiceState
mutex sync.RWMutex
}
// NewVoiceStateCache creates a new VoiceStateCache.
func NewVoiceStateCache() *VoiceStateCache {
return &VoiceStateCache{
voiceStates: []*disgord.VoiceState{},
}
}
// Handle handles a voice state event.
func (c *VoiceStateCache) Handle(session disgord.Session, voiceState *disgord.VoiceState) error {
// get user who triggered voice state update event
user, err := session.GetUser(context.Background(), voiceState.UserID)
if err != nil {
return err
}
// bots don't count
if !user.Bot {
if voiceState.ChannelID.IsZero() {
// no channel ID; this is a 'leave voice channel' event
c.DeleteVoiceState(user.ID)
} else {
// channel ID exists; user could've freshly joined a voice channel or switched to a different one
_, oldVoiceState := c.GetVoiceState(user.ID)
if oldVoiceState == nil {
// this is a 'freshly joined voice channel' event
c.AddVoiceState(voiceState)
} else {
// this is a 'moved between voice channels' event
c.UpdateVoiceState(voiceState.UserID, voiceState)
}
}
}
return nil
}
// AddVoiceState adds a Disgord voice state.
func (c *VoiceStateCache) AddVoiceState(vs *disgord.VoiceState) {
if vs == nil {
return
}
c.mutex.Lock()
defer c.mutex.Unlock()
c.voiceStates = append(c.voiceStates, vs)
}
// GetVoiceState gets a Disgord voice state.
func (c *VoiceStateCache) GetVoiceState(userID disgord.Snowflake) (int, *disgord.VoiceState) {
if userID.IsZero() {
return -1, nil
}
c.mutex.RLock()
defer c.mutex.RUnlock()
for i, vs := range c.voiceStates {
if vs.UserID == userID {
return i, vs
}
}
return -1, nil
}
// UpdateVoiceState updates a Disgord voice state.
func (c *VoiceStateCache) UpdateVoiceState(userID disgord.Snowflake, vs *disgord.VoiceState) {
if userID.IsZero() || vs == nil {
return
}
i, _ := c.GetVoiceState(userID)
if i == -1 {
c.AddVoiceState(vs)
return
}
c.mutex.Lock()
defer c.mutex.Unlock()
c.voiceStates[i] = vs
}
// DeleteVoiceState deletes a Disgord voice state.
func (c *VoiceStateCache) DeleteVoiceState(userID disgord.Snowflake) {
if userID.IsZero() {
return
}
i, _ := c.GetVoiceState(userID)
if i == -1 {
return
}
c.mutex.Lock()
defer c.mutex.Unlock()
c.voiceStates = append(c.voiceStates[:i], c.voiceStates[i+1:]...)
} Now that I had somewhere to store this information, I just needed to connect it to the event handlers. First, listen for the events: // Guild Create (when bot joins guild)
bot.On(disgord.EvtGuildCreate, bot.guildCreate)
// Voice State Update
bot.On(disgord.EvtVoiceStateUpdate, bot.voiceStateUpdate) Then, handle them: func (yb *YourBot) guildCreate(session disgord.Session, evt *disgord.GuildCreate) {
for _, vs := range evt.Guild.VoiceStates {
err := yb.voiceStateCache.Handle(session, vs)
if err != nil {
yb.Logger().Error(fmt.Sprintf("voiceStateCache Handle error: %+v\n", err))
}
}
}
func (yb *YourBot) voiceStateUpdate(session disgord.Session, evt *disgord.VoiceStateUpdate) {
err := yb.voiceStateCache.Handle(session, evt.VoiceState)
if err != nil {
yb.Logger().Error(fmt.Sprintf("voiceStateCache Handle error: %+v\n", err))
}
} Easy as that! Hope this helps anyone that finds themselves in the same boat. |
My solution is extremely(!!) inspired by the bowot bot by @saanuregh. These are the places you can find his equivalent methods for reference: |
Here's an example of how to use this voice state cache API in your bot: // getVoiceChannelID retrieves the voice channel ID of the message author, if they're in one
func (yb *YourBot) getVoiceChannelID(session disgord.Session, evt *disgord.MessageCreate) disgord.Snowflake {
_, vs := yb.voiceStateCache.GetVoiceState(evt.Message.Author.ID)
if vs == nil {
yb.Logger().Info(fmt.Sprintf("%s (%s) is not in a voice channel\n", evt.Message.Author.Username, evt.Message.Author.ID))
return 0
}
return vs.ChannelID
} |
I'm re-writing the cache a bit now. Perhaps you want to implement voice state under the new interface? I can let you know when that would be ready for PR's. |
Yeah, I'd love to implement the voice state stuff into Disgord! I'll probably need a little hand holding at first (I've never contributed to OSS before), but just let me know when. At that point we can discuss what changes you like to see to convert my quick-fix to your new cache/interface. |
I forgot to make my quick-fix cache example thread safe; I've since refactored my post above to utilize |
see #311 |
@andersfylling Do you still want me to add some voice state caching to your new cache system? |
that would be great. I only closed this, along with a few other voice state cache related issues, to keep everything in one place. Hopefully it's easy to add voice caching now |
When I receive a message via an EvtMessageCreate, I need to know what voice channel they are in (if they are in one). This is a really easy thing to do in Discord.py by just checking the existence of a message's
ctx.author.voice.channel
and using it apropriately. How would I go about doing that with this library?The text was updated successfully, but these errors were encountered: