diff options
| author | citrons <citrons@mondecitronne.com> | 2025-01-26 01:56:53 -0600 |
|---|---|---|
| committer | citrons <citrons@mondecitronne.com> | 2025-01-26 01:56:53 -0600 |
| commit | 10b8a79389e7073f6bd65695c3d05c77b825bc33 (patch) | |
| tree | b7e6dbd84b5b2c960ab8aafc1f99c3950d679e44 /server/channel/channel.go | |
initial commit
Diffstat (limited to 'server/channel/channel.go')
| -rw-r--r-- | server/channel/channel.go | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/server/channel/channel.go b/server/channel/channel.go new file mode 100644 index 0000000..50b43b6 --- /dev/null +++ b/server/channel/channel.go @@ -0,0 +1,148 @@ +package channel + +import ( + "citrons.xyz/talk/proto" + "citrons.xyz/talk/server/object" + "citrons.xyz/talk/server/session" + "citrons.xyz/talk/server/user" +) + +type ChannelStore struct { + world *object.World + byName map[string]*Channel +} + +type Channel struct { + store *ChannelStore + id string + name string + members map[string]Membership + messages []proto.Object + byId map[string]int + defaultMembership Membership + Stream session.Stream +} + +func NewStore(world *object.World) *ChannelStore { + return &ChannelStore {world, make(map[string]*Channel)} +} + +func (cs *ChannelStore) CreateChannel(name string) (*Channel, *proto.Fail) { + if cs.byName[name] != nil { + return nil, &proto.Fail { + "name-taken", "", map[string]string {"": name}, + } + } + var c Channel + c.store = cs + c.name = name + c.members = make(map[string]Membership) + c.byId = make(map[string]int) + c.defaultMembership = DefaultMembership + + cs.byName[name] = &c + c.id = cs.world.NewObject(&c) + return &c, nil +} + +func (cs *ChannelStore) ByName(name string) *Channel { + return cs.byName[name] +} + +func (c *Channel) Name() string { + return c.name +} + +func (c *Channel) Id() string { + return c.id +} + +func (c *Channel) Rename(name string) *proto.Fail { + if c.store.byName[name] != nil { + return &proto.Fail { + "name-taken", "", map[string]string {"": name}, + } + } + c.store.byName[c.name] = nil + c.store.byName[name] = c + c.name = name + return nil +} + +func (c *Channel) Put(m proto.Object) proto.Object { + m.Id = proto.GenId() + m.Fields["t"] = proto.Timestamp() + c.byId[m.Id] = len(c.messages) + c.messages = append(c.messages, m) + for s, _ := range c.Stream.Subscribers() { + if m.Fields["f"] == s.UserId { + continue + } + if c.members[s.UserId].See { + s.Event(proto.NewCmd("p", c.id, m)) + } + } + return m +} + +func (c *Channel) prune() { + for m, _ := range c.members { + switch c.store.world.GetObject(m).(type) { + case *user.User: + default: + delete(c.members, m) + } + } +} + +func (c *Channel) Join(u *user.User) *proto.Fail { + if c.members[u.Id()].Yes { + return nil + } + c.members[u.Id()] = c.defaultMembership + u.Channels[c.id] = true + c.Put(proto.Object{"join", "", map[string]string {"": u.Id()}}) + return nil +} + +func (c *Channel) Leave(u *user.User) *proto.Fail { + if !c.members[u.Id()].Yes { + return nil + } + delete(c.members, u.Id()) + delete(u.Channels, c.id) + c.Put(proto.Object{"leave", "", map[string]string {"": u.Id()}}) + return nil +} + +func (c *Channel) Members() map[string]Membership { + c.prune() + return c.members +} + +func (c *Channel) SetMembership(u *user.User, m Membership) { + if c.members[u.Id()].Yes { + c.members[u.Id()] = m + } +} + +func (c *Channel) Delete() { + c.Stream.Event(proto.NewCmd("delete", c.id)) + c.Stream.UnsubscribeAll() + + for m, _ := range c.members { + switch u := c.store.world.GetObject(m).(type) { + case *user.User: + u.Channels[c.id] = false + default: + } + } + delete(c.store.byName, c.name) + c.store.world.RemoveObject(c.id) +} + +func (c *Channel) GetInfo() proto.Object { + return proto.Object { + "channel", c.id, map[string]string {"": c.name}, + } +} |
