Browse Source

simi-properly close websockets and simplify voice reconnect

Bruce Marriner 8 years ago
parent
commit
bbce2612b0
2 changed files with 57 additions and 61 deletions
  1. 27 39
      voice.go
  2. 30 22
      wsapi.go

+ 27 - 39
voice.go

@@ -181,11 +181,24 @@ func (v *VoiceConnection) Close() {
 	}
 
 	if v.wsConn != nil {
-		v.log(LogInformational, "closing wsConn")
-		err := v.wsConn.Close()
+		v.log(LogInformational, "sending close frame")
+
+		// To cleanly close a connection, a client should send a close
+		// frame and wait for the server to close the connection.
+		err := v.wsConn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
+		if err != nil {
+			v.log(LogError, "error closing websocket, %s", err)
+		}
+
+		// TODO: Wait for Discord to actually close the connection.
+		time.Sleep(1 * time.Second)
+
+		v.log(LogInformational, "closing websocket")
+		err = v.wsConn.Close()
 		if err != nil {
-			log.Println("error closing websocket connection: ", err)
+			v.log(LogError, "error closing websocket, %s", err)
 		}
+
 		v.wsConn = nil
 	}
 }
@@ -799,42 +812,6 @@ func (v *VoiceConnection) reconnect() {
 
 	defer func() { v.reconnecting = false }()
 
-	/*
-		if v.session == nil {
-			v.log(LogInformational, "cannot reconnect with nil session")
-			return
-		}
-
-			// check that the gateway session is Ready
-			// this needs more smarts - but the issue is that well the session
-			// could be not ready and in that case the disconnect below will panic
-			// one cause for that is if the gw disconnects and starts the reconnect
-			// processes right before the voice disconnects.
-			// NOTE: this will probably change but it's a safety net for now
-			i := 0
-			for v.session.DataReady == false || v.session.wsConn == nil {
-				if i > 20 {
-					v.log(LogInformational, "timeout waiting for ready session, I give up.")
-					return
-				}
-				time.Sleep(1 * time.Second)
-				i++
-			}
-
-			// Send a OP4 with a nil channel to disconnect
-			// this may not be required, but is here as a safety for now.
-			if v.sessionID != "" {
-				data := voiceChannelJoinOp{4, voiceChannelJoinData{&v.GuildID, nil, true, true}}
-				v.session.wsMutex.Lock()
-				err := v.session.wsConn.WriteJSON(data)
-				v.session.wsMutex.Unlock()
-				if err != nil {
-					v.log(LogError, "error sending disconnect packet, %s", err)
-				}
-				v.sessionID = ""
-			}
-	*/
-
 	// Close any currently open connections
 	v.Close()
 
@@ -867,6 +844,17 @@ func (v *VoiceConnection) reconnect() {
 			return
 		}
 
+		// if the quick reconnect above didn't work lets just send a disconnect
+		// packet to reset things.
+		// Send a OP4 with a nil channel to disconnect
+		data := voiceChannelJoinOp{4, voiceChannelJoinData{&v.GuildID, nil, true, true}}
+		v.session.wsMutex.Lock()
+		err = v.session.wsConn.WriteJSON(data)
+		v.session.wsMutex.Unlock()
+		if err != nil {
+			v.log(LogError, "error sending disconnect packet, %s", err)
+		}
+
 		v.log(LogInformational, "error reconnecting to channel %s, %s", v.ChannelID, err)
 	}
 }

+ 30 - 22
wsapi.go

@@ -427,19 +427,19 @@ func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool) (voice *Voi
 
 	s.log(LogInformational, "called")
 
-	// If a voice connection already exists for this guild then
-	// return that connection. If the channel differs, also change channels.
-	var ok bool
-	if voice, ok = s.VoiceConnections[gID]; ok && voice.GuildID != "" {
-		//TODO: consider a better variable than GuildID in the above check
-		// to verify if this connection is valid or not.
-
-		if voice.ChannelID != cID {
-			err = voice.ChangeChannel(cID, mute, deaf)
-		}
-		return
+	voice, _ = s.VoiceConnections[gID]
+
+	if voice == nil {
+		voice = &VoiceConnection{}
+		s.VoiceConnections[gID] = voice
 	}
 
+	voice.GuildID = gID
+	voice.ChannelID = cID
+	voice.deaf = deaf
+	voice.mute = mute
+	voice.session = s
+
 	// Send the request to Discord that we want to join the voice channel
 	data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, &cID, mute, deaf}}
 	s.wsMutex.Lock()
@@ -457,17 +457,6 @@ func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool) (voice *Voi
 		return
 	}
 
-	if voice == nil {
-		voice = &VoiceConnection{}
-		s.VoiceConnections[gID] = voice
-	}
-
-	voice.GuildID = gID
-	voice.ChannelID = cID
-	voice.deaf = deaf
-	voice.mute = mute
-	voice.session = s
-
 	return
 }
 
@@ -656,9 +645,28 @@ func (s *Session) Close() (err error) {
 		s.listening = nil
 	}
 
+	// TODO: Close all active Voice Connections too
+	// this should force stop any reconnecting voice channels too
+
 	if s.wsConn != nil {
+
+		s.log(LogInformational, "sending close frame")
+		// To cleanly close a connection, a client should send a close
+		// frame and wait for the server to close the connection.
+		err := s.wsConn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
+		if err != nil {
+			s.log(LogError, "error closing websocket, %s", err)
+		}
+
+		// TODO: Wait for Discord to actually close the connection.
+		time.Sleep(1 * time.Second)
+
 		s.log(LogInformational, "closing gateway websocket")
 		err = s.wsConn.Close()
+		if err != nil {
+			s.log(LogError, "error closing websocket, %s", err)
+		}
+
 		s.wsConn = nil
 	}