| author | Stephen Paul Weber
<singpolyma@singpolyma.net> 2024-09-24 02:56:07 UTC |
| committer | Stephen Paul Weber
<singpolyma@singpolyma.net> 2024-09-24 02:56:07 UTC |
| parent | 75543e6a5bcded1cf5c9a53c4b41583125fc1b70 |
| snikket/persistence/browser.js | +53 | -5 |
diff --git a/snikket/persistence/browser.js b/snikket/persistence/browser.js index 51cdaea..acea1f3 100644 --- a/snikket/persistence/browser.js +++ b/snikket/persistence/browser.js @@ -4,7 +4,10 @@ import { snikket as enums } from "./snikket-enums"; import { snikket } from "./snikket"; -const browser = (dbname) => { +const browser = (dbname, tokenize, stemmer) => { + if (!tokenize) tokenize = function(s) { return s.split(" "); } + if (!stemmer) stemmer = function(s) { return s; } + var db = null; function openDb(version) { var dbOpenReq = indexedDB.open(dbname, version); @@ -57,12 +60,11 @@ const browser = (dbname) => { }); } - async function hydrateMessage(value) { + function hydrateMessageSync(value) { if (!value) return null; const tx = db.transaction(["messages"], "readonly"); const store = tx.objectStore("messages"); - let replyToMessage = value.replyToMessage && await hydrateMessage((await promisifyRequest(store.openCursor(IDBKeyRange.only(value.replyToMessage))))?.value); const message = new snikket.ChatMessage(); message.localId = value.localId ? value.localId : null; @@ -77,18 +79,29 @@ const browser = (dbname) => { message.sender = value.sender && snikket.JID.parse(value.sender); message.recipients = value.recipients.map((r) => snikket.JID.parse(r)); message.replyTo = value.replyTo.map((r) => snikket.JID.parse(r)); - message.replyToMessage = replyToMessage; message.threadId = value.threadId; message.attachments = value.attachments; message.reactions = value.reactions; message.text = value.text; message.lang = value.lang; message.isGroupchat = value.isGroupchat || value.groupchat; - message.versions = await Promise.all((value.versions || []).map(hydrateMessage)); message.payloads = (value.payloads || []).map(snikket.Stanza.parse); return message; } + async function hydrateMessage(value) { + if (!value) return null; + + const message = hydrateMessageSync(value); + const tx = db.transaction(["messages"], "readonly"); + const store = tx.objectStore("messages"); + const replyToMessage = value.replyToMessage && await hydrateMessage((await promisifyRequest(store.openCursor(IDBKeyRange.only(value.replyToMessage))))?.value); + + message.replyToMessage = replyToMessage; + message.versions = await Promise.all((value.versions || []).map(hydrateMessage)); + return message; + } + function serializeMessage(account, message) { return { ...message, @@ -391,6 +404,41 @@ const browser = (dbname) => { } }, + searchMessages: function(account, chatId, q, callback) { + const tx = db.transaction(["messages"], "readonly"); + const store = tx.objectStore("messages"); + var cursor; + if (chatId) { + cursor = store.index("chats").openCursor( + IDBKeyRange.bound([account, chatId], [account, chatId, []]), + "prev" + ); + } else if (account) { + cursor = store.index("accounts").openCursor( + IDBKeyRange.bound([account], [account, []]), + "prev" + ); + } else { + cursor = store.openCursor(undefined, "prev"); + } + const qTok = new Set(tokenize(q).map(stemmer)); + cursor.onsuccess = (event) => { + if (event.target.result) { + const value = event.target.result.value; + if (new Set(tokenize(value.text).map(stemmer)).isSupersetOf(qTok)) { + if (!callback(q, hydrateMessageSync(value))) return; + } + event.target.result.continue(); + } else { + callback(null); + } + } + cursor.onerror = (event) => { + console.error(event); + callback(null); + } + }, + getMediaUri: function(hashAlgorithm, hash, callback) { (async function() { var niUrl;