forked from pothtonswer/discordmuffin
Merge remote-tracking branch 'bwmarrin/develop' into pointers
This commit is contained in:
commit
ea33680562
7 changed files with 215 additions and 53 deletions
|
@ -63,8 +63,8 @@ that information in a nice format.
|
|||
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
|
||||
|
||||
- [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
|
||||
- [GoGerard](https://github.com/GoGerard/GoGerard) A modern bot for Discord
|
||||
- [Digo](https://github.com/sethdmoore/digo) A pluggable bot for your Discord server
|
||||
|
|
49
message.go
Normal file
49
message.go
Normal file
|
@ -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
|
||||
}
|
41
structs.go
41
structs.go
|
@ -13,9 +13,7 @@ package discordgo
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -29,7 +27,6 @@ type Session struct {
|
|||
// 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>
|
||||
|
||||
// Settable Callback functions for Websocket Events
|
||||
OnEvent func(*Session, *Event)
|
||||
|
@ -78,13 +75,14 @@ type Session struct {
|
|||
// Everything below here is used for Voice testing.
|
||||
// This stuff is almost guarenteed to change a lot
|
||||
// and is even a bit hackish right now.
|
||||
Voice *voice
|
||||
VwsConn *websocket.Conn // new for voice
|
||||
VSessionID string
|
||||
VToken string
|
||||
VEndpoint string
|
||||
VGuildID string
|
||||
VChannelID string
|
||||
Vop2 VoiceOP2
|
||||
Vop2 voiceOP2
|
||||
UDPConn *net.UDPConn
|
||||
|
||||
// Managed state object, updated with events.
|
||||
|
@ -101,39 +99,6 @@ type Session 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.
|
||||
type VoiceRegion struct {
|
||||
ID string `json:"id"`
|
||||
|
@ -302,7 +267,7 @@ type Settings struct {
|
|||
type Event struct {
|
||||
Type string `json:"t"`
|
||||
State int `json:"s"`
|
||||
Operation int `json:"o"`
|
||||
Operation int `json:"op"`
|
||||
Direction int `json:"dir"`
|
||||
RawData json.RawMessage `json:"d"`
|
||||
}
|
||||
|
|
127
tests/discordgo_test.go
Normal file
127
tests/discordgo_test.go
Normal file
|
@ -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
|
||||
|
||||
}
|
43
voice.go
43
voice.go
|
@ -18,23 +18,44 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"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
|
||||
type VoiceOP2 struct {
|
||||
type voiceOP2 struct {
|
||||
SSRC uint32 `json:"ssrc"`
|
||||
Port int `json:"port"`
|
||||
Modes []string `json:"modes"`
|
||||
|
@ -117,7 +138,7 @@ func (s *Session) VoiceEvent(messageType int, message []byte) (err error) {
|
|||
printJSON(message)
|
||||
}
|
||||
|
||||
var e VEvent
|
||||
var e Event
|
||||
if err := json.Unmarshal(message, &e); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -125,7 +146,7 @@ func (s *Session) VoiceEvent(messageType int, message []byte) (err error) {
|
|||
switch e.Operation {
|
||||
|
||||
case 2: // READY packet
|
||||
var st VoiceOP2
|
||||
var st voiceOP2
|
||||
if err := json.Unmarshal(e.RawData, &st); err != nil {
|
||||
fmt.Println(e.Type, err)
|
||||
printJSON(e.RawData) // TODO: Better error logginEventg
|
||||
|
|
Loading…
Reference in a new issue