mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-08-06 16:53:38 +02:00
Fix same-second same-message collision in room servers with per-sender disambiguation at DB level
This commit is contained in:
@@ -161,6 +161,80 @@ describe('getMessageContentKey', () => {
|
||||
|
||||
expect(getMessageContentKey(msg1)).toBe(getMessageContentKey(msg2));
|
||||
});
|
||||
|
||||
it('PRIV messages with different sender_key produce different keys (room dedup)', () => {
|
||||
const msg1 = createMessage({
|
||||
type: 'PRIV',
|
||||
conversation_key: 'room_pubkey',
|
||||
text: 'ok',
|
||||
sender_timestamp: 1700000000,
|
||||
sender_key: 'alice_key',
|
||||
});
|
||||
const msg2 = createMessage({
|
||||
type: 'PRIV',
|
||||
conversation_key: 'room_pubkey',
|
||||
text: 'ok',
|
||||
sender_timestamp: 1700000000,
|
||||
sender_key: 'bob_key',
|
||||
});
|
||||
|
||||
expect(getMessageContentKey(msg1)).not.toBe(getMessageContentKey(msg2));
|
||||
});
|
||||
|
||||
it('PRIV messages with same sender_key still dedup (true room echo)', () => {
|
||||
const msg1 = createMessage({
|
||||
type: 'PRIV',
|
||||
conversation_key: 'room_pubkey',
|
||||
text: 'ok',
|
||||
sender_timestamp: 1700000000,
|
||||
sender_key: 'alice_key',
|
||||
});
|
||||
const msg2 = createMessage({
|
||||
type: 'PRIV',
|
||||
conversation_key: 'room_pubkey',
|
||||
text: 'ok',
|
||||
sender_timestamp: 1700000000,
|
||||
sender_key: 'alice_key',
|
||||
});
|
||||
|
||||
expect(getMessageContentKey(msg1)).toBe(getMessageContentKey(msg2));
|
||||
});
|
||||
|
||||
it('CHAN messages ignore sender_key (channel dedup unchanged)', () => {
|
||||
const msg1 = createMessage({
|
||||
type: 'CHAN',
|
||||
text: 'hello',
|
||||
sender_timestamp: 1700000000,
|
||||
sender_key: 'alice_key',
|
||||
});
|
||||
const msg2 = createMessage({
|
||||
type: 'CHAN',
|
||||
text: 'hello',
|
||||
sender_timestamp: 1700000000,
|
||||
sender_key: 'bob_key',
|
||||
});
|
||||
|
||||
expect(getMessageContentKey(msg1)).toBe(getMessageContentKey(msg2));
|
||||
});
|
||||
|
||||
it('PRIV messages with null sender_key still dedup normally', () => {
|
||||
const msg1 = createMessage({
|
||||
type: 'PRIV',
|
||||
conversation_key: 'contact_key',
|
||||
text: 'hi',
|
||||
sender_timestamp: 1700000000,
|
||||
sender_key: null,
|
||||
});
|
||||
const msg2 = createMessage({
|
||||
type: 'PRIV',
|
||||
conversation_key: 'contact_key',
|
||||
text: 'hi',
|
||||
sender_timestamp: 1700000000,
|
||||
sender_key: null,
|
||||
});
|
||||
|
||||
expect(getMessageContentKey(msg1)).toBe(getMessageContentKey(msg2));
|
||||
});
|
||||
});
|
||||
|
||||
describe('mergePendingAck', () => {
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import type { Message } from '../types';
|
||||
|
||||
// Content identity matches the frontend's message-level dedup contract.
|
||||
// Content identity matches the backend's message-level dedup indexes.
|
||||
export function getMessageContentKey(msg: Message): string {
|
||||
// When sender_timestamp exists, dedup by content (catches radio-path duplicates with different IDs).
|
||||
// When null, include msg.id so each message gets a unique key — avoids silently dropping
|
||||
// different messages that share the same text and received_at second.
|
||||
const ts = msg.sender_timestamp ?? `r${msg.received_at}-${msg.id}`;
|
||||
return `${msg.type}-${msg.conversation_key}-${msg.text}-${ts}`;
|
||||
// For incoming PRIV messages (room-server posts), include sender_key so that
|
||||
// two different room participants sending identical text in the same second
|
||||
// are not collapsed. Mirrors idx_messages_incoming_priv_dedup.
|
||||
const senderSuffix = msg.type === 'PRIV' && msg.sender_key ? `-${msg.sender_key}` : '';
|
||||
return `${msg.type}-${msg.conversation_key}-${msg.text}-${ts}${senderSuffix}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user