All sent JSON data now using structs

This commit is contained in:
Bruce Marriner 2015-12-20 00:13:19 -06:00
parent 0fbfc66554
commit b87add9152

View file

@ -23,7 +23,7 @@ import (
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
) )
// A VEvent is the inital structure for voice websocket events. I think // A VEvent is the initial structure for voice websocket events. I think
// I can reuse the data websocket structure here. // I can reuse the data websocket structure here.
type VEvent struct { type VEvent struct {
Type string `json:"t"` Type string `json:"t"`
@ -41,15 +41,32 @@ type VoiceOP2 struct {
HeartbeatInterval time.Duration `json:"heartbeat_interval"` HeartbeatInterval time.Duration `json:"heartbeat_interval"`
} }
type voiceHandshakeData struct {
ServerID string `json:"server_id"`
UserID string `json:"user_id"`
SessionID string `json:"session_id"`
Token string `json:"token"`
}
type voiceHandshakeOp struct {
Op int `json:"op"` // Always 0
Data voiceHandshakeData `json:"d"`
}
// VoiceOpenWS opens a voice websocket connection. This should be called // VoiceOpenWS opens a voice websocket connection. This should be called
// after VoiceChannelJoin is used and the data VOICE websocket events // after VoiceChannelJoin is used and the data VOICE websocket events
// are captured. // are captured.
func (s *Session) VoiceOpenWS() { func (s *Session) VoiceOpenWS() {
// Don't open a socket if one is already open
if s.VwsConn != nil {
return
}
var self User var self User
var err error var err error
self, err = s.User("@me") // AGAIN, Move to @ login and store in session self, err = s.User("@me") // TODO: Move to @ login and store in session
// Connect to Voice Websocket // Connect to Voice Websocket
vg := fmt.Sprintf("wss://%s", strings.TrimSuffix(s.VEndpoint, ":80")) vg := fmt.Sprintf("wss://%s", strings.TrimSuffix(s.VEndpoint, ":80"))
@ -58,16 +75,7 @@ func (s *Session) VoiceOpenWS() {
fmt.Println("VOICE cannot open websocket:", err) fmt.Println("VOICE cannot open websocket:", err)
} }
// Send initial handshake data to voice websocket. This is required. json := voiceHandshakeOp{0, voiceHandshakeData{s.VGuildID, self.ID, s.VSessionID, s.VToken}}
json := map[string]interface{}{
"op": 0,
"d": map[string]interface{}{
"server_id": s.VGuildID,
"user_id": self.ID,
"session_id": s.VSessionID,
"token": s.VToken,
},
}
err = s.VwsConn.WriteJSON(json) err = s.VwsConn.WriteJSON(json)
if err != nil { if err != nil {
@ -147,13 +155,29 @@ func (s *Session) VoiceEvent(messageType int, message []byte) (err error) {
return return
} }
type voiceUDPData struct {
Address string `json:"address"` // Public IP of machine running this code
Port uint16 `json:"port"` // UDP Port of machine running this code
Mode string `json:"mode"` // plain or ? (plain or encrypted)
}
type voiceUDPD struct {
Protocol string `json:"protocol"` // Always "udp" ?
Data voiceUDPData `json:"data"`
}
type voiceUDPOp struct {
Op int `json:"op"` // Always 1
Data voiceUDPD `json:"d"`
}
// VoiceOpenUDP opens a UDP connect to the voice server and completes the // VoiceOpenUDP opens a UDP connect to the voice server and completes the
// initial required handshake. This connect is left open in the session // initial required handshake. This connect is left open in the session
// and can be used to send or receive audio. // and can be used to send or receive audio.
func (s *Session) VoiceOpenUDP() { func (s *Session) VoiceOpenUDP() {
// TODO: add code to convert hostname into an IP address to avoid problems // TODO: add code to convert hostname into an IP address to avoid problems
// with frequent DNS lookups. // with frequent DNS lookups. ??
udpHost := fmt.Sprintf("%s:%d", strings.TrimSuffix(s.VEndpoint, ":80"), s.Vop2.Port) udpHost := fmt.Sprintf("%s:%d", strings.TrimSuffix(s.VEndpoint, ":80"), s.Vop2.Port)
serverAddr, err := net.ResolveUDPAddr("udp", udpHost) serverAddr, err := net.ResolveUDPAddr("udp", udpHost)
@ -182,6 +206,7 @@ func (s *Session) VoiceOpenUDP() {
fmt.Println("Voice RLEN should be 70 but isn't") fmt.Println("Voice RLEN should be 70 but isn't")
} }
// TODO need serious changes, this will likely not work on all IPs!
ip := string(rb[4:16]) // must be a better way. TODO: NEEDS TESTING ip := string(rb[4:16]) // must be a better way. TODO: NEEDS TESTING
port := make([]byte, 2) port := make([]byte, 2)
port[0] = rb[68] port[0] = rb[68]
@ -190,10 +215,9 @@ func (s *Session) VoiceOpenUDP() {
// Take the parsed data from above and send it back to Discord // Take the parsed data from above and send it back to Discord
// to finalize the UDP handshake. // to finalize the UDP handshake.
json := fmt.Sprintf(`{"op":1,"d":{"protocol":"udp","data":{"address":"%s","port":%d,"mode":"plain"}}}`, ip, p) jsondata := voiceUDPOp{1, voiceUDPD{"udp", voiceUDPData{ip, p, "plain"}}}
jsonb := []byte(json)
err = s.VwsConn.WriteMessage(websocket.TextMessage, jsonb) err = s.VwsConn.WriteJSON(jsondata)
if err != nil { if err != nil {
fmt.Println("error:", err) fmt.Println("error:", err)
return return
@ -209,6 +233,16 @@ func (s *Session) VoiceCloseUDP() {
s.UDPConn.Close() s.UDPConn.Close()
} }
type voiceSpeakingData struct {
Speaking bool `json:"speaking"`
Delay int `json:"delay"`
}
type voiceSpeakingOp struct {
Op int `json:"op"` // Always 5
Data voiceSpeakingData `json:"d"`
}
func (s *Session) VoiceSpeaking() { func (s *Session) VoiceSpeaking() {
if s.VwsConn == nil { if s.VwsConn == nil {
@ -217,8 +251,8 @@ func (s *Session) VoiceSpeaking() {
return return
} }
jsonb := []byte(`{"op":5,"d":{"speaking":true,"delay":0}}`) json := voiceSpeakingOp{5, voiceSpeakingData{true, 0}}
err := s.VwsConn.WriteMessage(websocket.TextMessage, jsonb) err := s.VwsConn.WriteJSON(json)
if err != nil { if err != nil {
fmt.Println("error:", err) fmt.Println("error:", err)
return return
@ -284,6 +318,11 @@ func (s *Session) VoiceUDPKeepalive(i time.Duration) {
} }
} }
type voiceHeartbeatOp struct {
Op int `json:"op"` // Always 3
Data int `json:"d"`
}
// VoiceHeartbeat sends regular heartbeats to voice Discord so it knows the client // VoiceHeartbeat sends regular heartbeats to voice Discord so it knows the client
// is still connected. If you do not send these heartbeats Discord will // is still connected. If you do not send these heartbeats Discord will
// disconnect the websocket connection after a few seconds. // disconnect the websocket connection after a few seconds.
@ -292,15 +331,15 @@ func (s *Session) VoiceHeartbeat(i time.Duration) {
ticker := time.NewTicker(i * time.Millisecond) ticker := time.NewTicker(i * time.Millisecond)
for { for {
timestamp := int(time.Now().Unix()) timestamp := int(time.Now().Unix())
err := s.VwsConn.WriteJSON(map[string]int{ json := voiceHeartbeatOp{3, timestamp}
"op": 3,
"d": timestamp, err := s.VwsConn.WriteJSON(json)
})
if err != nil { if err != nil {
s.VoiceReady = false s.VoiceReady = false
fmt.Println(err) fmt.Println(err)
return // log error? return // log error?
} }
s.VoiceReady = true s.VoiceReady = true
<-ticker.C <-ticker.C
} }