import 'dart:convert'; import 'package:commons_core/commons_core.dart'; import '../security/secret_store.dart'; /// Persists a 1:1 chat history, keystore-backed (so no plaintext at rest). A /// capped, per-peer JSON list — recent history survives leaving the chat. Small /// and simple on purpose; the encrypted Drift DB is the eventual home if chats /// grow large. class MessageStore { MessageStore(this._store); final SecretStore _store; static const _prefix = 'tane.social.chat.'; /// Keep only the most recent [_cap] messages per conversation, to bound the /// keystore entry size. static const _cap = 200; String _key(String peerPubkey) => '$_prefix$peerPubkey'; /// Messages exchanged with [peerPubkey], oldest first. Future> history(String peerPubkey) async { final raw = await _store.read(_key(peerPubkey)); if (raw == null || raw.isEmpty) return const []; final list = jsonDecode(raw) as List; return [ for (final m in list.cast>()) PrivateMessage( fromPubkey: m['from'] as String, text: m['text'] as String, at: DateTime.fromMillisecondsSinceEpoch(m['at'] as int), ), ]; } /// Appends [message] to the conversation with [peerPubkey] (trimming to the /// cap). Future append(String peerPubkey, PrivateMessage message) async { final next = [...await history(peerPubkey), message]; final capped = next.length > _cap ? next.sublist(next.length - _cap) : next; await _store.write( _key(peerPubkey), jsonEncode([ for (final m in capped) { 'from': m.fromPubkey, 'text': m.text, 'at': m.at.millisecondsSinceEpoch, }, ]), ); } }