Browse Source

Merge remote-tracking branch 'bwmarrin/develop' into pointers

Chris Rhodes 9 years ago
parent
commit
ea33680562
7 changed files with 215 additions and 53 deletions
  1. 2 2
      README.md
  2. 0 0
      examples/api_basic/api_basic.go
  3. 0 0
      examples/new_basic/new_basic.go
  4. 49 0
      message.go
  5. 5 40
      structs.go
  6. 127 0
      tests/discordgo_test.go
  7. 32 11
      voice.go

+ 2 - 2
README.md

@@ -63,8 +63,8 @@ that information in a nice format.
 Below is a list of examples and other projects using Discordgo.  Please submit 
 Below is a list of examples and other projects using Discordgo.  Please submit 
 an issue if you would like your project added or removed from this list 
 an issue if you would like your project added or removed from this list 
 
 
-- [Basic - New](https://github.com/bwmarrin/discordgo/tree/develop/example/new_basic) A basic example using the easy New() helper function
-- [Basic - API](https://github.com/bwmarrin/discordgo/tree/develop/example/api_basic) A basic example using the low level API functions.
+- [Basic - New](https://github.com/bwmarrin/discordgo/tree/develop/examples/new_basic) A basic example using the easy New() helper function
+- [Basic - API](https://github.com/bwmarrin/discordgo/tree/develop/examples/api_basic) A basic example using the low level API functions.
 - [Bruxism](https://github.com/iopred/bruxism) A chat bot for YouTube and Discord
 - [Bruxism](https://github.com/iopred/bruxism) A chat bot for YouTube and Discord
 - [GoGerard](https://github.com/GoGerard/GoGerard) A modern bot for Discord
 - [GoGerard](https://github.com/GoGerard/GoGerard) A modern bot for Discord
 - [Digo](https://github.com/sethdmoore/digo) A pluggable bot for your Discord server
 - [Digo](https://github.com/sethdmoore/digo) A pluggable bot for your Discord server

example/api_basic/api_basic.go → examples/api_basic/api_basic.go


example/new_basic/new_basic.go → examples/new_basic/new_basic.go


+ 49 - 0
message.go

@@ -0,0 +1,49 @@
+// Discordgo - Discord bindings for Go
+// Available at https://github.com/bwmarrin/discordgo
+
+// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains code related to the Message struct
+
+package discordgo
+
+import (
+	"fmt"
+	"strings"
+)
+
+// A Message stores all data related to a specific Discord message.
+type Message struct {
+	ID              string        `json:"id"`
+	Author          User          `json:"author"`
+	Content         string        `json:"content"`
+	Attachments     []*Attachment `json:"attachments"`
+	Tts             bool          `json:"tts"`
+	Embeds          []*Embed      `json:"embeds"`
+	Timestamp       string        `json:"timestamp"`
+	MentionEveryone bool          `json:"mention_everyone"`
+	EditedTimestamp string        `json:"edited_timestamp"`
+	Mentions        []*User       `json:"mentions"`
+	ChannelID       string        `json:"channel_id"`
+}
+
+// An Attachment stores data for message attachments.
+type Attachment struct { //TODO figure this out
+}
+
+// An Embed stores data for message embeds.
+type Embed struct { // TODO figure this out
+}
+
+// ContentWithMentionsReplaced will replace all @<id> mentions with the
+// username of the mention.
+func (m *Message) ContentWithMentionsReplaced() string {
+	content := m.Content
+	for _, user := range m.Mentions {
+		content = strings.Replace(content, fmt.Sprintf("<@%s>", user.ID),
+			fmt.Sprintf("@%s", user.Username), -1)
+	}
+	return content
+}

+ 5 - 40
structs.go

@@ -13,9 +13,7 @@ package discordgo
 
 
 import (
 import (
 	"encoding/json"
 	"encoding/json"
-	"fmt"
 	"net"
 	"net"
-	"strings"
 	"sync"
 	"sync"
 	"time"
 	"time"
 
 
@@ -27,9 +25,8 @@ import (
 // Debug : If set to ture debug logging will be displayed.
 // Debug : If set to ture debug logging will be displayed.
 type Session struct {
 type Session struct {
 	// General configurable settings.
 	// General configurable settings.
-	Token       string // Authentication token for this session
-	Debug       bool   // Debug for printing JSON request/responses
-	AutoMention bool   // if set to True, ChannelSendMessage will auto mention <@ID>
+	Token string // Authentication token for this session
+	Debug bool   // Debug for printing JSON request/responses
 
 
 	// Settable Callback functions for Websocket Events
 	// Settable Callback functions for Websocket Events
 	OnEvent                   func(*Session, *Event)
 	OnEvent                   func(*Session, *Event)
@@ -78,13 +75,14 @@ type Session struct {
 	// Everything below here is used for Voice testing.
 	// Everything below here is used for Voice testing.
 	// This stuff is almost guarenteed to change a lot
 	// This stuff is almost guarenteed to change a lot
 	// and is even a bit hackish right now.
 	// and is even a bit hackish right now.
+	Voice      *voice
 	VwsConn    *websocket.Conn // new for voice
 	VwsConn    *websocket.Conn // new for voice
 	VSessionID string
 	VSessionID string
 	VToken     string
 	VToken     string
 	VEndpoint  string
 	VEndpoint  string
 	VGuildID   string
 	VGuildID   string
 	VChannelID string
 	VChannelID string
-	Vop2       VoiceOP2
+	Vop2       voiceOP2
 	UDPConn    *net.UDPConn
 	UDPConn    *net.UDPConn
 
 
 	// Managed state object, updated with events.
 	// Managed state object, updated with events.
@@ -101,39 +99,6 @@ type Session struct {
 	listenChan chan struct{}
 	listenChan chan struct{}
 }
 }
 
 
-// A Message stores all data related to a specific Discord message.
-type Message struct {
-	ID              string        `json:"id"`
-	Author          User          `json:"author"`
-	Content         string        `json:"content"`
-	Attachments     []*Attachment `json:"attachments"`
-	Tts             bool          `json:"tts"`
-	Embeds          []*Embed      `json:"embeds"`
-	Timestamp       string        `json:"timestamp"`
-	MentionEveryone bool          `json:"mention_everyone"`
-	EditedTimestamp string        `json:"edited_timestamp"`
-	Mentions        []*User       `json:"mentions"`
-	ChannelID       string        `json:"channel_id"`
-}
-
-// ContentWithMentionsReplaced will replace all @<id> mentions with the
-// username of the mention.
-func (m *Message) ContentWithMentionsReplaced() string {
-	content := m.Content
-	for _, user := range m.Mentions {
-		content = strings.Replace(content, fmt.Sprintf("<@%s>", user.ID), fmt.Sprintf("@%s", user.Username), -1)
-	}
-	return content
-}
-
-// An Attachment stores data for message attachments.
-type Attachment struct { //TODO figure this out
-}
-
-// An Embed stores data for message embeds.
-type Embed struct { // TODO figure this out
-}
-
 // A VoiceRegion stores data for a specific voice region server.
 // A VoiceRegion stores data for a specific voice region server.
 type VoiceRegion struct {
 type VoiceRegion struct {
 	ID       string `json:"id"`
 	ID       string `json:"id"`
@@ -302,7 +267,7 @@ type Settings struct {
 type Event struct {
 type Event struct {
 	Type      string          `json:"t"`
 	Type      string          `json:"t"`
 	State     int             `json:"s"`
 	State     int             `json:"s"`
-	Operation int             `json:"o"`
+	Operation int             `json:"op"`
 	Direction int             `json:"dir"`
 	Direction int             `json:"dir"`
 	RawData   json.RawMessage `json:"d"`
 	RawData   json.RawMessage `json:"d"`
 }
 }

+ 127 - 0
tests/discordgo_test.go

@@ -0,0 +1,127 @@
+package discordgo_test
+
+import (
+	"os"
+	"runtime"
+	"testing"
+	"time"
+
+	. "github.com/bwmarrin/discordgo"
+)
+
+//////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////// VARS NEEDED FOR TESTING
+var (
+	dg *Session // Stores global discordgo session
+
+	envToken    string = os.Getenv("DG_TOKEN")    // Token to use when authenticating
+	envUsername string = os.Getenv("DG_USERNAME") // Username to use when authenticating
+	envPassword string = os.Getenv("DG_PASSWORD") // Password to use when authenticating
+	envGuild    string = os.Getenv("DG_GUILD")    // Guild ID to use for tests
+	envChannel  string = os.Getenv("DG_CHANNEL")  // Channel ID to use for tests
+	envUser     string = os.Getenv("DG_USER")     // User ID to use for tests
+	envAdmin    string = os.Getenv("DG_ADMIN")    // User ID of admin user to use for tests
+)
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////// HELPER FUNCTIONS USED FOR TESTING
+
+// This waits x time for the check bool to be the want bool
+func waitBoolEqual(timeout time.Duration, check *bool, want bool) bool {
+
+	start := time.Now()
+	for {
+		if *check == want {
+			return true
+		}
+
+		if time.Since(start) > timeout {
+			return false
+		}
+
+		runtime.Gosched()
+	}
+}
+
+// Checks if we're connected to Discord
+func isConnected() bool {
+
+	if dg == nil {
+		return false
+	}
+
+	if dg.Token == "" {
+		return false
+	}
+
+	// Need a way to see if the ws connection is nil
+
+	if !waitBoolEqual(10*time.Second, &dg.DataReady, true) {
+		return false
+	}
+
+	return true
+}
+
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////// START OF TESTS
+
+// TestNew tests the New() function without any arguments.  This should return
+// a valid Session{} struct and no errors.
+func TestNew(t *testing.T) {
+
+	_, err := New()
+	if err != nil {
+		t.Errorf("New() returned error: %+v", err)
+	}
+}
+
+// TestNewUserPass tests the New() function with a username and password.
+// This should return a valid Session{}, a valid Session.Token, and open
+// a websocket connection to Discord.
+func TestNewUserPass(t *testing.T) {
+
+	if isConnected() {
+		t.Skip("Skipping New(username,password), already connected.")
+	}
+
+	if envUsername == "" || envPassword == "" {
+		t.Skip("Skipping New(username,password), DG_USERNAME or DG_PASSWORD not set")
+		return
+	}
+	// Not testing yet.
+}
+
+// TestNewToken tests the New() function with a Token.  This should return
+// the same as the TestNewUserPass function.
+func TestNewToken(t *testing.T) {
+
+	if isConnected() {
+		t.Skip("Skipping New(token), already connected.")
+	}
+
+	if envToken == "" {
+		t.Skip("Skipping New(token), DG_TOKEN not set")
+	}
+
+	d, err := New(envToken)
+	if err != nil {
+		t.Fatalf("New(envToken) returned error: %+v", err)
+	}
+
+	if d == nil {
+		t.Fatal("New(envToken), d is nil, should be Session{}")
+	}
+
+	if d.Token == "" {
+		t.Fatal("New(envToken), d.Token is empty, should be a valid Token.")
+	}
+
+	if !waitBoolEqual(10*time.Second, &d.DataReady, true) {
+		t.Fatal("New(envToken), d.DataReady is false after 10 seconds.  Should be true.")
+	}
+
+	t.Log("Successfully connected to Discord.")
+	dg = d
+
+}

+ 32 - 11
voice.go

@@ -18,23 +18,44 @@ import (
 	"fmt"
 	"fmt"
 	"net"
 	"net"
 	"strings"
 	"strings"
+	"sync"
 	"time"
 	"time"
 
 
 	"github.com/gorilla/websocket"
 	"github.com/gorilla/websocket"
 )
 )
 
 
-// A VEvent is the initial structure for voice websocket events.  I think
-// I can reuse the data websocket structure here.
-type VEvent struct {
-	Type      string          `json:"t"`
-	State     int             `json:"s"`
-	Operation int             `json:"op"`
-	RawData   json.RawMessage `json:"d"`
+// A Voice struct holds all data and functions related to Discord Voice support.
+// NOTE: This is not used right at this moment, but it will be used soon.
+type voice struct {
+	Ready bool
+	WS    *voiceWS
+	UDP   *voiceUDP
+
+	SessionID string
+	Token     string
+	Endpoint  string
+	GuildID   string
+	ChannelID string
+	OP2       *voiceOP2
 }
 }
 
 
-// A VoiceOP2 stores the data for voice operation 2 websocket events
+type voiceWS struct {
+	Ready bool
+	Chan  chan struct{}
+	Lock  sync.Mutex
+	Conn  *websocket.Conn
+}
+
+type voiceUDP struct {
+	Ready bool
+	Chan  chan struct{}
+	Lock  sync.Mutex
+	Conn  *net.UDPConn
+}
+
+// A voiceOP2 stores the data for voice operation 2 websocket events
 // which is sort of like the voice READY packet
 // which is sort of like the voice READY packet
-type VoiceOP2 struct {
+type voiceOP2 struct {
 	SSRC              uint32        `json:"ssrc"`
 	SSRC              uint32        `json:"ssrc"`
 	Port              int           `json:"port"`
 	Port              int           `json:"port"`
 	Modes             []string      `json:"modes"`
 	Modes             []string      `json:"modes"`
@@ -117,7 +138,7 @@ func (s *Session) VoiceEvent(messageType int, message []byte) (err error) {
 		printJSON(message)
 		printJSON(message)
 	}
 	}
 
 
-	var e VEvent
+	var e Event
 	if err := json.Unmarshal(message, &e); err != nil {
 	if err := json.Unmarshal(message, &e); err != nil {
 		return err
 		return err
 	}
 	}
@@ -125,7 +146,7 @@ func (s *Session) VoiceEvent(messageType int, message []byte) (err error) {
 	switch e.Operation {
 	switch e.Operation {
 
 
 	case 2: // READY packet
 	case 2: // READY packet
-		var st VoiceOP2
+		var st voiceOP2
 		if err := json.Unmarshal(e.RawData, &st); err != nil {
 		if err := json.Unmarshal(e.RawData, &st); err != nil {
 			fmt.Println(e.Type, err)
 			fmt.Println(e.Type, err)
 			printJSON(e.RawData) // TODO: Better error logginEventg
 			printJSON(e.RawData) // TODO: Better error logginEventg