From 074d1bcdae4c42d3918d4306754d13444bdecd43 Mon Sep 17 00:00:00 2001 From: Bruce Marriner Date: Thu, 12 Nov 2015 23:25:48 -0600 Subject: [PATCH] Huge update to Websocket support. Changed "Server" to "Guild" to remain consistant with Discords API naming. --- channel.go | 28 +++++---- guild.go | 81 ++++++++++++++++++++++++++ restapi.go | 4 +- session.go | 39 +++++++------ users.go | 2 +- wsapi.go | 168 ++++++++++++++++++++++++++++++++++++++++++++++++----- 6 files changed, 274 insertions(+), 48 deletions(-) create mode 100644 guild.go diff --git a/channel.go b/channel.go index 518d6a6..4b59dae 100644 --- a/channel.go +++ b/channel.go @@ -1,16 +1,24 @@ package discordgo type Channel struct { - Server_id int `json:"guild_id,string,omitempty"` - Id int `json:"id,string"` - Name string `json:"name"` - Topic string `json:"topic"` - Position int `json:"position"` - Last_message_id int `json:"last_message_id,string"` - Type string `json:"type"` - Is_private bool `json:"is_private"` - Permission_overwrites string `json:"-"` // ignored for now - Session *Session + GuildId int `json:"guild_id,string,omitempty"` + Id int `json:"id,string"` + Name string `json:"name"` + Topic string `json:"topic"` + Position int `json:"position"` + Type string `json:"type"` + PermissionOverwrites []PermissionOverwrite `json:"permission_overwrites"` + IsPrivate bool `json:"is_private"` + LastMessageId int `json:"last_message_id,string"` + Recipient User `json:"recipient"` + Session *Session +} + +type PermissionOverwrite struct { + Type string `json:"type"` + Id int `json:"id,string"` + Deny int `json:"deny"` + Allow int `json:"allow"` } /* diff --git a/guild.go b/guild.go new file mode 100644 index 0000000..e0ea5d6 --- /dev/null +++ b/guild.go @@ -0,0 +1,81 @@ +package discordgo + +type Guild struct { + Id int `json:"id,string"` + Name string `json:"name"` + Icon string `json:"icon"` + Region string `json:"region"` + Joined_at string `json:"joined_at"` // make time stamp + Afk_timeout int `json:"afk_timeout"` + Afk_channel_id int `json:"afk_channel_id"` + Embed_channel_id int `json:"embed_channel_id"` + Embed_enabled bool `json:"embed_enabled"` + Owner_id int `json:"owner_id,string"` + Large bool `json:"large"` // ?? + JoinedAt string `json:"joined_at"` // make this a timestamp + Roles []Role `json:"roles"` + Members []Member `json:"members"` + Presences []Presence `json:"presences"` + Channels []Channel `json:"channels"` + VoiceStates []VoiceState `json:"voice_states"` + Session *Session // I got to be doing it wrong here. +} + +type VoiceState struct { + UserId int `json:"user_id,string"` + Suppress bool `json:"suppress"` + SessionId string `json:"session_id"` + SelfMute bool `json:"self_mute"` + SelfDeaf bool `json:"self_deaf"` + Mute bool `json:"mute"` + Deaf bool `json:"deaf"` + ChannelId int `json:"channel_id,string"` +} + +type Presence struct { + User User `json:"user"` + Status string `json:"status"` + GameId int `json:"game_id"` +} + +// TODO: Member vs User? +type Member struct { + GuildId int `json:"guild_id"` + JoinedAt string `json:"joined_at"` + Deaf bool `json:"deaf"` + mute bool `json:"mute"` + User User `json:"user"` + Roles []Role `json:"roles"` +} + +type Role struct { + Id int `json:"id,string"` + Name string `json:"name"` + Managed bool `json:"managed"` + Color int `json:"color"` + Hoist bool `json:"hoist"` + Position int `json:"position"` + Permissions int `json:"permissions"` +} + +// Channels returns an array of Channel structures for channels within +// this Server +/* +TODO: How to name these? If we make a variable to store +channels from READY packet, etc. We can't have a Channel +func? And which is better. Channels func gets live up +to date data on each call.. so, there is some benefit there. + +Maybe it should have both, but make the Channels check and +pull new data based on a cache time? + +func (s *Server) Channels() (c []Channel, err error) { + c, err = Channels(s.Session, s.Id) + return +} +*/ +/* + +func (s *Server) Members() (m []Users, err error) { +} +*/ diff --git a/restapi.go b/restapi.go index c504e1b..886dd00 100644 --- a/restapi.go +++ b/restapi.go @@ -162,8 +162,8 @@ func PrivateChannels(session *Session, userId string) (channels []Channel, err e return } -// Servers returns an array of Server structures for all servers for a user -func Servers(session *Session, userId string) (servers []Server, err error) { +// Guilds returns an array of Guild structures for all servers for a user +func Guilds(session *Session, userId string) (servers []Guild, err error) { body, err := Request(session, "GET", fmt.Sprintf("%s/%s/guilds", USERS, userId), ``) err = json.Unmarshal(body, &servers) diff --git a/session.go b/session.go index 3b44d35..2ef4e3f 100644 --- a/session.go +++ b/session.go @@ -18,24 +18,25 @@ type Session struct { // Settable Callback functions for Websocket Events OnEvent func(*Session, Event) // should Event be *Event? OnReady func(*Session, Ready) + OnTypingStart func(*Session, TypingStart) OnMessageCreate func(*Session, Message) - OnTypingStart func(*Session, Event) - OnMessageAck func(*Session, Event) - OnMessageUpdate func(*Session, Event) - OnMessageDelete func(*Session, Event) - OnPresenceUpdate func(*Session, Event) - OnChannelCreate func(*Session, Event) - OnChannelUpdate func(*Session, Event) - OnChannelDelete func(*Session, Event) - OnGuildCreate func(*Session, Event) - OnGuildDelete func(*Session, Event) - OnGuildMemberAdd func(*Session, Event) - OnGuildMemberRemove func(*Session, Event) - OnGuildMemberDelete func(*Session, Event) // which is it? - OnGuildMemberUpdate func(*Session, Event) - OnGuildRoleCreate func(*Session, Event) - OnGuildRoleDelete func(*Session, Event) - OnGuildIntegrationsUpdate func(*Session, Event) + OnMessageUpdate func(*Session, Message) + OnMessageDelete func(*Session, MessageDelete) + OnMessageAck func(*Session, MessageAck) + OnPresenceUpdate func(*Session, PresenceUpdate) + OnVoiceStateUpdate func(*Session, VoiceState) + OnChannelCreate func(*Session, Channel) + OnChannelUpdate func(*Session, Channel) + OnChannelDelete func(*Session, Channel) + OnGuildCreate func(*Session, Guild) + OnGuildDelete func(*Session, Guild) + OnGuildMemberAdd func(*Session, Member) + OnGuildMemberRemove func(*Session, Member) + OnGuildMemberDelete func(*Session, Member) // which is it? + OnGuildMemberUpdate func(*Session, Member) + OnGuildRoleCreate func(*Session, Role) + OnGuildRoleDelete func(*Session, Role) + OnGuildIntegrationsUpdate func(*Session, GuildIntegrationsUpdate) // OnMessageCreate func(Session, Event, Message) // ^^ Any value to passing session, event, message? @@ -69,8 +70,8 @@ func (session *Session) PrivateChannels() (channels []Channel, err error) { return } -func (session *Session) Servers() (servers []Server, err error) { - servers, err = Servers(session, "@me") +func (session *Session) Guilds() (servers []Guild, err error) { + servers, err = Guilds(session, "@me") return } diff --git a/users.go b/users.go index cab8a8c..ff4c6fe 100644 --- a/users.go +++ b/users.go @@ -14,6 +14,6 @@ type PrivateChannel struct { IsPrivate bool `json:"is_private"` LastMessageId int `json:"last_message_id,string"` Recipient User `json:"recipient"` -} +} // merge with channel? // PM function to PM a user. diff --git a/wsapi.go b/wsapi.go index f87855c..8e45b05 100644 --- a/wsapi.go +++ b/wsapi.go @@ -37,7 +37,7 @@ type Ready struct { User User `json:"user"` ReadState []ReadState PrivateChannels []PrivateChannel - Servers []Server + Guilds []Guild } // ReadState might need to move? Gives me the read status @@ -48,6 +48,34 @@ type ReadState struct { ID int `json:"id,string"` } +type TypingStart struct { + UserId int `json:"user_id,string"` + ChannelId int `json:"channel_id,string"` + Timestamp int `json:"timestamp"` +} + +type PresenceUpdate struct { + User User `json:"user"` + Status string `json:"status"` + Roles []Role `json:"roles"` + GuildId int `json:"guild_id,string"` + GameId int `json:"game_id"` +} + +type MessageAck struct { + MessageId int `json:"message_id,string"` + ChannelId int `json:"channel_id,string"` +} + +type MessageDelete struct { + Id int `json:"id,string"` + ChannelId int `json:"channel_id,string"` +} // so much like MessageAck.. + +type GuildIntegrationsUpdate struct { + GuildId int `json:"guild_id,string"` +} + // Open a websocket connection to Discord func Open(s *Session) (err error) { @@ -139,70 +167,178 @@ func event(s *Session, messageType int, message []byte) (err error) { if s.OnReady != nil { var st Ready if err := json.Unmarshal(e.RawData, &st); err != nil { + printJSON(e.RawData) // TODO: Better error logging return err } s.OnReady(s, st) return } + case "VOICE_STATE_UPDATE": + if s.OnVoiceStateUpdate != nil { + var st VoiceState + if err := json.Unmarshal(e.RawData, &st); err != nil { + printJSON(e.RawData) // TODO: Better error logging + return err + } + s.OnVoiceStateUpdate(s, st) + return + } + case "PRESENCE_UPDATE": + if s.OnPresenceUpdate != nil { + var st PresenceUpdate + if err := json.Unmarshal(e.RawData, &st); err != nil { + printJSON(e.RawData) // TODO: Better error logging + return err + } + s.OnPresenceUpdate(s, st) + return + } case "TYPING_START": if s.OnTypingStart != nil { + var st TypingStart + if err := json.Unmarshal(e.RawData, &st); err != nil { + printJSON(e.RawData) // TODO: Better error logging + return err + } + s.OnTypingStart(s, st) + return } case "MESSAGE_CREATE": if s.OnMessageCreate != nil { var st Message if err := json.Unmarshal(e.RawData, &st); err != nil { + printJSON(e.RawData) // TODO: Better error logging return err } s.OnMessageCreate(s, st) return } - case "MESSAGE_ACK": - if s.OnMessageAck != nil { - } case "MESSAGE_UPDATE": if s.OnMessageUpdate != nil { + var st Message + if err := json.Unmarshal(e.RawData, &st); err != nil { + printJSON(e.RawData) // TODO: Better error logging + return err + } + s.OnMessageUpdate(s, st) + return } case "MESSAGE_DELETE": if s.OnMessageDelete != nil { + var st MessageDelete + if err := json.Unmarshal(e.RawData, &st); err != nil { + printJSON(e.RawData) // TODO: Better error logging + return err + } + s.OnMessageDelete(s, st) } - case "PRESENCE_UPDATE": - if s.OnPresenceUpdate != nil { + case "MESSAGE_ACK": + if s.OnMessageAck != nil { + var st MessageAck + if err := json.Unmarshal(e.RawData, &st); err != nil { + printJSON(e.RawData) // TODO: Better error logging + return err + } + s.OnMessageAck(s, st) + return } case "CHANNEL_CREATE": if s.OnChannelCreate != nil { + var st Channel + if err := json.Unmarshal(e.RawData, &st); err != nil { + printJSON(e.RawData) // TODO: Better error logginEventg + return err + } + s.OnChannelCreate(s, st) + return } case "CHANNEL_UPDATE": if s.OnChannelUpdate != nil { + var st Channel + if err := json.Unmarshal(e.RawData, &st); err != nil { + printJSON(e.RawData) // TODO: Better error logginEventg + return err + } + s.OnChannelUpdate(s, st) + return } case "CHANNEL_DELETE": if s.OnChannelDelete != nil { + var st Channel + if err := json.Unmarshal(e.RawData, &st); err != nil { + printJSON(e.RawData) // TODO: Better error logginEventg + return err + } + s.OnChannelDelete(s, st) + return } case "GUILD_CREATE": if s.OnGuildCreate != nil { + var st Guild + if err := json.Unmarshal(e.RawData, &st); err != nil { + printJSON(e.RawData) // TODO: Better error logginEventg + return err + } + s.OnGuildCreate(s, st) + return } case "GUILD_DELETE": if s.OnGuildDelete != nil { + var st Guild + if err := json.Unmarshal(e.RawData, &st); err != nil { + printJSON(e.RawData) // TODO: Better error logginEventg + return err + } + s.OnGuildDelete(s, st) + return } case "GUILD_MEMBER_ADD": if s.OnGuildMemberAdd != nil { + var st Member + if err := json.Unmarshal(e.RawData, &st); err != nil { + printJSON(e.RawData) // TODO: Better error logginEventg + return err + } + s.OnGuildMemberAdd(s, st) + return } - case "GUILD_MEMBER_REMOVE": // which is it. + case "GUILD_MEMBER_REMOVE": if s.OnGuildMemberRemove != nil { - } - case "GUILD_MEMBER_DELETE": - if s.OnGuildMemberDelete != nil { + var st Member + if err := json.Unmarshal(e.RawData, &st); err != nil { + printJSON(e.RawData) // TODO: Better error logginEventg + return err + } + s.OnGuildMemberRemove(s, st) + return } case "GUILD_MEMBER_UPDATE": if s.OnGuildMemberUpdate != nil { + var st Member + if err := json.Unmarshal(e.RawData, &st); err != nil { + printJSON(e.RawData) // TODO: Better error logginEventg + return err + } + s.OnGuildMemberUpdate(s, st) + return } - case "GUILD_ROLE_CREATE": - if s.OnGuildRoleCreate != nil { - } - case "GUILD_ROLE_DELETE": - if s.OnGuildRoleDelete != nil { - } + /* + case "GUILD_ROLE_CREATE": + if s.OnGuildRoleCreate != nil { + } + case "GUILD_ROLE_DELETE": + if s.OnGuildRoleDelete != nil { + } + */ case "GUILD_INTEGRATIONS_UPDATE": if s.OnGuildIntegrationsUpdate != nil { + var st GuildIntegrationsUpdate + if err := json.Unmarshal(e.RawData, &st); err != nil { + printJSON(e.RawData) // TODO: Better error logginEventg + return err + } + s.OnGuildIntegrationsUpdate(s, st) + return } default: fmt.Println("UNKNOWN EVENT: ", e.Type)