fix: key messages by networkId:room to prevent collision across networks

Two networks sharing a room name (e.g. "general") were clobbering each
other's message lists. Now keyed by `${networkId}:${room}` throughout
the web store, MessagePane, and Sidebar DM detection.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Fredrik Johansson
2026-06-29 16:55:16 +02:00
parent dab5387cbd
commit f5fb0862ff
3 changed files with 19 additions and 11 deletions

View File

@@ -16,8 +16,9 @@ export function MessagePane() {
const { messages, historyCutoff, activeRoom, activeNetworkId, localPeer, connectedPeers, knownPeers, send } = useWaste() const { messages, historyCutoff, activeRoom, activeNetworkId, localPeer, connectedPeers, knownPeers, send } = useWaste()
const [draft, setDraft] = useState('') const [draft, setDraft] = useState('')
const bottomRef = useRef<HTMLDivElement>(null) const bottomRef = useRef<HTMLDivElement>(null)
const roomMessages = messages[activeRoom] ?? [] const msgKey = activeNetworkId ? `${activeNetworkId}:${activeRoom}` : activeRoom
const cutoff = historyCutoff[activeRoom] ?? 0 const roomMessages = messages[msgKey] ?? []
const cutoff = historyCutoff[msgKey] ?? 0
// Find the index of the first live message (ts > cutoff). // Find the index of the first live message (ts > cutoff).
// The divider appears just before this index, or at the top if all are history. // The divider appears just before this index, or at the top if all are history.

View File

@@ -42,9 +42,15 @@ export function Sidebar() {
const netCustomRooms = activeNetworkId ? (customRooms[activeNetworkId] ?? []) : [] const netCustomRooms = activeNetworkId ? (customRooms[activeNetworkId] ?? []) : []
const rooms = ['general', ...netCustomRooms] const rooms = ['general', ...netCustomRooms]
Object.keys(messages).forEach(r => { if (activeNetworkId) {
if (r.startsWith('dm:') && !rooms.includes(r)) rooms.push(r) const prefix = `${activeNetworkId}:dm:`
}) Object.keys(messages).forEach(k => {
if (k.startsWith(prefix)) {
const r = k.slice(activeNetworkId.length + 1)
if (!rooms.includes(r)) rooms.push(r)
}
})
}
function submitNewRoom(e: React.FormEvent) { function submitNewRoom(e: React.FormEvent) {
e.preventDefault() e.preventDefault()

View File

@@ -283,14 +283,14 @@ export const useWaste = create<WasteState>((set, get) => ({
case 'message_received': { case 'message_received': {
if (msg.message) { if (msg.message) {
const m = msg.message const m = msg.message
const room = m.room const key = `${msg.network_id}:${m.room}`
const fromId = String(m.from) const fromId = String(m.from)
set(s => { set(s => {
const existing = s.messages[room] ?? [] const existing = s.messages[key] ?? []
if (m.mid && existing.some(e => e.mid === m.mid)) return s if (m.mid && existing.some(e => e.mid === m.mid)) return s
const prev = s.peerStatus[fromId] ?? {} const prev = s.peerStatus[fromId] ?? {}
return { return {
messages: { ...s.messages, [room]: [...existing, m] }, messages: { ...s.messages, [key]: [...existing, m] },
peerStatus: { ...s.peerStatus, [fromId]: { ...prev, lastSeen: m.ts } }, peerStatus: { ...s.peerStatus, [fromId]: { ...prev, lastSeen: m.ts } },
} }
}) })
@@ -378,16 +378,17 @@ export const useWaste = create<WasteState>((set, get) => ({
const room = msg.room const room = msg.room
const incoming = (msg.messages ?? []) as ChatMessage[] const incoming = (msg.messages ?? []) as ChatMessage[]
if (!room || incoming.length === 0) break if (!room || incoming.length === 0) break
const key = `${msg.network_id}:${room}`
set(s => { set(s => {
const existing = s.messages[room] ?? [] const existing = s.messages[key] ?? []
const existingMids = new Set(existing.map(m => m.mid).filter(Boolean)) const existingMids = new Set(existing.map(m => m.mid).filter(Boolean))
const fresh = incoming.filter(m => !m.mid || !existingMids.has(m.mid)) const fresh = incoming.filter(m => !m.mid || !existingMids.has(m.mid))
if (fresh.length === 0) return s if (fresh.length === 0) return s
const merged = [...fresh, ...existing].sort((a, b) => a.ts - b.ts) const merged = [...fresh, ...existing].sort((a, b) => a.ts - b.ts)
const cutoff = fresh[fresh.length - 1]?.ts ?? 0 const cutoff = fresh[fresh.length - 1]?.ts ?? 0
return { return {
messages: { ...s.messages, [room]: merged }, messages: { ...s.messages, [key]: merged },
historyCutoff: { ...s.historyCutoff, [room]: cutoff }, historyCutoff: { ...s.historyCutoff, [key]: cutoff },
} }
}) })
break break