Add connect timeout, fix ChannelVoiceJoin "leaking" connections

This commit is contained in:
andrei 2016-03-08 02:36:00 -08:00
parent b48e8c992e
commit 5dc0b9f2a1
3 changed files with 40 additions and 16 deletions

View file

@ -54,7 +54,7 @@ type Session struct {
// Whether the UDP Connection is ready
UDPReady bool
// Stores a mapping of channel id's to VoiceConnections
// Stores a mapping of guild id's to VoiceConnections
VoiceConnections map[string]*VoiceConnection
// Managed state object, updated internally with events when

View file

@ -12,6 +12,7 @@ package discordgo
import (
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"net"
"runtime"
@ -97,7 +98,6 @@ type voiceHandshakeOp struct {
// after VoiceConnectionChannelJoin is used and the data VOICE websocket events
// are captured.
func (v *VoiceConnection) Open() (err error) {
v.Lock()
defer v.Unlock()
@ -131,8 +131,19 @@ func (v *VoiceConnection) Open() (err error) {
return
}
func (v *VoiceConnection) WaitUntilConnected() {
<-v.connected
func (v *VoiceConnection) WaitUntilConnected() error {
if v.Ready {
return nil
}
value, ok := <-v.connected
if (!value && !v.Ready) || !ok {
delete(v.session.VoiceConnections, v.GuildID)
return errors.New("Timed out connecting to voice")
}
return nil
}
// wsListen listens on the voice websocket for messages and passes them
@ -603,9 +614,11 @@ func (v *VoiceConnection) Close() {
v.Lock()
defer v.Unlock()
if v.Ready {
// Send a OP4 with a nil channel to disconnect
if v.sessionID != "" {
data := voiceChannelJoinOp{4, voiceChannelJoinData{&v.GuildID, nil, true, true}}
v.session.wsConn.WriteJSON(data)
v.sessionID = ""
}
v.Ready = false
@ -632,15 +645,10 @@ func (v *VoiceConnection) Close() {
}
}
// Change channels
// Request to change channels
func (v *VoiceConnection) ChangeChannel(channelID string) (err error) {
data := voiceChannelJoinOp{4, voiceChannelJoinData{&v.GuildID, &channelID, true, true}}
err = v.session.wsConn.WriteJSON(data)
if err == nil {
v.ChannelID = channelID
}
return err
}

View file

@ -336,7 +336,13 @@ type voiceChannelJoinOp struct {
// cID : Channel ID of the channel to join.
// mute : If true, you will be set to muted upon joining.
// deaf : If true, you will be set to deafened upon joining.
func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool) (voice *VoiceConnection, err error) {
// timeout : If greater than zero, the timeout in milliseconds after which connecting will fail
func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool, timeout int) (voice *VoiceConnection, err error) {
// If a voice connection for the guild exists, return that
if _, exists := s.VoiceConnections[gID]; exists {
return s.VoiceConnections[gID], err
}
// Send the request to Discord that we want to join the voice channel
data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, &cID, mute, deaf}}
err = s.wsConn.WriteJSON(data)
@ -359,6 +365,16 @@ func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool) (voice *Voi
voice.GuildID = gID
voice.ChannelID = cID
// Queue the timeout in case we fail to connect
if timeout > 0 {
go func() {
time.Sleep(time.Millisecond * time.Duration(timeout))
if !voice.Ready {
voice.connected <- false
}
}()
}
return voice, err
}