WIP: новая схема сообщений и push (не проверено)

This commit is contained in:
AidarKC
2026-04-19 20:41:58 +03:00
parent f0b560ec06
commit cc59bd18ee
27 changed files with 1668 additions and 94 deletions
+144 -2
View File
@@ -1,6 +1,7 @@
import { chatMessages, wallet } from './mock-data.js';
import { AuthService } from './services/auth-service.js';
import { clearClientAuthData } from './services/key-vault.js';
import { listStoredMessages, putStoredMessage } from './services/message-store.js';
const clone = (value) => JSON.parse(JSON.stringify(value));
const SESSION_STORAGE_KEY = 'shine-ui-current-session-v1';
@@ -130,6 +131,8 @@ function createInitialState({ withStoredSession = true } = {}) {
contacts: [],
appLog: [],
incomingDedup: {},
knownMessageKeys: {},
outgoingTempSeq: 1,
notificationsTab: 'replies',
pageLabelCollapsed: false,
session: {
@@ -199,6 +202,55 @@ export const authService = new AuthService(state.entrySettings.shineServer);
let onSessionReset = null;
let onSessionAuthorized = null;
function persistMessageRecord(chatId, row) {
if (!chatId || !row?.messageKey) return;
void putStoredMessage({
messageKey: row.messageKey,
chatId,
from: row.from || 'in',
text: String(row.text || ''),
baseKey: String(row.baseKey || ''),
messageType: Number(row.messageType || 0),
rawBlobB64: String(row.rawBlobB64 || ''),
unread: Boolean(row.unread),
firstTick: Boolean(row.firstTick),
secondTick: Boolean(row.secondTick),
readReceiptSent: Boolean(row.readReceiptSent),
refBaseKey: String(row.refBaseKey || ''),
ts: Date.now(),
}).catch(() => {});
}
export async function hydrateMessagesFromStore() {
try {
const rows = await listStoredMessages();
rows
.sort((a, b) => Number(a?.ts || 0) - Number(b?.ts || 0))
.forEach((row) => {
const chatId = String(row?.chatId || '').trim();
const messageKey = String(row?.messageKey || '').trim();
if (!chatId || !messageKey) return;
if (state.knownMessageKeys[messageKey]) return;
state.knownMessageKeys[messageKey] = true;
getChatMessages(chatId).push({
from: row.from === 'out' ? 'out' : 'in',
text: String(row.text || ''),
messageKey,
baseKey: String(row.baseKey || ''),
messageType: Number(row.messageType || 0),
rawBlobB64: String(row.rawBlobB64 || ''),
unread: Boolean(row.unread),
firstTick: Boolean(row.firstTick),
secondTick: Boolean(row.secondTick),
readReceiptSent: Boolean(row.readReceiptSent),
refBaseKey: String(row.refBaseKey || ''),
});
});
} catch {
// ignore broken storage
}
}
export function getChatMessages(chatId) {
if (!state.chats[chatId]) {
state.chats[chatId] = [];
@@ -209,7 +261,7 @@ export function getChatMessages(chatId) {
export function addChatMessage(chatId, text) {
const message = text.trim();
if (!message) return;
getChatMessages(chatId).push({ from: 'out', text: message });
getChatMessages(chatId).push({ from: 'out', text: message, firstTick: false, secondTick: false, unread: false });
}
@@ -218,10 +270,100 @@ export function addIncomingMessage(chatId, text, messageId = '') {
if (!msg) return false;
if (messageId && state.incomingDedup[messageId]) return false;
if (messageId) state.incomingDedup[messageId] = true;
getChatMessages(chatId).push({ from: 'in', text: msg, messageId });
getChatMessages(chatId).push({ from: 'in', text: msg, messageId, unread: true });
return true;
}
export function addOutgoingPendingMessage(chatId, text) {
const msg = String(text || '').trim();
if (!msg) return null;
const tempId = `tmp-${Date.now()}-${state.outgoingTempSeq++}`;
getChatMessages(chatId).push({
from: 'out',
text: msg,
tempId,
firstTick: false,
secondTick: false,
unread: false,
});
return tempId;
}
export function markOutgoingSent(tempId, { messageKey = '', baseKey = '' } = {}) {
if (!tempId) return;
const keys = Object.keys(state.chats || {});
keys.forEach((chatId) => {
const list = getChatMessages(chatId);
const row = list.find((item) => item?.tempId === tempId);
if (!row) return;
row.firstTick = true;
row.messageKey = messageKey || row.messageKey || '';
row.baseKey = baseKey || row.baseKey || '';
if (messageKey) {
state.knownMessageKeys[messageKey] = true;
persistMessageRecord(chatId, row);
}
});
}
export function markOutgoingReadByBaseKey(baseKey) {
if (!baseKey) return;
const keys = Object.keys(state.chats || {});
keys.forEach((chatId) => {
const list = getChatMessages(chatId);
list.forEach((row) => {
if (row?.from !== 'out') return;
if (row.baseKey === baseKey) {
row.secondTick = true;
persistMessageRecord(chatId, row);
}
});
});
}
export function addSignedMessageToChat({
chatId,
messageKey,
baseKey = '',
from = 'in',
text = '',
messageType = 1,
unread = false,
rawBlobB64 = '',
refBaseKey = '',
} = {}) {
const id = String(messageKey || '').trim();
if (!chatId || !id) return false;
if (state.knownMessageKeys[id]) return false;
state.knownMessageKeys[id] = true;
const row = {
from: from === 'out' ? 'out' : 'in',
text: String(text || ''),
messageKey: id,
baseKey: String(baseKey || ''),
messageType: Number(messageType || 0),
rawBlobB64: String(rawBlobB64 || ''),
unread: Boolean(unread),
refBaseKey: String(refBaseKey || ''),
firstTick: from === 'out',
secondTick: false,
};
getChatMessages(chatId).push(row);
persistMessageRecord(chatId, row);
return true;
}
export function markChatRead(chatId) {
const list = getChatMessages(chatId);
list.forEach((row) => {
if (row?.from === 'in') {
row.unread = false;
persistMessageRecord(chatId, row);
}
});
}
export function setContacts(list) {
state.contacts = Array.isArray(list) ? [...list] : [];
}