126 lines
3.2 KiB
Go
126 lines
3.2 KiB
Go
package channel
|
|
|
|
import (
|
|
"context"
|
|
"sort"
|
|
|
|
"github.com/diamondburned/arikawa/discord"
|
|
"github.com/diamondburned/arikawa/gateway"
|
|
"github.com/diamondburned/cchat"
|
|
"github.com/diamondburned/cchat-discord/internal/discord/message"
|
|
"github.com/diamondburned/cchat-discord/internal/funcutil"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
var _ cchat.Messenger = (*Channel)(nil)
|
|
|
|
// IsMessenger returns true if the current user is allowed to see the channel.
|
|
func (ch *Channel) IsMessenger() bool {
|
|
p, err := ch.state.StateOnly().Permissions(ch.id, ch.state.UserID)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
return p.Has(discord.PermissionViewChannel)
|
|
}
|
|
|
|
func (ch *Channel) JoinServer(ctx context.Context, ct cchat.MessagesContainer) (func(), error) {
|
|
state := ch.state.WithContext(ctx)
|
|
|
|
m, err := state.Messages(ch.id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var addcancel = funcutil.NewCancels()
|
|
|
|
var constructor func(discord.Message) cchat.MessageCreate
|
|
|
|
if ch.guildID.IsValid() {
|
|
// Create the backlog without any member information.
|
|
g, err := state.Guild(ch.guildID)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "Failed to get guild")
|
|
}
|
|
|
|
constructor = func(m discord.Message) cchat.MessageCreate {
|
|
return message.NewBacklogMessage(m, ch.state, *g)
|
|
}
|
|
|
|
// Subscribe to typing events.
|
|
ch.state.MemberState.Subscribe(ch.guildID)
|
|
|
|
// Listen to new members before creating the backlog and requesting members.
|
|
addcancel(ch.state.AddHandler(func(c *gateway.GuildMembersChunkEvent) {
|
|
if c.GuildID != ch.guildID {
|
|
return
|
|
}
|
|
|
|
m, err := ch.messages()
|
|
if err != nil {
|
|
// TODO: log
|
|
return
|
|
}
|
|
|
|
g, err := ch.guild()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// Loop over all messages and replace the author. The latest
|
|
// messages are in front.
|
|
for _, msg := range m {
|
|
for _, member := range c.Members {
|
|
if msg.Author.ID != member.User.ID {
|
|
continue
|
|
}
|
|
|
|
ct.UpdateMessage(message.NewMessageUpdateAuthor(msg, member, *g, ch.state))
|
|
}
|
|
}
|
|
}))
|
|
} else {
|
|
constructor = func(m discord.Message) cchat.MessageCreate {
|
|
return message.NewDirectMessage(m, ch.state)
|
|
}
|
|
}
|
|
|
|
// Only do all this if we even have any messages.
|
|
if len(m) > 0 {
|
|
// Sort messages chronologically using the ID so that the oldest messages
|
|
// (ones with the smallest snowflake) is in front.
|
|
sort.Slice(m, func(i, j int) bool { return m[i].ID < m[j].ID })
|
|
|
|
// Iterate from the earliest messages to the latest messages.
|
|
for _, m := range m {
|
|
ct.CreateMessage(constructor(m))
|
|
}
|
|
|
|
// Mark this channel as read.
|
|
ch.state.ReadState.MarkRead(ch.id, m[len(m)-1].ID)
|
|
}
|
|
|
|
// Bind the handler.
|
|
addcancel(
|
|
ch.state.AddHandler(func(m *gateway.MessageCreateEvent) {
|
|
if m.ChannelID == ch.id {
|
|
ct.CreateMessage(message.NewMessageCreate(m, ch.state))
|
|
ch.state.ReadState.MarkRead(ch.id, m.ID)
|
|
}
|
|
}),
|
|
ch.state.AddHandler(func(m *gateway.MessageUpdateEvent) {
|
|
// If the updated content is empty. TODO: add embed support.
|
|
if m.ChannelID == ch.id {
|
|
ct.UpdateMessage(message.NewMessageUpdateContent(m.Message, ch.state))
|
|
}
|
|
}),
|
|
ch.state.AddHandler(func(m *gateway.MessageDeleteEvent) {
|
|
if m.ChannelID == ch.id {
|
|
ct.DeleteMessage(message.NewHeaderDelete(m))
|
|
}
|
|
}),
|
|
)
|
|
|
|
return funcutil.JoinCancels(addcancel()), nil
|
|
}
|