Added member list support
This commit is contained in:
parent
afed1e13ad
commit
cdd9b68043
|
@ -10,8 +10,8 @@ import (
|
|||
)
|
||||
|
||||
type Category struct {
|
||||
id discord.Snowflake
|
||||
guildID discord.Snowflake
|
||||
id discord.ChannelID
|
||||
guildID discord.GuildID
|
||||
session *Session
|
||||
}
|
||||
|
||||
|
|
32
channel.go
32
channel.go
|
@ -37,16 +37,16 @@ func filterAccessible(s *Session, chs []discord.Channel) []discord.Channel {
|
|||
return filtered
|
||||
}
|
||||
|
||||
func filterCategory(chs []discord.Channel, catID discord.Snowflake) []discord.Channel {
|
||||
func filterCategory(chs []discord.Channel, catID discord.ChannelID) []discord.Channel {
|
||||
var filtered = chs[:0]
|
||||
var catvalid = catID.Valid()
|
||||
var catvalid = catID.IsValid()
|
||||
|
||||
for _, ch := range chs {
|
||||
switch {
|
||||
// If the given ID is not valid, then we look for channels with
|
||||
// similarly invalid category IDs, because yes, Discord really sends
|
||||
// inconsistent responses.
|
||||
case !catvalid && !ch.CategoryID.Valid():
|
||||
case !catvalid && !ch.CategoryID.IsValid():
|
||||
fallthrough
|
||||
// Basic comparison.
|
||||
case ch.CategoryID == catID:
|
||||
|
@ -60,8 +60,8 @@ func filterCategory(chs []discord.Channel, catID discord.Snowflake) []discord.Ch
|
|||
}
|
||||
|
||||
type Channel struct {
|
||||
id discord.Snowflake
|
||||
guildID discord.Snowflake
|
||||
id discord.ChannelID
|
||||
guildID discord.GuildID
|
||||
session *Session
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,7 @@ func (ch *Channel) messages() ([]discord.Message, error) {
|
|||
}
|
||||
|
||||
func (ch *Channel) guild() (*discord.Guild, error) {
|
||||
if ch.guildID.Valid() {
|
||||
if ch.guildID.IsValid() {
|
||||
return ch.session.Guild(ch.guildID)
|
||||
}
|
||||
return nil, errors.New("channel not in a guild")
|
||||
|
@ -134,7 +134,7 @@ func (ch *Channel) Name() text.Rich {
|
|||
|
||||
func (ch *Channel) Nickname(ctx context.Context, labeler cchat.LabelContainer) (func(), error) {
|
||||
// We don't have a nickname if we're not in a guild.
|
||||
if !ch.guildID.Valid() {
|
||||
if !ch.guildID.IsValid() {
|
||||
return func() {}, nil
|
||||
}
|
||||
|
||||
|
@ -199,7 +199,7 @@ func (ch *Channel) JoinServer(ctx context.Context, ct cchat.MessagesContainer) (
|
|||
|
||||
var constructor func(discord.Message) cchat.MessageCreate
|
||||
|
||||
if ch.guildID.Valid() {
|
||||
if ch.guildID.IsValid() {
|
||||
// Create the backlog without any member information.
|
||||
g, err := state.Guild(ch.guildID)
|
||||
if err != nil {
|
||||
|
@ -295,7 +295,7 @@ func (ch *Channel) MessageEditable(id string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
m, err := ch.session.Store.Message(ch.id, s)
|
||||
m, err := ch.session.Store.Message(ch.id, discord.MessageID(s))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
@ -310,7 +310,7 @@ func (ch *Channel) RawMessageContent(id string) (string, error) {
|
|||
return "", errors.Wrap(err, "Failed to parse ID")
|
||||
}
|
||||
|
||||
m, err := ch.session.Store.Message(ch.id, s)
|
||||
m, err := ch.session.Store.Message(ch.id, discord.MessageID(s))
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "Failed to get the message")
|
||||
}
|
||||
|
@ -325,7 +325,7 @@ func (ch *Channel) EditMessage(id, content string) error {
|
|||
return errors.Wrap(err, "Failed to parse ID")
|
||||
}
|
||||
|
||||
_, err = ch.session.EditText(ch.id, s, content)
|
||||
_, err = ch.session.EditText(ch.id, discord.MessageID(s), content)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -343,7 +343,7 @@ func (ch *Channel) DoMessageAction(action, id string) error {
|
|||
|
||||
switch action {
|
||||
case ActionDelete:
|
||||
return ch.session.DeleteMessage(ch.id, s)
|
||||
return ch.session.DeleteMessage(ch.id, discord.MessageID(s))
|
||||
default:
|
||||
return ErrUnknownAction
|
||||
}
|
||||
|
@ -355,7 +355,7 @@ func (ch *Channel) MessageActions(id string) []string {
|
|||
return nil
|
||||
}
|
||||
|
||||
m, err := ch.session.Store.Message(ch.id, s)
|
||||
m, err := ch.session.Store.Message(ch.id, discord.MessageID(s))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -384,9 +384,9 @@ func (ch *Channel) MessageActions(id string) []string {
|
|||
|
||||
// canManageMessages returns whether or not the user is allowed to manage
|
||||
// messages.
|
||||
func (ch *Channel) canManageMessages(userID discord.Snowflake) bool {
|
||||
func (ch *Channel) canManageMessages(userID discord.UserID) bool {
|
||||
// If we're not in a guild, then clearly we cannot.
|
||||
if !ch.guildID.Valid() {
|
||||
if !ch.guildID.IsValid() {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -438,7 +438,7 @@ func (ch *Channel) TypingSubscribe(ti cchat.TypingIndicator) (func(), error) {
|
|||
// muted returns if this channel is muted. This includes the channel's category
|
||||
// and guild.
|
||||
func (ch *Channel) muted() bool {
|
||||
return (ch.guildID.Valid() && ch.session.MutedState.Guild(ch.guildID, false)) ||
|
||||
return (ch.guildID.IsValid() && ch.session.MutedState.Guild(ch.guildID, false)) ||
|
||||
ch.session.MutedState.Channel(ch.id) ||
|
||||
ch.session.MutedState.Category(ch.id)
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ func (ch *SendableChannel) completeMentions(word string) (entries []cchat.Comple
|
|||
|
||||
// Keep track of the number of authors.
|
||||
// TODO: fix excess allocations
|
||||
var authors = make(map[discord.Snowflake]struct{}, MaxCompletion)
|
||||
var authors = make(map[discord.UserID]struct{}, MaxCompletion)
|
||||
|
||||
for _, msg := range msgs {
|
||||
// If we've already added the author into the list, then skip.
|
||||
|
@ -65,7 +65,7 @@ func (ch *SendableChannel) completeMentions(word string) (entries []cchat.Comple
|
|||
var match = strings.ToLower(word)
|
||||
|
||||
// If we're not in a guild, then we can check the list of recipients.
|
||||
if !ch.guildID.Valid() {
|
||||
if !ch.guildID.IsValid() {
|
||||
c, err := ch.self()
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -127,7 +127,7 @@ func (ch *SendableChannel) completeChannels(word string) (entries []cchat.Comple
|
|||
}
|
||||
|
||||
// Ignore if we're not in a guild.
|
||||
if !ch.guildID.Valid() {
|
||||
if !ch.guildID.IsValid() {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,7 @@ func (ch *SendableChannel) completeChannels(word string) (entries []cchat.Comple
|
|||
}
|
||||
|
||||
var category string
|
||||
if channel.CategoryID.Valid() {
|
||||
if channel.CategoryID.IsValid() {
|
||||
if c, _ := ch.session.Store.Channel(channel.CategoryID); c != nil {
|
||||
category = c.Name
|
||||
}
|
||||
|
|
|
@ -1 +1,276 @@
|
|||
package discord
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/diamondburned/arikawa/discord"
|
||||
"github.com/diamondburned/arikawa/gateway"
|
||||
"github.com/diamondburned/cchat"
|
||||
"github.com/diamondburned/cchat-discord/segments"
|
||||
"github.com/diamondburned/cchat/text"
|
||||
"github.com/diamondburned/ningen/states/member"
|
||||
)
|
||||
|
||||
func seekPrevGroup(l *member.List, ix int) (item, group gateway.GuildMemberListOpItem) {
|
||||
l.ViewItems(func(items []gateway.GuildMemberListOpItem) {
|
||||
item = items[ix]
|
||||
|
||||
// Search backwards.
|
||||
for i := ix; i >= 0; i-- {
|
||||
if items[i].Group != nil {
|
||||
group = items[i]
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (ch *Channel) ListMembers(ctx context.Context, c cchat.MemberListContainer) (func(), error) {
|
||||
if !ch.guildID.IsValid() {
|
||||
return func() {}, nil
|
||||
}
|
||||
|
||||
cancel := ch.session.AddHandler(func(u *gateway.GuildMemberListUpdate) {
|
||||
l, err := ch.session.MemberState.GetMemberList(ch.guildID, ch.id)
|
||||
if err != nil {
|
||||
return // wat
|
||||
}
|
||||
|
||||
for _, ev := range u.Ops {
|
||||
switch ev.Op {
|
||||
case "SYNC":
|
||||
ch.checkSync(c)
|
||||
|
||||
case "INSERT", "UPDATE":
|
||||
item, group := seekPrevGroup(l, ev.Index)
|
||||
if item.Member != nil && group.Group != nil {
|
||||
c.SetMember(group.Group.ID, NewListMember(ev.Index, ch, item))
|
||||
}
|
||||
|
||||
case "DELETE":
|
||||
_, group := seekPrevGroup(l, ev.Index-1)
|
||||
if group.Group != nil {
|
||||
c.RemoveMember(group.Group.ID, strconv.Itoa(ev.Index))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
ch.session.MemberState.RequestMemberList(ch.guildID, ch.id, 0)
|
||||
return cancel, nil
|
||||
}
|
||||
|
||||
func (ch *Channel) checkSync(c cchat.MemberListContainer) {
|
||||
l, err := ch.session.MemberState.GetMemberList(ch.guildID, ch.id)
|
||||
if err != nil {
|
||||
ch.session.MemberState.RequestMemberList(ch.guildID, ch.id, 0)
|
||||
return
|
||||
}
|
||||
|
||||
var sectionKeys []string
|
||||
var sectionsMap map[string]*ListSection
|
||||
|
||||
l.ViewGroups(func(groups []gateway.GuildMemberListGroup) {
|
||||
sectionKeys = make([]string, 0, len(groups))
|
||||
sectionsMap = make(map[string]*ListSection, len(groups))
|
||||
|
||||
for _, group := range groups {
|
||||
sectionKeys = append(sectionKeys, group.ID)
|
||||
sectionsMap[group.ID] = NewListSection(l.ID(), ch, group)
|
||||
}
|
||||
|
||||
var sections = make([]cchat.MemberListSection, len(sectionKeys))
|
||||
for i, key := range sectionKeys {
|
||||
sections[i] = sectionsMap[key]
|
||||
}
|
||||
|
||||
c.SetSections(sections)
|
||||
})
|
||||
|
||||
l.ViewItems(func(items []gateway.GuildMemberListOpItem) {
|
||||
var group gateway.GuildMemberListGroup
|
||||
|
||||
for i, item := range items {
|
||||
switch {
|
||||
case item.Group != nil:
|
||||
group = *item.Group
|
||||
|
||||
case item.Member != nil:
|
||||
c.SetMember(group.ID, NewListMember(i, ch, item))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type ListMember struct {
|
||||
ix int // experiment with this being the index
|
||||
|
||||
// Keep stateful references to do on-demand loading.
|
||||
channel *Channel
|
||||
|
||||
// constant states
|
||||
userID discord.UserID
|
||||
roleID discord.RoleID
|
||||
origName string // use if cache is stale
|
||||
}
|
||||
|
||||
var _ cchat.ListMember = (*ListMember)(nil)
|
||||
|
||||
// NewListMember creates a new list member. it.Member must not be nil.
|
||||
func NewListMember(ix int, ch *Channel, it gateway.GuildMemberListOpItem) *ListMember {
|
||||
roleID, _ := discord.ParseSnowflake(it.Member.HoistedRole)
|
||||
|
||||
return &ListMember{
|
||||
ix: ix,
|
||||
channel: ch,
|
||||
userID: it.Member.User.ID,
|
||||
roleID: discord.RoleID(roleID),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ListMember) ID() string {
|
||||
return strconv.Itoa(l.ix)
|
||||
}
|
||||
|
||||
func (l *ListMember) Name() text.Rich {
|
||||
n, err := l.channel.session.MemberDisplayName(l.channel.guildID, l.userID)
|
||||
if err != nil {
|
||||
return text.Plain(l.origName)
|
||||
}
|
||||
|
||||
r, err := l.channel.session.State.Role(l.channel.guildID, l.roleID)
|
||||
if err != nil {
|
||||
return text.Plain(l.origName)
|
||||
}
|
||||
|
||||
return text.Rich{
|
||||
Content: n,
|
||||
Segments: []text.Segment{segments.NewColored(len(n), uint32(r.Color))},
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ListMember) Status() cchat.UserStatus {
|
||||
p, err := l.channel.session.State.Presence(l.channel.guildID, l.userID)
|
||||
if err != nil {
|
||||
return cchat.UnknownStatus
|
||||
}
|
||||
|
||||
switch p.Status {
|
||||
case discord.OnlineStatus:
|
||||
return cchat.OnlineStatus
|
||||
case discord.DoNotDisturbStatus:
|
||||
return cchat.BusyStatus
|
||||
case discord.IdleStatus:
|
||||
return cchat.AwayStatus
|
||||
case discord.OfflineStatus, discord.InvisibleStatus:
|
||||
return cchat.OfflineStatus
|
||||
default:
|
||||
return cchat.UnknownStatus
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ListMember) Secondary() text.Rich {
|
||||
p, err := l.channel.session.State.Presence(l.channel.guildID, l.userID)
|
||||
if err != nil {
|
||||
return text.Plain("")
|
||||
}
|
||||
|
||||
if p.Game != nil {
|
||||
return segments.FormatActivity(*p.Game)
|
||||
}
|
||||
|
||||
if len(p.Activities) > 0 {
|
||||
return segments.FormatActivity(p.Activities[0])
|
||||
}
|
||||
|
||||
return text.Plain("")
|
||||
}
|
||||
|
||||
type ListSection struct {
|
||||
// constant states
|
||||
listID string
|
||||
id string // roleID or online or offline
|
||||
name string
|
||||
total int
|
||||
|
||||
channel *Channel
|
||||
}
|
||||
|
||||
var (
|
||||
_ cchat.MemberListSection = (*ListSection)(nil)
|
||||
_ cchat.MemberListDynamicSection = (*ListSection)(nil)
|
||||
)
|
||||
|
||||
func NewListSection(listID string, ch *Channel, group gateway.GuildMemberListGroup) *ListSection {
|
||||
var name string
|
||||
|
||||
switch group.ID {
|
||||
case "online":
|
||||
name = "Online"
|
||||
case "offline":
|
||||
name = "Offline"
|
||||
default:
|
||||
p, err := discord.ParseSnowflake(group.ID)
|
||||
if err != nil {
|
||||
name = group.ID
|
||||
} else {
|
||||
r, err := ch.session.Role(ch.guildID, discord.RoleID(p))
|
||||
if err != nil {
|
||||
name = fmt.Sprintf("<@#%s>", p.String())
|
||||
} else {
|
||||
name = r.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &ListSection{
|
||||
listID: listID,
|
||||
channel: ch,
|
||||
id: group.ID,
|
||||
name: name,
|
||||
total: int(group.Count),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ListSection) ID() string {
|
||||
return s.id
|
||||
// return fmt.Sprintf("%s-%s", s.listID, s.name)
|
||||
}
|
||||
|
||||
func (s *ListSection) Name() text.Rich {
|
||||
return text.Rich{Content: s.name}
|
||||
}
|
||||
|
||||
func (s *ListSection) Total() int {
|
||||
return s.total
|
||||
}
|
||||
|
||||
// TODO: document that Load{More,Less} works more like a shifting window.
|
||||
|
||||
func (s *ListSection) LoadMore() bool {
|
||||
// This variable is here purely to make lines shorter.
|
||||
var memstate = s.channel.session.MemberState
|
||||
|
||||
chunk := memstate.GetMemberListChunk(s.channel.guildID, s.channel.id)
|
||||
if chunk < 0 {
|
||||
chunk = 0
|
||||
}
|
||||
|
||||
return memstate.RequestMemberList(s.channel.guildID, s.channel.id, chunk) != nil
|
||||
}
|
||||
|
||||
func (s *ListSection) LoadLess() bool {
|
||||
var memstate = s.channel.session.MemberState
|
||||
|
||||
chunk := memstate.GetMemberListChunk(s.channel.guildID, s.channel.id)
|
||||
if chunk <= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
memstate.RequestMemberList(s.channel.guildID, s.channel.id, chunk-1)
|
||||
return true
|
||||
}
|
||||
|
|
6
go.mod
6
go.mod
|
@ -3,9 +3,9 @@ module github.com/diamondburned/cchat-discord
|
|||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/diamondburned/arikawa v0.12.4
|
||||
github.com/diamondburned/cchat v0.0.46
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200717072304-e483f86c08e6
|
||||
github.com/diamondburned/arikawa v1.1.6
|
||||
github.com/diamondburned/cchat v0.0.48
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200815214034-638820c48066
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/go-test/deep v1.0.6
|
||||
github.com/pkg/errors v0.9.1
|
||||
|
|
18
go.sum
18
go.sum
|
@ -33,6 +33,10 @@ github.com/diamondburned/arikawa v0.10.5 h1:o5lBopooA+8cXlKZdct5qF0xztuZZ35phvQr
|
|||
github.com/diamondburned/arikawa v0.10.5/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
|
||||
github.com/diamondburned/arikawa v0.12.4 h1:lhWJqcGkIIMiOYWdsoEuGlri2UbMkzMeh+VfuJPkXt4=
|
||||
github.com/diamondburned/arikawa v0.12.4/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
|
||||
github.com/diamondburned/arikawa v1.1.4 h1:+fctDxzPCF84DFL+POBQgG4CuSpSepE09mdR3Y4vNRQ=
|
||||
github.com/diamondburned/arikawa v1.1.4/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
|
||||
github.com/diamondburned/arikawa v1.1.6 h1:Y/ioTYipS2v/NXfcAEhCnMTzrpxDjWlkjLKKcX29n6o=
|
||||
github.com/diamondburned/arikawa v1.1.6/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
|
||||
github.com/diamondburned/cchat v0.0.34 h1:BGiVxMRA9dmW3rLilIldBvjVan7eTTpaWCCfX9IKBYU=
|
||||
github.com/diamondburned/cchat v0.0.34/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
|
||||
github.com/diamondburned/cchat v0.0.35 h1:WiMGl8BQJgbP9E4xRxgLGlqUsHpTcJgDKDt8/6a7lBk=
|
||||
|
@ -57,6 +61,10 @@ github.com/diamondburned/cchat v0.0.45 h1:HMVSKx1h6lh2OenWaBTvMSK531hWaXAW7I0tKZ
|
|||
github.com/diamondburned/cchat v0.0.45/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
|
||||
github.com/diamondburned/cchat v0.0.46 h1:fzm2XA9uGasX0uaic1AFfUMGA53PlO+GGmkYbx49A5k=
|
||||
github.com/diamondburned/cchat v0.0.46/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
|
||||
github.com/diamondburned/cchat v0.0.47 h1:qU2TNeXlqru8za4qAgMPWTw6k8HGGOyic08GPPZJ6r8=
|
||||
github.com/diamondburned/cchat v0.0.47/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
|
||||
github.com/diamondburned/cchat v0.0.48 h1:MAzGzKY20JBh/LnirOZVPwbMq07xfqu4Lb4XsV9/sXQ=
|
||||
github.com/diamondburned/cchat v0.0.48/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200621014632-6babb812b249 h1:yP7kJ+xCGpDz6XbcfACJcju4SH1XDPwlrvbofz3lP8I=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200621014632-6babb812b249/go.mod h1:xW9hpBZsGi8KpAh10TyP+YQlYBo+Xc+2w4TR6N0951A=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200708085949-b64e350f3b8c h1:3h/kyk6HplYZF3zLi106itjYJWjbuMK/twijeGLEy2M=
|
||||
|
@ -83,6 +91,16 @@ github.com/diamondburned/ningen v0.1.1-0.20200717070406-6dc482b394c0 h1:DkzeHISw
|
|||
github.com/diamondburned/ningen v0.1.1-0.20200717070406-6dc482b394c0/go.mod h1:Sunqp1b9Tc0+DtWKslhf83Zepgj/TELB6h8J9HZCPqQ=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200717072304-e483f86c08e6 h1:YN0cj0aOCa+tKmx0aD5qsbSYaIJnyrA0/+eygMKP+/w=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200717072304-e483f86c08e6/go.mod h1:Sunqp1b9Tc0+DtWKslhf83Zepgj/TELB6h8J9HZCPqQ=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200814175234-6d546fac7724 h1:889IwdXZdIJlwlARBHZ2xxZ05Qfjd0yrVnpivyjfxTo=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200814175234-6d546fac7724/go.mod h1:Lcgkgu/QfaTqnBQqYb2LlnhM9aR509uEt07y61UQNGg=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200814183847-6722b606d3e1 h1:t3UPOrtdabeRqlHN+KIIht9MI6BdyCil7r5A8kz9hq4=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200814183847-6722b606d3e1/go.mod h1:Lcgkgu/QfaTqnBQqYb2LlnhM9aR509uEt07y61UQNGg=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200815001935-477d5b58b555 h1:NGxGSTnUWlNL8rUlU6hKxaOCbpM8Jrgwh/51pBu28UQ=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200815001935-477d5b58b555/go.mod h1:Lcgkgu/QfaTqnBQqYb2LlnhM9aR509uEt07y61UQNGg=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200815192814-e630cb3debe2 h1:9GZLZhVlqqTSwKX9CTf+fmj+/kpF8B1p+uYLdaUAHVI=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200815192814-e630cb3debe2/go.mod h1:PIsJWdDhjgN9OiR+qrDPD8KGQ8UyFuRVrgs3Ewu6a3c=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200815214034-638820c48066 h1:TOLTl0zLJ+idYB7i6C4oGfmVF1Y0AFoNfVQWU3hmc4A=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200815214034-638820c48066/go.mod h1:PIsJWdDhjgN9OiR+qrDPD8KGQ8UyFuRVrgs3Ewu6a3c=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
|
|
9
guild.go
9
guild.go
|
@ -3,6 +3,7 @@ package discord
|
|||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/diamondburned/arikawa/discord"
|
||||
|
@ -44,7 +45,7 @@ func NewGuildFolder(s *Session, gf gateway.GuildFolder) *GuildFolder {
|
|||
}
|
||||
|
||||
func (gf *GuildFolder) ID() string {
|
||||
return gf.GuildFolder.ID.String()
|
||||
return strconv.FormatInt(int64(gf.GuildFolder.ID), 10)
|
||||
}
|
||||
|
||||
func (gf *GuildFolder) Name() text.Rich {
|
||||
|
@ -80,7 +81,7 @@ func (gf *GuildFolder) Servers(container cchat.ServersContainer) error {
|
|||
}
|
||||
|
||||
type Guild struct {
|
||||
id discord.Snowflake
|
||||
id discord.GuildID
|
||||
session *Session
|
||||
}
|
||||
|
||||
|
@ -97,7 +98,7 @@ func NewGuild(s *Session, g *discord.Guild) *Guild {
|
|||
}
|
||||
}
|
||||
|
||||
func NewGuildFromID(s *Session, gID discord.Snowflake) (*Guild, error) {
|
||||
func NewGuildFromID(s *Session, gID discord.GuildID) (*Guild, error) {
|
||||
g, err := s.Guild(gID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -156,7 +157,7 @@ func (g *Guild) Servers(container cchat.ServersContainer) error {
|
|||
}
|
||||
|
||||
// Only get top-level channels (those with category ID being null).
|
||||
var toplevels = filterAccessible(g.session, filterCategory(c, discord.NullSnowflake))
|
||||
var toplevels = filterAccessible(g.session, filterCategory(c, 0))
|
||||
|
||||
// Sort so that positions are correct.
|
||||
sort.SliceStable(toplevels, func(i, j int) bool {
|
||||
|
|
18
message.go
18
message.go
|
@ -12,10 +12,10 @@ import (
|
|||
)
|
||||
|
||||
type messageHeader struct {
|
||||
id discord.Snowflake
|
||||
id discord.MessageID
|
||||
time discord.Timestamp
|
||||
channelID discord.Snowflake
|
||||
guildID discord.Snowflake
|
||||
channelID discord.ChannelID
|
||||
guildID discord.GuildID
|
||||
nonce string
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ func newHeader(msg discord.Message) messageHeader {
|
|||
guildID: msg.GuildID,
|
||||
nonce: msg.Nonce,
|
||||
}
|
||||
if msg.EditedTimestamp.Valid() {
|
||||
if msg.EditedTimestamp.IsValid() {
|
||||
h.time = msg.EditedTimestamp
|
||||
}
|
||||
return h
|
||||
|
@ -58,7 +58,7 @@ func AvatarURL(URL string) string {
|
|||
}
|
||||
|
||||
type Author struct {
|
||||
id discord.Snowflake
|
||||
id discord.UserID
|
||||
name text.Rich
|
||||
avatar string
|
||||
}
|
||||
|
@ -198,7 +198,7 @@ func NewMessageCreate(c *gateway.MessageCreateEvent, s *Session) Message {
|
|||
func NewBacklogMessage(m discord.Message, s *Session, g discord.Guild) Message {
|
||||
// If the message doesn't have a guild, then we don't need all the
|
||||
// complicated member fetching process.
|
||||
if !m.GuildID.Valid() {
|
||||
if !m.GuildID.IsValid() {
|
||||
return NewMessage(m, s, NewUser(m.Author, s))
|
||||
}
|
||||
|
||||
|
@ -220,7 +220,7 @@ func NewMessage(m discord.Message, s *Session, author Author) Message {
|
|||
var content = segments.ParseMessage(&m, s.Store)
|
||||
|
||||
// Request members in mentions if we're in a guild.
|
||||
if m.GuildID.Valid() {
|
||||
if m.GuildID.IsValid() {
|
||||
for _, segment := range content.Segments {
|
||||
if mention, ok := segment.(*segments.MentionSegment); ok {
|
||||
// If this is not a user mention, then skip.
|
||||
|
@ -231,7 +231,7 @@ func NewMessage(m discord.Message, s *Session, author Author) Message {
|
|||
// If we already have a member, then skip. We could check this
|
||||
// using the timestamp, as we might have a user set into the
|
||||
// member field
|
||||
if m := mention.GuildUser.Member; m != nil && m.Joined.Valid() {
|
||||
if m := mention.GuildUser.Member; m != nil && m.Joined.IsValid() {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -249,7 +249,7 @@ func NewMessage(m discord.Message, s *Session, author Author) Message {
|
|||
}
|
||||
|
||||
func (m Message) Author() cchat.MessageAuthor {
|
||||
if !m.author.id.Valid() {
|
||||
if !m.author.id.IsValid() {
|
||||
return nil
|
||||
}
|
||||
return m.author
|
||||
|
|
|
@ -115,7 +115,7 @@ func (r *TextRenderer) renderEmbed(embed discord.Embed, m *discord.Message, s st
|
|||
r.ensureBreak()
|
||||
}
|
||||
|
||||
if embed.Timestamp.Valid() {
|
||||
if embed.Timestamp.IsValid() {
|
||||
if embed.Footer != nil {
|
||||
r.buf.WriteString(" - ")
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ type MentionSegment struct {
|
|||
*md.Mention
|
||||
|
||||
store state.Store
|
||||
guild discord.Snowflake
|
||||
guild discord.GuildID
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -241,7 +241,7 @@ func userInfo(guild discord.Guild, member discord.Member, state *ningen.State) t
|
|||
}
|
||||
|
||||
// Write extra information if any, but only if we have the guild state.
|
||||
if len(member.RoleIDs) > 0 && guild.ID.Valid() {
|
||||
if len(member.RoleIDs) > 0 && guild.ID.IsValid() {
|
||||
// Write a prepended new line, as role writes will always prepend a new
|
||||
// line. This is to prevent a trailing new line.
|
||||
formatSectionf(&segment, &content, "Roles")
|
||||
|
@ -275,7 +275,7 @@ func userInfo(guild discord.Guild, member discord.Member, state *ningen.State) t
|
|||
formatActivity(&segment, &content, ac)
|
||||
content.WriteString("\n\n")
|
||||
}
|
||||
} else if guild.ID.Valid() {
|
||||
} else if guild.ID.IsValid() {
|
||||
// If we're still in a guild, then we can ask Discord for that
|
||||
// member with their presence attached.
|
||||
state.MemberState.RequestMember(guild.ID, member.User.ID)
|
||||
|
@ -312,6 +312,16 @@ func formatSectionf(segment *text.Rich, content *bytes.Buffer, f string, argv ..
|
|||
segmentadd(segment, InlineSegment{start, end, text.AttrBold | text.AttrUnderline})
|
||||
}
|
||||
|
||||
func FormatActivity(ac discord.Activity) text.Rich {
|
||||
var rich text.Rich
|
||||
var cbuf bytes.Buffer
|
||||
|
||||
formatActivity(&rich, &cbuf, ac)
|
||||
|
||||
rich.Content = cbuf.String()
|
||||
return rich
|
||||
}
|
||||
|
||||
func formatActivity(segment *text.Rich, content *bytes.Buffer, ac discord.Activity) {
|
||||
switch ac.Type {
|
||||
case discord.GameActivity:
|
||||
|
@ -331,7 +341,7 @@ func formatActivity(segment *text.Rich, content *bytes.Buffer, ac discord.Activi
|
|||
content.WriteByte('\n')
|
||||
|
||||
if ac.Emoji != nil {
|
||||
if !ac.Emoji.ID.Valid() {
|
||||
if !ac.Emoji.ID.IsValid() {
|
||||
content.WriteString(ac.Emoji.Name)
|
||||
} else {
|
||||
segmentadd(segment, EmojiSegment{
|
||||
|
@ -367,7 +377,10 @@ func formatActivity(segment *text.Rich, content *bytes.Buffer, ac discord.Activi
|
|||
}
|
||||
}
|
||||
|
||||
func getPresence(state *ningen.State, guildID, userID discord.Snowflake) *discord.Activity {
|
||||
func getPresence(
|
||||
state *ningen.State,
|
||||
guildID discord.GuildID, userID discord.UserID) *discord.Activity {
|
||||
|
||||
p, err := state.Presence(guildID, userID)
|
||||
if err != nil {
|
||||
return nil
|
||||
|
@ -380,7 +393,7 @@ func getPresence(state *ningen.State, guildID, userID discord.Snowflake) *discor
|
|||
return p.Game
|
||||
}
|
||||
|
||||
func findRole(roles []discord.Role, id discord.Snowflake) (discord.Role, bool) {
|
||||
func findRole(roles []discord.Role, id discord.RoleID) (discord.Role, bool) {
|
||||
for _, role := range roles {
|
||||
if role.ID == id {
|
||||
return role, true
|
||||
|
|
|
@ -72,7 +72,7 @@ func (Authenticator) Authenticate(form []string) (cchat.Session, error) {
|
|||
|
||||
type Session struct {
|
||||
*ningen.State
|
||||
userID discord.Snowflake
|
||||
userID discord.UserID
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -168,7 +168,7 @@ func (s *Session) Servers(container cchat.ServersContainer) error {
|
|||
for _, folder := range s.Ready.Settings.GuildFolders {
|
||||
// TODO: correct.
|
||||
switch {
|
||||
case folder.ID.Valid():
|
||||
case folder.ID > 0:
|
||||
fallthrough
|
||||
case len(folder.GuildIDs) > 1:
|
||||
toplevels = append(toplevels, NewGuildFolder(s, folder))
|
||||
|
|
2
typer.go
2
typer.go
|
@ -24,7 +24,7 @@ func NewTyperAuthor(author Author, ev *gateway.TypingStartEvent) Typer {
|
|||
}
|
||||
|
||||
func NewTyper(s *Session, ev *gateway.TypingStartEvent) (*Typer, error) {
|
||||
if ev.GuildID.Valid() {
|
||||
if ev.GuildID.IsValid() {
|
||||
g, err := s.Store.Guild(ev.GuildID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -59,7 +59,7 @@ func ExtIs(URL string, exts []string) bool {
|
|||
}
|
||||
|
||||
// AssetURL generates the image URL from the given asset image ID.
|
||||
func AssetURL(appID discord.Snowflake, imageID string) string {
|
||||
func AssetURL(appID discord.AppID, imageID string) string {
|
||||
if strings.HasPrefix(imageID, "spotify:") {
|
||||
return "https://i.scdn.co/image/" + strings.TrimPrefix(imageID, "spotify:")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue