From 0bf5515629f1cfe1557dba4f8d588ac64b77d408 Mon Sep 17 00:00:00 2001 From: Kyren223 Date: Wed, 5 Feb 2025 19:41:34 +0200 Subject: When a user sends a message "signal" and the receiving user doesn't have the signal already open, it will be added as the first signal --- internal/client/ui/core/chat/chat.go | 28 ++++++++++-- internal/client/ui/core/core.go | 14 ++++-- internal/client/ui/core/signallist/signallist.go | 4 +- internal/client/ui/core/state/state.go | 58 ++++++++++++++++-------- internal/data/notifications.sql.go | 17 +++++++ internal/server/api/api.go | 10 ++++ internal/server/api/helpers.go | 7 +-- internal/server/server.go | 4 ++ query/notifications.sql | 6 +++ 9 files changed, 117 insertions(+), 31 deletions(-) diff --git a/internal/client/ui/core/chat/chat.go b/internal/client/ui/core/chat/chat.go index aba65a2..37fc1a8 100644 --- a/internal/client/ui/core/chat/chat.go +++ b/internal/client/ui/core/chat/chat.go @@ -277,6 +277,26 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { state.State.LastReadMessages[receiverId] = lastMsg } + + m.hasReadAccess = true + m.hasWriteAccess = true // TODO: implement blocking users + + if m.locked { + m.vi.Placeholder = SendMessagePlaceholder + m.borderStyle = ViFocusedBorder + m.style = focusStyle + m.vi.SetInactive(false) + m.vi.Focus() + if m.editingMessage != nil { + m.borderStyle = ViEditBorder + m.style = editStyle + } + } else { + m.vi.Placeholder = SendMessagePlaceholder + m.borderStyle = ViBlurredBorder + m.style = blurStyle + m.vi.SetInactive(false) + } } if !m.focus { @@ -734,8 +754,6 @@ func (m *Model) ResetBeforeSwitch() { MaxHeight: m.maxMessagesHeight, } - state.SendUserDatUpdate() - } else if m.receiverIndex != -1 { receiverId := state.Data.Signals[m.receiverIndex] log.Println("Saving signal:", receiverId) @@ -744,8 +762,6 @@ func (m *Model) ResetBeforeSwitch() { Base: m.base, MaxHeight: m.maxMessagesHeight, } - - state.SendUserDatUpdate() } } @@ -772,6 +788,8 @@ func (m *Model) RestoreAfterSwitch() tea.Cmd { // Don't ask for messages if you already visited this frequency return nil } + + log.Println("Requesting frequency messages") return gateway.Send(&packet.RequestMessages{ ReceiverID: nil, FrequencyID: &frequency.ID, @@ -795,6 +813,8 @@ func (m *Model) RestoreAfterSwitch() tea.Cmd { // Don't ask for messages if you already visited this frequency return nil } + + log.Println("Requesting signal messages:", receiverId) return gateway.Send(&packet.RequestMessages{ ReceiverID: &receiverId, FrequencyID: nil, diff --git a/internal/client/ui/core/core.go b/internal/client/ui/core/core.go index b87600d..60225d8 100644 --- a/internal/client/ui/core/core.go +++ b/internal/client/ui/core/core.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "math" + "slices" "time" "github.com/atotto/clipboard" @@ -191,8 +192,6 @@ func (m *Model) updateNotConnected(msg tea.Msg) tea.Cmd { m.connected = true m.timeout = initialTimeout - requestUserData := gateway.Send(&packet.GetUserData{}) - var setName tea.Cmd if m.name != "" { setName = gateway.Send(&packet.SetUserData{ @@ -206,7 +205,7 @@ func (m *Model) updateNotConnected(msg tea.Msg) tea.Cmd { m.name = "" } - return tea.Batch(m.timer.Stop(), requestUserData, setName) + return tea.Batch(m.timer.Stop(), setName) case gateway.ConnectionFailed: log.Println("failed to connect:", msg) @@ -323,7 +322,14 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd { state.UpdateTrusteds(msg) case *packet.NotificationsInfo: - state.UpdateNotifications(msg) + signals := state.UpdateNotifications(msg) + if m.networkList.Index() == networklist.SignalsIndex { + m.chat.SetReceiver(-1) + state.Data.Signals = slices.Insert(state.Data.Signals, 0, signals...) + return m.chat.SetReceiver(m.signalList.Index()) + } else { + state.Data.Signals = slices.Insert(state.Data.Signals, 0, signals...) + } case ui.BanReasonPopupMsg: popup := banreason.New(msg.User, msg.Network) diff --git a/internal/client/ui/core/signallist/signallist.go b/internal/client/ui/core/signallist/signallist.go index e6fccb9..c9fad95 100644 --- a/internal/client/ui/core/signallist/signallist.go +++ b/internal/client/ui/core/signallist/signallist.go @@ -28,8 +28,8 @@ var ( MarginBottom(1).Padding(1, 2).Align(lipgloss.Center). Border(lipgloss.ThickBorder(), false, false, true) - margin = 2 - padding = 1 + margin = 2 + padding = 1 signalStyle = lipgloss.NewStyle(). Margin(0, margin).Padding(0, padding).Align(lipgloss.Left) diff --git a/internal/client/ui/core/state/state.go b/internal/client/ui/core/state/state.go index 658c218..8c6dfeb 100644 --- a/internal/client/ui/core/state/state.go +++ b/internal/client/ui/core/state/state.go @@ -4,6 +4,7 @@ import ( "context" "crypto/ed25519" "encoding/json" + "log" "slices" "time" @@ -51,12 +52,12 @@ var State state = state{ type UserData struct { Networks []snowflake.ID - Signals []snowflake.ID + Signals []snowflake.ID } var Data UserData = UserData{ Networks: []snowflake.ID{}, - Signals: []snowflake.ID{}, + Signals: []snowflake.ID{}, } var UserID *snowflake.ID = nil @@ -107,12 +108,6 @@ func UpdateNetworks(info *packet.NetworksInfo) { _, ok := State.Networks[id] return !ok }) - - data := JsonUserData() - gateway.SendAsync(&packet.SetUserData{ - Data: &data, - User: nil, - }) } func UpdateFrequencies(info *packet.FrequenciesInfo) { @@ -225,7 +220,15 @@ func FromJsonUserData(s string) { if err != nil { return } - Data = data + + // log.Println("Previous user data:", Data) + if data.Networks != nil { + Data.Networks = data.Networks + } + if data.Signals != nil { + Data.Signals = data.Signals + } + log.Println("Updated user data:", Data) } func UpdateTrusteds(info *packet.TrustInfo) { @@ -250,26 +253,45 @@ func GetLastMessage(id snowflake.ID) *snowflake.ID { return &msg.ID } -func SendUserDatUpdate() { - data := JsonUserData() - gateway.SendAsync(&packet.SetUserData{ - Data: &data, - User: nil, - }) +func IsFrequency(id snowflake.ID) bool { + // Note this is very expensive and inefficient + // A map is better but as most of the time frequencies are iterated + // over based on a network id, this would add overhead + // And this function is only used once in notifications + + for _, frequencies := range State.Frequencies { + for _, frequency := range frequencies { + if id == frequency.ID { + return true + } + } + } + return false } -func UpdateNotifications(info *packet.NotificationsInfo) { +func UpdateNotifications(info *packet.NotificationsInfo) []snowflake.ID { + signals := []snowflake.ID{} + for i := 0; i < len(info.Source); i++ { + source := info.Source[i] lastRead := snowflake.ID(info.LastRead[i]) - State.LastReadMessages[info.Source[i]] = &lastRead + State.LastReadMessages[source] = &lastRead ping := info.Pings[i] if ping != nil { - State.Notifications[info.Source[i]] = int(*ping) + // log.Println(source, *ping) + State.Notifications[source] = int(*ping) + if !IsFrequency(source) && !slices.Contains(Data.Signals, source) { + signals = append(signals, source) + // log.Println("Signals:", Data.Signals) + } } else { + // log.Println(source, "deleted") delete(State.Notifications, info.Source[i]) } } + + return signals } func SendFinalData() { diff --git a/internal/data/notifications.sql.go b/internal/data/notifications.sql.go index 5819438..393d90a 100644 --- a/internal/data/notifications.sql.go +++ b/internal/data/notifications.sql.go @@ -11,6 +11,23 @@ import ( "github.com/kyren223/eko/pkg/snowflake" ) +const insertLastReadMessage = `-- name: InsertLastReadMessage :exec +INSERT OR IGNORE INTO last_read_messages ( + user_id, source_id, last_read +) VALUES (?, ?, ?) +` + +type InsertLastReadMessageParams struct { + UserID snowflake.ID + SourceID snowflake.ID + LastRead int64 +} + +func (q *Queries) InsertLastReadMessage(ctx context.Context, arg InsertLastReadMessageParams) error { + _, err := q.db.ExecContext(ctx, insertLastReadMessage, arg.UserID, arg.SourceID, arg.LastRead) + return err +} + const setLastReadMessage = `-- name: SetLastReadMessage :exec INSERT INTO last_read_messages ( user_id, source_id, last_read diff --git a/internal/server/api/api.go b/internal/server/api/api.go index 92679b8..e087268 100644 --- a/internal/server/api/api.go +++ b/internal/server/api/api.go @@ -156,6 +156,16 @@ func SendMessage(ctx context.Context, sess *session.Session, request *packet.Sen return &ErrInternalError } + err = queries.InsertLastReadMessage(ctx, data.InsertLastReadMessageParams{ + UserID: *request.ReceiverID, + SourceID: sess.ID(), + LastRead: 0, + }) + if err != nil { + log.Println("database error 7:", err) + return &ErrInternalError + } + return UserPropagate(ctx, sess, user.ID, &packet.MessagesInfo{ Messages: []data.Message{message}, RemovedMessages: nil, diff --git a/internal/server/api/helpers.go b/internal/server/api/helpers.go index 2daeb9f..4327a49 100644 --- a/internal/server/api/helpers.go +++ b/internal/server/api/helpers.go @@ -151,15 +151,16 @@ SELECT e.source_id, e.last_read, CASE WHEN COUNT(m.id) = 0 THEN NULL - ELSE SUM(CASE WHEN (m.ping = 0 OR (m.ping = 1 AND pf.is_admin = true) OR m.ping = ?) THEN 1 ELSE 0 END) + ELSE SUM(CASE WHEN (m.frequency_id IS NULL OR + m.ping = 0 OR (m.ping = 1 AND pf.is_admin = true) OR m.ping = ?) THEN 1 ELSE 0 END) -- 0 is @everyone, 1 is @admins, otherwise it's user_id END AS pings FROM entries e +LEFT JOIN permitted_frequencies pf ON e.source_id = pf.id LEFT JOIN messages m ON m.id > e.last_read - AND (m.frequency_id = e.source_id OR + AND ((m.frequency_id = e.source_id AND pf.id IS NOT NULL) OR (m.receiver_id = e.source_id AND m.sender_id = ?) OR (m.sender_id = e.source_id AND m.receiver_id = ?)) -JOIN permitted_frequencies pf ON e.source_id = pf.id GROUP BY e.source_id, e.last_read; ` diff --git a/internal/server/server.go b/internal/server/server.go index 153f612..1477e7f 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -414,6 +414,7 @@ func (server *server) sendInitialPackets(ctx context.Context, sess *session.Sess if payload == &api.ErrInternalError { return false } + log.Println(sess.Addr(), "sending", payload.Type(), "payload:", payload) pkt := packet.NewPacket(packet.NewMsgPackEncoder(payload)) sess.Write(ctx, pkt) @@ -421,6 +422,7 @@ func (server *server) sendInitialPackets(ctx context.Context, sess *session.Sess if payload == &api.ErrInternalError { return false } + log.Println(sess.Addr(), "sending", payload.Type(), "payload:", payload) pkt = packet.NewPacket(packet.NewMsgPackEncoder(payload)) sess.Write(ctx, pkt) @@ -428,6 +430,7 @@ func (server *server) sendInitialPackets(ctx context.Context, sess *session.Sess if err != nil { return false } + log.Println(sess.Addr(), "sending", payload.Type(), "payload:", payload) pkt = packet.NewPacket(packet.NewMsgPackEncoder(payload)) sess.Write(ctx, pkt) @@ -435,6 +438,7 @@ func (server *server) sendInitialPackets(ctx context.Context, sess *session.Sess if payload == &api.ErrInternalError { return false } + log.Println(sess.Addr(), "sending", payload.Type(), "payload:", payload) pkt = packet.NewPacket(packet.NewMsgPackEncoder(payload)) sess.Write(ctx, pkt) diff --git a/query/notifications.sql b/query/notifications.sql index 5dd4d5a..72a05f1 100644 --- a/query/notifications.sql +++ b/query/notifications.sql @@ -5,3 +5,9 @@ INSERT INTO last_read_messages ( ON CONFLICT DO UPDATE SET last_read = EXCLUDED.last_read WHERE user_id = EXCLUDED.user_id AND source_id = EXCLUDED.source_id; + + +-- name: InsertLastReadMessage :exec +INSERT OR IGNORE INTO last_read_messages ( + user_id, source_id, last_read +) VALUES (?, ?, ?); -- cgit v1.3.1