diff --git a/Example/example.ts b/Example/example.ts index e653c3f..ff6dc9a 100644 --- a/Example/example.ts +++ b/Example/example.ts @@ -9,6 +9,7 @@ import { WA_MESSAGE_STUB_TYPES, ReconnectMode, ProxyAgent, + waChatKey, } from '../src/WAConnection/WAConnection' import * as fs from 'fs' @@ -21,6 +22,7 @@ async function example() { conn.connectOptions.regenerateQRIntervalMs = 5000 // attempt to reconnect at most 10 times conn.connectOptions.maxRetries = 10 + conn.chatOrderingKey = waChatKey(true) // order chats such that pinned chats are on top conn.on ('credentials-updated', () => { // save credentials whenever updated @@ -35,11 +37,12 @@ async function example() { //conn.connectOptions.agent = ProxyAgent ('http://1.0.180.120:8080') await conn.connect() - const unread = await conn.loadAllUnreadMessages () - console.log('oh hello ' + conn.user.name + ' (' + conn.user.jid + ')') console.log('you have ' + conn.chats.length + ' chats & ' + Object.keys(conn.contacts).length + ' contacts') - console.log ('you have ' + unread.length + ' unread messages') + + // uncomment to load all unread messages + //const unread = await conn.loadAllUnreadMessages () + //console.log ('you have ' + unread.length + ' unread messages') /* Note: one can take this auth_info.json file and login again from any computer without having to scan the QR code, and get full access to one's WhatsApp. Despite the convenience, be careful with this file */ diff --git a/package.json b/package.json index 0562c80..dc2033c 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "url": "git@github.com:adiwajshing/baileys.git" }, "dependencies": { - "@adiwajshing/keyed-db": "^0.1.5", + "@adiwajshing/keyed-db": "^0.1.8", "curve25519-js": "^0.0.4", "futoin-hkdf": "^1.3.2", "https-proxy-agent": "^5.0.0", diff --git a/src/WAConnection/0.Base.ts b/src/WAConnection/0.Base.ts index 52774e4..ccd4e1c 100644 --- a/src/WAConnection/0.Base.ts +++ b/src/WAConnection/0.Base.ts @@ -55,7 +55,7 @@ export class WAConnection extends EventEmitter { /** Whether the phone is connected */ phoneConnected: boolean = false /** key to use to order chats */ - chatOrderingKey = Utils.WA_CHAT_KEY + chatOrderingKey = Utils.waChatKey(false) /** log messages */ shouldLogMessages = false @@ -63,7 +63,7 @@ export class WAConnection extends EventEmitter { maxCachedMessages = 50 - chats: KeyedDB = new KeyedDB (Utils.WA_CHAT_KEY, value => value.jid) + chats = new KeyedDB (Utils.waChatKey(false), value => value.jid) contacts: { [k: string]: WAContact } = {} /** Data structure of tokens & IDs used to establish one's identiy to WhatsApp Web */ diff --git a/src/WAConnection/3.Connect.ts b/src/WAConnection/3.Connect.ts index d68fc01..80ed547 100644 --- a/src/WAConnection/3.Connect.ts +++ b/src/WAConnection/3.Connect.ts @@ -167,7 +167,7 @@ export class WAConnection extends Base { * Must be called immediately after connect */ protected receiveChatsAndContacts(waitOnlyForLast: boolean) { - const chats = new KeyedDB(this.chatOrderingKey, c => c.jid) + const chats = new KeyedDB(this.chatOrderingKey, c => c.jid) const contacts = {} let receivedContacts = false diff --git a/src/WAConnection/5.User.ts b/src/WAConnection/5.User.ts index 1b81584..2f723ec 100644 --- a/src/WAConnection/5.User.ts +++ b/src/WAConnection/5.User.ts @@ -6,7 +6,7 @@ import { WAMetric, WAFlag, } from '../WAConnection/Constants' -import { generateProfilePicture, WA_CHAT_KEY, whatsappID, unixTimestampSeconds } from './Utils' +import { generateProfilePicture, waChatKey, whatsappID, unixTimestampSeconds } from './Utils' import { Mutex } from './Mutex' // All user related functions -- get profile picture, set status etc. @@ -96,7 +96,7 @@ export class WAConnection extends Base { * @param searchString optionally search for users * @returns the chats & the cursor to fetch the next page */ - async loadChats (count: number, before: number | null, options: WALoadChatOptions = {}) { + async loadChats (count: number, before: string | null, options: WALoadChatOptions = {}) { const chats = this.chats.paginated (before, count, options && (chat => ( (typeof options?.custom !== 'function' || options?.custom(chat)) && (typeof options?.searchString === 'undefined' || chat.name?.includes (options.searchString) || chat.jid?.startsWith(options.searchString)) @@ -108,7 +108,7 @@ export class WAConnection extends Base { )) ) } - const cursor = (chats[chats.length-1] && chats.length >= count) && this.chatOrderingKey (chats[chats.length-1]) + const cursor = (chats[chats.length-1] && chats.length >= count) && this.chatOrderingKey.key (chats[chats.length-1]) return { chats, cursor } } /** diff --git a/src/WAConnection/Constants.ts b/src/WAConnection/Constants.ts index 01c4325..dbbd6e7 100644 --- a/src/WAConnection/Constants.ts +++ b/src/WAConnection/Constants.ts @@ -207,7 +207,7 @@ export interface WAChat { name?: string // Baileys added properties - messages: KeyedDB + messages: KeyedDB imgUrl?: string } export enum WAMetric { diff --git a/src/WAConnection/Utils.ts b/src/WAConnection/Utils.ts index 96391b8..3cebe77 100644 --- a/src/WAConnection/Utils.ts +++ b/src/WAConnection/Utils.ts @@ -24,18 +24,14 @@ export const Browsers = { /** The appropriate browser based on your OS & release */ appropriate: browser => [ platformMap [platform()] || 'Ubuntu', browser, release() ] as [string, string, string] } -function hashCode(s: string) { - for(var i = 0, h = 0; i < s.length; i++) - h = Math.imul(31, h) + s.charCodeAt(i) | 0; - return h; -} export const toNumber = (t: Long | number) => (t['low'] || t) as number - -export const WA_CHAT_KEY = (c: WAChat) => ((c.t*100000) + (hashCode(c.jid)%100000))*-1 // -1 to sort descending -export const WA_CHAT_KEY_PIN = (c: WAChat) => ((c.t*100000)*(c.pin ? 2 : 1) + (hashCode(c.jid)%100000))*-1 // -1 to sort descending - +export const waChatKey = (pin: boolean) => ({ + key: (c: WAChat) => (pin ? (c.pin ? '1' : '0') : '') + c.t.toString(16).padStart(8, '0') + c.jid, + compare: (k1: string, k2: string) => k2.localeCompare (k1) +}) export const WA_MESSAGE_KEY = (m: WAMessage) => toNumber (m.messageTimestamp)*1000 + (m['epoch'] || 0)%1000 export const WA_MESSAGE_ID = (m: WAMessage) => GET_MESSAGE_ID (m.key) + export const GET_MESSAGE_ID = (key: WAMessageKey) => `${key.id}|${key.fromMe ? 1 : 0}` export const whatsappID = (jid: string) => jid?.replace ('@c.us', '@s.whatsapp.net') diff --git a/yarn.lock b/yarn.lock index eebfa0f..74c41e0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@adiwajshing/keyed-db@^0.1.5": - version "0.1.7" - resolved "https://registry.yarnpkg.com/@adiwajshing/keyed-db/-/keyed-db-0.1.7.tgz#49a0a2703d1fd09fe2626a39a39212950f9f214b" - integrity sha512-MJdTNGUynoQD+zk3ndCw+P1kuAeSZhqF+Mt3fnlgntBlZnU0XNqV2L2RGDO1ciCfwFaxjzMxLqzxx/CJoDeTHA== +"@adiwajshing/keyed-db@^0.1.8": + version "0.1.8" + resolved "https://registry.yarnpkg.com/@adiwajshing/keyed-db/-/keyed-db-0.1.8.tgz#3c8a16216e7334e16d969398c8d37837f7b8b788" + integrity sha512-UEP/94y3Ljihg2XpnI3BRT1Ucc9anP5pP+L5lLZgoWrMzn7xnK5UipLRMC5Yo7mThfZ4xyFVEX8yowZzPFv7dw== "@babel/runtime@^7.7.2": version "7.11.2" @@ -721,37 +721,37 @@ error-ex@^1.2.0: is-arrayish "^0.2.1" es-abstract@^1.17.0-next.1, es-abstract@^1.17.4, es-abstract@^1.17.5: - version "1.17.6" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a" - integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw== + version "1.17.7" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.7.tgz#a4de61b2f66989fc7421676c1cb9787573ace54c" + integrity sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g== dependencies: es-to-primitive "^1.2.1" function-bind "^1.1.1" has "^1.0.3" has-symbols "^1.0.1" - is-callable "^1.2.0" - is-regex "^1.1.0" - object-inspect "^1.7.0" + is-callable "^1.2.2" + is-regex "^1.1.1" + object-inspect "^1.8.0" object-keys "^1.1.1" - object.assign "^4.1.0" + object.assign "^4.1.1" string.prototype.trimend "^1.0.1" string.prototype.trimstart "^1.0.1" -es-abstract@^1.18.0-next.0: - version "1.18.0-next.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.0.tgz#b302834927e624d8e5837ed48224291f2c66e6fc" - integrity sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ== +es-abstract@^1.18.0-next.0, es-abstract@^1.18.0-next.1: + version "1.18.0-next.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.1.tgz#6e3a0a4bda717e5023ab3b8e90bec36108d22c68" + integrity sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA== dependencies: es-to-primitive "^1.2.1" function-bind "^1.1.1" has "^1.0.3" has-symbols "^1.0.1" - is-callable "^1.2.0" + is-callable "^1.2.2" is-negative-zero "^2.0.0" is-regex "^1.1.1" object-inspect "^1.8.0" object-keys "^1.1.1" - object.assign "^4.1.0" + object.assign "^4.1.1" string.prototype.trimend "^1.0.1" string.prototype.trimstart "^1.0.1" @@ -969,9 +969,9 @@ he@1.2.0: integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== highlight.js@^10.0.0: - version "10.2.0" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.2.0.tgz#367151bcf813adebc54822f1cb51d2e1e599619f" - integrity sha512-OryzPiqqNCfO/wtFo619W+nPYALM6u7iCQkum4bqRmmlcTikOkmlL06i009QelynBPAlNByTQU6cBB2cOBQtCw== + version "10.2.1" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.2.1.tgz#09784fe2e95612abbefd510948945d4fe6fa9668" + integrity sha512-A+sckVPIb9zQTUydC9lpRX1qRFO/N0OKEh0NwIr65ckvWA/oMY8v9P3+kGRK3w2ULSh9E8v5MszXafodQ6039g== hosted-git-info@^2.1.4: version "2.8.8" @@ -1043,7 +1043,7 @@ is-buffer@~2.0.3: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623" integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A== -is-callable@^1.1.4, is-callable@^1.2.0: +is-callable@^1.1.4, is-callable@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9" integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA== @@ -1112,7 +1112,7 @@ is-plain-obj@^1.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= -is-regex@^1.1.0, is-regex@^1.1.1: +is-regex@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg== @@ -1410,18 +1410,18 @@ object-assign@^4.0.1: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= -object-inspect@^1.7.0, object-inspect@^1.8.0: +object-inspect@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA== object-is@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.2.tgz#c5d2e87ff9e119f78b7a088441519e2eec1573b6" - integrity sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ== + version "1.1.3" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.3.tgz#2e3b9e65560137455ee3bd62aec4d90a2ea1cc81" + integrity sha512-teyqLvFWzLkq5B9ki8FVWA902UER2qkxmdA4nLf+wjOLAWgxzCWZNCxpDq9MvE8MmhWNr+I8w3BN49Vx36Y6Xg== dependencies: define-properties "^1.1.3" - es-abstract "^1.17.5" + es-abstract "^1.18.0-next.1" object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" @@ -1438,7 +1438,7 @@ object.assign@4.1.0: has-symbols "^1.0.0" object-keys "^1.0.11" -object.assign@^4.1.0: +object.assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.1.tgz#303867a666cdd41936ecdedfb1f8f3e32a478cdd" integrity sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==