working on messages sync

This commit is contained in:
koplenov 2026-05-09 19:51:06 +03:00
parent be4a3e928c
commit 1c288a9b47

View file

@ -7,21 +7,22 @@
status: string
}
type Xmpp_message = {
id: string
from: string
to: string
body: string
time: number
nick?: string // sender nick for MUC groupchat messages
media_uri?: string
media_mime?: string
media_name?: string
media_kind?: Media_type
media_size?: number
media_hash?: string
media_hash_algo?: string
}
type Xmpp_message = {
id: string
from: string
to: string
body: string
time: number
nick?: string // sender nick for MUC groupchat messages
mam_id?: string // archive result id for MAM pagination
media_uri?: string
media_mime?: string
media_name?: string
media_kind?: Media_type
media_size?: number
media_hash?: string
media_hash_algo?: string
}
type Xmpp_room = {
jid: string
@ -44,6 +45,7 @@
body: string
time: number
nick?: string
mam_id?: string
media_uri?: string
media_mime?: string
media_name?: string
@ -317,6 +319,7 @@ private _getBody(el: Element): string | null {
// XEP-0313 for MUC: query sent TO the room, no "with" filter, optional end-timestamp to avoid duplicating join-history
request_mam_room(room_jid: string, max = 50, before_id?: string, before_time?: number): void {
if (!this._ws) return
room_jid = room_jid.split('/')[0]
const qid = this._id()
const id = this._id()
this._mam_iqs.set(id, room_jid)
@ -341,6 +344,7 @@ private _getBody(el: Element): string | null {
// XEP-0313: request last `max` messages with a given peer; pass `before_id` for pagination
request_mam(with_jid: string, max = 50, before_id?: string): void {
if (!this._ws) return
with_jid = with_jid.split('/')[0]
const qid = this._id()
const id = this._id()
this._mam_iqs.set(id, with_jid)
@ -662,11 +666,14 @@ private _handle_message(el: Element) {
const from = slash >= 0 ? from_full.slice(0, slash) : from_full
// Only groupchat carries a meaningful nick after the slash; for 1:1 the resource is just a device id.
const nick = type === 'groupchat' && slash >= 0 ? from_full.slice(slash + 1) : undefined
const stanza_id = msg.getAttribute('id') || result.getAttribute('id') || this._id()
const mam_id = result.getAttribute('id') || stanza_id
this.on_mam_message?.({
id: result.getAttribute('id') || this._id(),
id: stanza_id,
from,
to: (msg.getAttribute('to') || '').split('/')[0],
body, time,
mam_id,
...(nick !== undefined ? { nick } : {}),
...(media || {}),
})
@ -705,6 +712,7 @@ private _handle_message(el: Element) {
private _rec = new Map<string, { recorder: MediaRecorder; chunks: Blob[]; stream: MediaStream }>()
private _history_loaded = new Set<string>()
private _mam_oldest = new Map<string, string>() // jid → oldest MAM result id
private _mam_oldest_time = new Map<string, number>() // jid → oldest MAM result time
private _loading_more = new Set<string>()
private _fin_count = new Map<string, number>()
private _scroll_setup = new Set<string>() // scroll listener installed
@ -1281,9 +1289,12 @@ private _handle_message(el: Element) {
const bare = this.my_jid().split('/')[0]
const peer = msg.from === bare ? msg.to : msg.from
if (peer) {
const cur = this._mam_oldest.get(peer)
const cur_time = cur ? (this._msg_by_id.get(cur)?.time ?? Infinity) : Infinity
if (msg.time < cur_time) this._mam_oldest.set(peer, msg.id)
const oldest_id = msg.mam_id || msg.id
const cur_time = this._mam_oldest_time.get(peer) ?? Infinity
if (msg.time < cur_time) {
this._mam_oldest.set(peer, oldest_id)
this._mam_oldest_time.set(peer, msg.time)
}
}
// MAM-on-delivery: server may wrap live messages in <result>; notify if recent
if (Date.now() - msg.time < 30_000 && msg.from !== bare) {
@ -1471,6 +1482,8 @@ private _handle_message(el: Element) {
this._scroll_setup.delete(jid)
this._oldest_time.delete(jid)
this._mam_oldest.delete(jid)
this._mam_oldest_time.delete(jid)
this._history_loaded.delete(jid)
this._fin_count.delete(jid)
this.messages_ver(this.messages_ver() + 1)
this.$.$mol_state_arg.value('chat', null)
@ -1852,7 +1865,13 @@ private _handle_message(el: Element) {
private _load_more_history(jid: string) {
if (this._loading_more.has(jid) || !this._conn) return
const oldest_id = this._mam_oldest.get(jid)
let oldest_id = this._mam_oldest.get(jid)
if (!oldest_id) {
const oldest_msg = this._msgs
.filter(m => m.from === jid || m.to === jid || (m.from === this.my_jid().split('/')[0] && m.to === jid) || (m.from === jid && m.to === this.my_jid().split('/')[0]))
.sort((a, b) => a.time - b.time)[0]
if (oldest_msg?.mam_id) oldest_id = oldest_msg.mam_id
}
this._loading_more.add(jid)
if (this._rooms.has(jid)) {
// cursor available after first MAM batch; otherwise use timestamp to avoid duplicating join-history
@ -1937,6 +1956,7 @@ private _handle_message(el: Element) {
...(msg.media_size !== undefined ? { media_size: msg.media_size } : {}),
...(msg.media_hash !== undefined ? { media_hash: msg.media_hash } : {}),
...(msg.media_hash_algo !== undefined ? { media_hash_algo: msg.media_hash_algo } : {}),
...(msg.mam_id !== undefined ? { mam_id: msg.mam_id } : {}),
}
await Messages.put(doc, [account, msg.id])
} catch (e) { console.warn('[xmpp] persist failed', e) }
@ -1953,7 +1973,7 @@ private _handle_message(el: Element) {
this._loading_persisted = true
try {
for (const doc of docs) {
this._add_message({
const msg: Xmpp_message = {
id: doc.id, from: doc.from, to: doc.to,
body: doc.body, time: doc.time,
...(doc.nick !== undefined ? { nick: doc.nick } : {}),
@ -1964,7 +1984,17 @@ private _handle_message(el: Element) {
...(doc.media_size !== undefined ? { media_size: doc.media_size } : {}),
...(doc.media_hash !== undefined ? { media_hash: doc.media_hash } : {}),
...(doc.media_hash_algo !== undefined ? { media_hash_algo: doc.media_hash_algo } : {}),
})
...(doc.mam_id !== undefined ? { mam_id: doc.mam_id } : {}),
}
this._add_message(msg)
if (msg.mam_id) {
const peer = this._peer_of(msg, account)
const cur_time = this._mam_oldest_time.get(peer) ?? Infinity
if (msg.time < cur_time) {
this._mam_oldest.set(peer, msg.mam_id)
this._mam_oldest_time.set(peer, msg.time)
}
}
}
} finally {
this._loading_persisted = false