feat: TUI room creation + daemon-side room persistence

/room <name> in the TUI sends create_room to the daemon, which persists
it in the rooms SQLite table and echoes room_created back. state_snapshot
now includes persisted rooms so they survive reconnects. Tab navigation
and room rendering pick them up automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Fredrik Johansson
2026-06-26 22:26:12 +02:00
parent 1308082c7b
commit 340735f992
4 changed files with 73 additions and 1 deletions

View File

@@ -28,6 +28,11 @@ CREATE TABLE IF NOT EXISTS peers (
alias TEXT NOT NULL,
last_seen DATETIME NOT NULL
);
CREATE TABLE IF NOT EXISTS rooms (
name TEXT PRIMARY KEY,
created_at DATETIME NOT NULL
);
`
// Store is a local SQLite-backed message and peer store.
@@ -119,6 +124,33 @@ func (s *Store) RecentMessages(room string, limit int) ([]proto.ChatMessage, err
return msgs, rows.Err()
}
// SaveRoom persists a room name. Duplicate names are silently ignored.
func (s *Store) SaveRoom(name string) error {
_, err := s.db.Exec(
`INSERT OR IGNORE INTO rooms (name, created_at) VALUES (?, ?)`,
name, time.Now().UTC(),
)
return err
}
// Rooms returns all persisted room names, ordered by creation time.
func (s *Store) Rooms() ([]string, error) {
rows, err := s.db.Query(`SELECT name FROM rooms ORDER BY created_at`)
if err != nil {
return nil, err
}
defer rows.Close()
var out []string
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
return nil, err
}
out = append(out, name)
}
return out, rows.Err()
}
// KnownPeers returns all peers seen since this daemon started storing data.
func (s *Store) KnownPeers() (map[proto.PeerID]string, error) {
rows, err := s.db.Query(`SELECT peer_id, alias FROM peers`)