Quellcode durchsuchen

Add connect timeout, fix ChannelVoiceJoin "leaking" connections

andrei vor 8 Jahren
Ursprung
Commit
5dc0b9f2a1
3 geänderte Dateien mit 40 neuen und 16 gelöschten Zeilen
  1. 1 1
      structs.go
  2. 18 10
      voice.go
  3. 21 5
      wsapi.go

+ 1 - 1
structs.go

@@ -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

+ 18 - 10
voice.go

@@ -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
 }

+ 21 - 5
wsapi.go

@@ -332,11 +332,17 @@ type voiceChannelJoinOp struct {
 // this func please monitor the Session.Voice.Ready bool to determine when
 // it is ready and able to send/receive audio, that should happen quickly.
 //
-//    gID   : Guild ID of the channel to join.
-//    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) {
+//    gID     : Guild ID of the channel to join.
+//    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.
+//    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
 }