mirror of
https://github.com/diamondburned/cchat-discord.git
synced 2024-12-23 04:46:43 +00:00
157 lines
3.8 KiB
Go
157 lines
3.8 KiB
Go
package private
|
|
|
|
import (
|
|
"sort"
|
|
"sync"
|
|
|
|
"github.com/diamondburned/arikawa/v2/discord"
|
|
"github.com/diamondburned/arikawa/v2/gateway"
|
|
"github.com/diamondburned/cchat"
|
|
"github.com/diamondburned/cchat-discord/internal/discord/channel"
|
|
"github.com/diamondburned/cchat-discord/internal/discord/private/hub"
|
|
"github.com/diamondburned/cchat-discord/internal/discord/state"
|
|
"github.com/diamondburned/cchat/text"
|
|
"github.com/diamondburned/cchat/utils/empty"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// I don't think the cchat specs said anything about sharing a cchat.Server, so
|
|
// we might need to do this. Nevertheless, it seems overkill.
|
|
type containerSet struct {
|
|
mut sync.Mutex
|
|
set map[cchat.ServersContainer]struct{}
|
|
}
|
|
|
|
func newContainerSet() *containerSet {
|
|
return &containerSet{
|
|
set: map[cchat.ServersContainer]struct{}{},
|
|
}
|
|
}
|
|
|
|
func (cset *containerSet) Register(container cchat.ServersContainer) {
|
|
cset.mut.Lock()
|
|
cset.set[container] = struct{}{}
|
|
cset.mut.Unlock()
|
|
}
|
|
|
|
// prependServer wraps around Server to always prepend this wrapped server on
|
|
// top of the servers container.
|
|
type prependServer struct{ cchat.Server }
|
|
|
|
var _ cchat.ServerUpdate = (*prependServer)(nil)
|
|
|
|
// PreviousID returns the appropriate parameters to prepend this server.
|
|
func (ps prependServer) PreviousID() (cchat.ID, bool) {
|
|
// Return the private container's ID so this server goes right after it.
|
|
return "!!!private-container!!!", false
|
|
}
|
|
|
|
func (cset *containerSet) AddChannel(s *state.Instance, ch *discord.Channel) {
|
|
c, err := channel.New(s, *ch)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
replace := prependServer{Server: c}
|
|
|
|
cset.mut.Lock()
|
|
|
|
for container := range cset.set {
|
|
container.UpdateServer(replace)
|
|
}
|
|
|
|
cset.mut.Unlock()
|
|
}
|
|
|
|
type Private struct {
|
|
empty.Server
|
|
state *state.Instance
|
|
hub *hub.Server
|
|
containers *containerSet
|
|
}
|
|
|
|
func New(s *state.Instance) (cchat.Server, error) {
|
|
containers := newContainerSet()
|
|
|
|
hubServer, err := hub.New(s, containers)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to make hub server")
|
|
}
|
|
|
|
return Private{
|
|
state: s,
|
|
hub: hubServer,
|
|
containers: containers,
|
|
}, nil
|
|
}
|
|
|
|
func (priv Private) ID() cchat.ID {
|
|
// Not even a number, so no chance of colliding with snowflakes.
|
|
return "!!!private-container!!!"
|
|
}
|
|
|
|
func (priv Private) Name() text.Rich {
|
|
return text.Plain("Private Channels")
|
|
}
|
|
|
|
func (priv Private) AsLister() cchat.Lister { return priv }
|
|
|
|
type activeChannel struct {
|
|
*discord.Channel
|
|
*gateway.ReadState // used for sorting
|
|
}
|
|
|
|
func (active activeChannel) LastMessageID() discord.MessageID {
|
|
if active.ReadState == nil {
|
|
return active.Channel.LastMessageID
|
|
}
|
|
if active.ReadState.LastMessageID > active.Channel.LastMessageID {
|
|
return active.ReadState.LastMessageID
|
|
}
|
|
if active.Channel.LastMessageID.IsValid() {
|
|
return active.Channel.LastMessageID
|
|
}
|
|
// Whatever.
|
|
return discord.MessageID(active.Channel.ID)
|
|
}
|
|
|
|
func (priv Private) Servers(container cchat.ServersContainer) error {
|
|
activeIDs := priv.hub.ActiveChannelIDs()
|
|
|
|
channels := make([]activeChannel, 0, len(activeIDs))
|
|
|
|
for _, id := range activeIDs {
|
|
c, err := priv.state.Channel(id)
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to get private channel")
|
|
}
|
|
|
|
channels = append(channels, activeChannel{
|
|
Channel: c,
|
|
ReadState: priv.state.ReadState.FindLast(id),
|
|
})
|
|
}
|
|
|
|
// Sort so that channels with the largest last message ID (and therefore the
|
|
// latest message) will be on top.
|
|
sort.Slice(channels, func(i, j int) bool {
|
|
return channels[i].LastMessageID() > channels[j].LastMessageID()
|
|
})
|
|
|
|
servers := make([]cchat.Server, len(channels)+1)
|
|
servers[0] = priv.hub
|
|
|
|
for i, ch := range channels {
|
|
c, err := channel.New(priv.state, *ch.Channel)
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to create server for private channel")
|
|
}
|
|
|
|
servers[i+1] = c
|
|
}
|
|
|
|
container.SetServers(servers)
|
|
priv.containers.Register(container)
|
|
return nil
|
|
}
|