@@ -2,6 +2,7 @@ package main
22
33import (
44 "fmt"
5+ "log/slog"
56 "strings"
67 "time"
78
@@ -19,6 +20,12 @@ type (
1920 errMsg error
2021)
2122
23+ // historyLoaded is sent once the background goroutine finishes reading prior
24+ // chat entries from the database.
25+ type historyLoaded struct {
26+ messages []string
27+ }
28+
2229type model struct {
2330 viewport viewport.Model
2431 messages []string
@@ -53,7 +60,7 @@ func initialModel(t *kamune.Transport) model {
5360 ta .ShowLineNumbers = false
5461
5562 vp := viewport .New (30 , 5 )
56- vp .SetContent (fmt .Sprintf (`Session ID is %s. Happy Chatting! ` , t .SessionID ()))
63+ vp .SetContent (fmt .Sprintf (`Session ID is %s. Loading history… ` , t .SessionID ()))
5764 vp .MouseWheelEnabled = true
5865 vp .Style = lipgloss .NewStyle ().
5966 Border (lipgloss .RoundedBorder ()).
@@ -74,8 +81,40 @@ func initialModel(t *kamune.Transport) model {
7481 }
7582}
7683
84+ // loadHistory returns a tea.Cmd that asynchronously reads prior chat entries
85+ // from the database and delivers them as a historyLoaded message.
86+ func loadHistory (t * kamune.Transport , userPrefix , userText , peerPrefix , peerText lipgloss.Style ) tea.Cmd {
87+ return func () tea.Msg {
88+ entries , err := t .Store ().GetChatHistory (t .SessionID ())
89+ if err != nil {
90+ slog .Warn ("failed to load chat history" ,
91+ slog .String ("session_id" , t .SessionID ()),
92+ slog .Any ("error" , err ))
93+ return historyLoaded {}
94+ }
95+
96+ var msgs []string
97+ for _ , ent := range entries {
98+ sender := "You"
99+ prefixStyle := userPrefix
100+ textStyle := userText
101+ if ent .Sender != kamune .SenderLocal {
102+ sender = "Peer"
103+ prefixStyle = peerPrefix
104+ textStyle = peerText
105+ }
106+ prefix := fmt .Sprintf ("[%s] %s: " , ent .Timestamp .Format (time .DateTime ), sender )
107+ msgs = append (msgs , prefixStyle .Render (prefix )+ textStyle .Render (string (ent .Data )))
108+ }
109+ return historyLoaded {messages : msgs }
110+ }
111+ }
112+
77113func (m model ) Init () tea.Cmd {
78- return textarea .Blink
114+ return tea .Batch (
115+ textarea .Blink ,
116+ loadHistory (m .transport , m .userPrefix , m .userText , m .peerPrefix , m .peerText ),
117+ )
79118}
80119
81120func (m model ) Update (msg tea.Msg ) (tea.Model , tea.Cmd ) {
@@ -88,6 +127,25 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
88127 m .viewport , vpCmd = m .viewport .Update (msg )
89128
90129 switch msg := msg .(type ) {
130+ case historyLoaded :
131+ header := fmt .Sprintf ("Session ID is %s. Happy Chatting!" , m .transport .SessionID ())
132+ if len (msg .messages ) > 0 {
133+ header = fmt .Sprintf ("Session ID is %s. Restored %d message(s). Happy Chatting!" ,
134+ m .transport .SessionID (), len (msg .messages ))
135+ // Prepend historical messages before any that arrived while loading.
136+ m .messages = append (msg .messages , m .messages ... )
137+ }
138+ content := header
139+ if len (m .messages ) > 0 {
140+ content = header + "\n " + strings .Join (m .messages , "\n " )
141+ }
142+ m .viewport .SetContent (lipgloss .
143+ NewStyle ().
144+ Width (m .viewport .Width ).
145+ Render (content ),
146+ )
147+ m .viewport .GotoBottom ()
148+
91149 case tea.WindowSizeMsg :
92150 m .viewport .Width = msg .Width
93151 m .textarea .SetWidth (msg .Width )
@@ -114,14 +172,16 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
114172 m .err = err
115173 return m , tiCmd
116174 }
117- go func () {
118- m .transport .Store ().AddChatEntry (
119- m .transport .SessionID (),
120- []byte (text ),
121- metadata .Timestamp (),
122- kamune .SenderLocal ,
123- )
124- }()
175+ if err := m .transport .Store ().AddChatEntry (
176+ m .transport .SessionID (),
177+ []byte (text ),
178+ metadata .Timestamp (),
179+ kamune .SenderLocal ,
180+ ); err != nil {
181+ slog .Error ("failed to persist sent chat entry" ,
182+ slog .String ("session_id" , m .transport .SessionID ()),
183+ slog .Any ("error" , err ))
184+ }
125185 prefix := fmt .Sprintf (
126186 "[%s] You: " ,
127187 metadata .Timestamp ().Format (time .DateTime ),
0 commit comments