diff options
Diffstat (limited to 'server/channel')
| -rw-r--r-- | server/channel/channel.go | 68 | ||||
| -rw-r--r-- | server/channel/command.go | 20 |
2 files changed, 87 insertions, 1 deletions
diff --git a/server/channel/channel.go b/server/channel/channel.go index e2a18c5..d907bc0 100644 --- a/server/channel/channel.go +++ b/server/channel/channel.go @@ -179,6 +179,14 @@ func (c *Channel) Rename(name string) *proto.Fail { } func (c *Channel) Put(m proto.Object, From *session.Session) proto.Object { + for uid := range c.Members() { + switch u := c.kind.world.GetCachedObject(uid).(type) { + case (*user.User): + if len(u.PrivateStream.Subscribers()) != 0 && !c.Unread(uid) { + u.PrivateStream.Event(proto.NewCmd("unread", c.id)) + } + } + } m.Id = proto.GenId() m.Fields["t"] = proto.Timestamp() err := c.kind.db.Update(func(tx *bolt.Tx) error { @@ -283,6 +291,56 @@ func (c *Channel) History(min, max int) []proto.Object { return result } +func (c *Channel) Unread(uid string) bool { + lastIndex := c.HistorySize() - 1 + if (lastIndex < 0) { + return false + } + latest := c.History(lastIndex, lastIndex + 1)[0].Id + + unread := true + err := c.kind.db.View(func(tx *bolt.Tx) error { + udata := tx.Bucket([]byte("user data")) + if udata == nil { + return nil + } + user := udata.Bucket([]byte(uid)) + if user == nil { + return nil + } + readStatus := user.Bucket([]byte("read status")) + if readStatus == nil { + return nil + } + unread = string(readStatus.Get([]byte(c.id))) != latest + return nil + }) + if err != nil { + log.Fatal("error reading database: ", err) + } + + return unread +} + +func (c *Channel) SetRead(uid string) { + lastIndex := c.HistorySize() - 1 + if (lastIndex < 0) { + return + } + latest := c.History(lastIndex, lastIndex + 1)[0].Id + + err := c.kind.db.Update(func(tx *bolt.Tx) error { + udata, _ := tx.CreateBucketIfNotExists([]byte("user data")) + user, _ := udata.CreateBucketIfNotExists([]byte(uid)) + readStatus, _ := user.CreateBucketIfNotExists([]byte("read status")) + readStatus.Put([]byte(c.id), []byte(latest)) + return nil + }) + if err != nil { + log.Fatal("error updating database: ", err) + } +} + func (c *Channel) Join(u *user.User) *proto.Fail { if c.isDirect { return &proto.Fail {"invalid", "", nil} @@ -427,7 +485,15 @@ func (c *Channel) Kind() string { } func (c *Channel) InfoFor(uid string) proto.Object { - return proto.Object { + i := proto.Object { c.Kind(), c.id, map[string]string {"": c.NameFor(uid)}, } + if uid != "" { + if c.Unread(uid) { + i.Fields["unread"] = "yes" + } else { + i.Fields["unread"] = "no" + } + } + return i } diff --git a/server/channel/command.go b/server/channel/command.go index 92ae2cc..23acccb 100644 --- a/server/channel/command.go +++ b/server/channel/command.go @@ -260,6 +260,26 @@ func (c *Channel) SendRequest(r session.Request) { r.ReplyInvalid() } + case "read": + if len(r.Cmd.Args) != 0 { + r.ReplyInvalid() + return + } + if !c.GetMembership(r.From.UserId).See { + r.Reply(proto.Fail{"forbidden", "", nil}.Cmd()) + return + } + c.SetRead(r.From.UserId) + + u := c.kind.world.GetObject(r.From.UserId).(*user.User) + for s := range u.PrivateStream.Subscribers { + if s != r.From { + s.Event(proto.NewCmd("read", c.id)) + } + } + + r.ReplyOk() + default: r.ReplyInvalid() } |
