mirror of
https://github.com/FranP-code/Baileys.git
synced 2025-10-13 00:32:22 +00:00
More accurate phone connection detection
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { WAConnection, MessageLogLevel, MessageOptions, MessageType, unixTimestampSeconds, toNumber, GET_MESSAGE_ID, waMessageKey } from '../WAConnection/WAConnection'
|
import { WAConnection, MessageOptions, MessageType, unixTimestampSeconds, toNumber, GET_MESSAGE_ID, waMessageKey } from '../WAConnection/WAConnection'
|
||||||
import * as assert from 'assert'
|
import * as assert from 'assert'
|
||||||
import {promises as fs} from 'fs'
|
import {promises as fs} from 'fs'
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ export const WAConnectionTest = (name: string, func: (conn: WAConnection) => voi
|
|||||||
describe(name, () => {
|
describe(name, () => {
|
||||||
const conn = new WAConnection()
|
const conn = new WAConnection()
|
||||||
conn.connectOptions.maxIdleTimeMs = 30_000
|
conn.connectOptions.maxIdleTimeMs = 30_000
|
||||||
conn.logLevel = MessageLogLevel.unhandled
|
conn.logger.level = 'debug'
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
const file = './auth_info.json'
|
const file = './auth_info.json'
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import * as assert from 'assert'
|
|||||||
import {WAConnection} from '../WAConnection/WAConnection'
|
import {WAConnection} from '../WAConnection/WAConnection'
|
||||||
import { AuthenticationCredentialsBase64, BaileysError, ReconnectMode, DisconnectReason } from '../WAConnection/Constants'
|
import { AuthenticationCredentialsBase64, BaileysError, ReconnectMode, DisconnectReason } from '../WAConnection/Constants'
|
||||||
import { delay } from '../WAConnection/Utils'
|
import { delay } from '../WAConnection/Utils'
|
||||||
import { assertChatDBIntegrity } from './Common'
|
import { assertChatDBIntegrity, testJid } from './Common'
|
||||||
|
|
||||||
describe('QR Generation', () => {
|
describe('QR Generation', () => {
|
||||||
it('should generate QR', async () => {
|
it('should generate QR', async () => {
|
||||||
@@ -73,22 +73,41 @@ describe('Test Connect', () => {
|
|||||||
})
|
})
|
||||||
it ('should disconnect & reconnect phone', async () => {
|
it ('should disconnect & reconnect phone', async () => {
|
||||||
const conn = new WAConnection ()
|
const conn = new WAConnection ()
|
||||||
|
conn.logger.level = 'debug'
|
||||||
await conn.loadAuthInfo('./auth_info.json').connect ()
|
await conn.loadAuthInfo('./auth_info.json').connect ()
|
||||||
assert.equal (conn.phoneConnected, true)
|
assert.equal (conn.phoneConnected, true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const waitForEvent = expect => new Promise (resolve => {
|
const waitForEvent = expect => new Promise (resolve => {
|
||||||
conn.on ('connection-phone-change', ({connected}) => {
|
conn.on ('connection-phone-change', ({connected}) => {
|
||||||
assert.equal (connected, expect)
|
if (connected === expect) {
|
||||||
conn.removeAllListeners ('connection-phone-change')
|
conn.removeAllListeners ('connection-phone-change')
|
||||||
resolve ()
|
resolve ()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log ('disconnect your phone from the internet')
|
console.log ('disconnect your phone from the internet')
|
||||||
|
await delay (10_000)
|
||||||
|
console.log ('phone should be disconnected now, testing...')
|
||||||
|
|
||||||
|
const messagesPromise = Promise.all (
|
||||||
|
[
|
||||||
|
conn.loadMessages (testJid, 50),
|
||||||
|
conn.getStatus (testJid),
|
||||||
|
conn.getProfilePicture (testJid).catch (() => '')
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
await waitForEvent (false)
|
await waitForEvent (false)
|
||||||
|
|
||||||
console.log ('reconnect your phone to the internet')
|
console.log ('reconnect your phone to the internet')
|
||||||
await waitForEvent (true)
|
await waitForEvent (true)
|
||||||
|
|
||||||
|
console.log ('reconnected successfully')
|
||||||
|
|
||||||
|
const final = await messagesPromise
|
||||||
|
assert.ok (final)
|
||||||
} finally {
|
} finally {
|
||||||
conn.close ()
|
conn.close ()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export class WAConnection extends EventEmitter {
|
|||||||
waitForChats: true,
|
waitForChats: true,
|
||||||
maxRetries: 5,
|
maxRetries: 5,
|
||||||
connectCooldownMs: 3000,
|
connectCooldownMs: 3000,
|
||||||
phoneResponseTime: 7500,
|
phoneResponseTime: 7_500,
|
||||||
alwaysUseTakeover: false
|
alwaysUseTakeover: false
|
||||||
}
|
}
|
||||||
/** When to auto-reconnect */
|
/** When to auto-reconnect */
|
||||||
@@ -81,6 +81,7 @@ export class WAConnection extends EventEmitter {
|
|||||||
protected encoder = new Encoder()
|
protected encoder = new Encoder()
|
||||||
protected decoder = new Decoder()
|
protected decoder = new Decoder()
|
||||||
protected pendingRequests: {resolve: () => void, reject: (error) => void}[] = []
|
protected pendingRequests: {resolve: () => void, reject: (error) => void}[] = []
|
||||||
|
protected phoneCheckInterval = undefined
|
||||||
|
|
||||||
protected referenceDate = new Date () // used for generating tags
|
protected referenceDate = new Date () // used for generating tags
|
||||||
protected lastSeen: Date = null // last keep alive received
|
protected lastSeen: Date = null // last keep alive received
|
||||||
@@ -216,13 +217,17 @@ export class WAConnection extends EventEmitter {
|
|||||||
* @param json query that was sent
|
* @param json query that was sent
|
||||||
* @param timeoutMs timeout after which the promise will reject
|
* @param timeoutMs timeout after which the promise will reject
|
||||||
*/
|
*/
|
||||||
async waitForMessage(tag: string, json?: Object, timeoutMs?: number) {
|
async waitForMessage(tag: string, json: Object, requiresPhoneConnection: boolean, timeoutMs?: number) {
|
||||||
|
if (!this.phoneCheckInterval && requiresPhoneConnection) {
|
||||||
|
this.startPhoneCheckInterval ()
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const result = await Utils.promiseTimeout(timeoutMs,
|
const result = await Utils.promiseTimeout(timeoutMs,
|
||||||
(resolve, reject) => (this.callbacks[tag] = { queryJSON: json, callback: resolve, errCallback: reject }),
|
(resolve, reject) => (this.callbacks[tag] = { queryJSON: json, callback: resolve, errCallback: reject }),
|
||||||
)
|
)
|
||||||
return result as any
|
return result as any
|
||||||
} finally {
|
} finally {
|
||||||
|
requiresPhoneConnection && this.clearPhoneCheckInterval ()
|
||||||
delete this.callbacks[tag]
|
delete this.callbacks[tag]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -239,32 +244,56 @@ export class WAConnection extends EventEmitter {
|
|||||||
* @param timeoutMs timeout after which the query will be failed (set to null to disable a timeout)
|
* @param timeoutMs timeout after which the query will be failed (set to null to disable a timeout)
|
||||||
* @param tag the tag to attach to the message
|
* @param tag the tag to attach to the message
|
||||||
*/
|
*/
|
||||||
async query({json, binaryTags, tag, timeoutMs, expect200, waitForOpen, longTag}: WAQuery) {
|
async query(q: WAQuery) {
|
||||||
|
let {json, binaryTags, tag, timeoutMs, expect200, waitForOpen, longTag, requiresPhoneConnection} = q
|
||||||
|
requiresPhoneConnection = requiresPhoneConnection !== false
|
||||||
waitForOpen = waitForOpen !== false
|
waitForOpen = waitForOpen !== false
|
||||||
if (waitForOpen) await this.waitForConnection()
|
if (waitForOpen) await this.waitForConnection()
|
||||||
|
|
||||||
tag = tag || this.generateMessageTag (longTag)
|
tag = tag || this.generateMessageTag (longTag)
|
||||||
const promise = this.waitForMessage(tag, json, timeoutMs)
|
const promise = this.waitForMessage(tag, json, requiresPhoneConnection, timeoutMs)
|
||||||
|
|
||||||
if (binaryTags) tag = await this.sendBinary(json as WANode, binaryTags, tag, longTag)
|
if (binaryTags) tag = await this.sendBinary(json as WANode, binaryTags, tag)
|
||||||
else tag = await this.sendJSON(json, tag, longTag)
|
else tag = await this.sendJSON(json, tag)
|
||||||
|
|
||||||
const response = await promise
|
const response = await promise
|
||||||
|
|
||||||
if (expect200 && response.status && Math.floor(+response.status / 100) !== 2) {
|
if (expect200 && response.status && Math.floor(+response.status / 100) !== 2) {
|
||||||
// read here: http://getstatuscode.com/599
|
// read here: http://getstatuscode.com/599
|
||||||
if (response.status === 599) {
|
if (response.status === 599) {
|
||||||
this.unexpectedDisconnect (DisconnectReason.badSession)
|
this.unexpectedDisconnect (DisconnectReason.badSession)
|
||||||
const response = await this.query ({json, binaryTags, tag, timeoutMs, expect200, waitForOpen})
|
const response = await this.query (q)
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
const message = STATUS_CODES[response.status] || 'unknown'
|
const message = STATUS_CODES[response.status] || 'unknown'
|
||||||
throw new BaileysError(
|
throw new BaileysError (
|
||||||
`Unexpected status in '${json[0] || 'generic query'}': ${STATUS_CODES[response.status]}(${response.status})`,
|
`Unexpected status in '${json[0] || 'generic query'}': ${STATUS_CODES[response.status]}(${response.status})`,
|
||||||
{query: json, message, status: response.status}
|
{query: json, message, status: response.status}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
/** interval is started when a query takes too long to respond */
|
||||||
|
protected startPhoneCheckInterval () {
|
||||||
|
// if its been a long time and we haven't heard back from WA, send a ping
|
||||||
|
this.phoneCheckInterval = setInterval (() => {
|
||||||
|
if (!this.conn) return // if disconnected, then don't do anything
|
||||||
|
|
||||||
|
this.logger.debug ('checking phone connection...')
|
||||||
|
this.sendAdminTest ()
|
||||||
|
|
||||||
|
this.phoneConnected = false
|
||||||
|
this.emit ('connection-phone-change', { connected: false })
|
||||||
|
}, this.connectOptions.phoneResponseTime)
|
||||||
|
}
|
||||||
|
protected clearPhoneCheckInterval () {
|
||||||
|
this.phoneCheckInterval && clearInterval (this.phoneCheckInterval)
|
||||||
|
this.phoneCheckInterval = undefined
|
||||||
|
}
|
||||||
|
protected async sendAdminTest () {
|
||||||
|
return this.sendJSON (['admin', 'test'])
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Send a binary encoded message
|
* Send a binary encoded message
|
||||||
* @param json the message to encode & send
|
* @param json the message to encode & send
|
||||||
@@ -335,9 +364,6 @@ export class WAConnection extends EventEmitter {
|
|||||||
protected closeInternal (reason?: DisconnectReason, isReconnecting: boolean=false) {
|
protected closeInternal (reason?: DisconnectReason, isReconnecting: boolean=false) {
|
||||||
this.logger.info (`closed connection, reason ${reason}${isReconnecting ? ', reconnecting in a few seconds...' : ''}`)
|
this.logger.info (`closed connection, reason ${reason}${isReconnecting ? ', reconnecting in a few seconds...' : ''}`)
|
||||||
|
|
||||||
this.qrTimeout && clearTimeout (this.qrTimeout)
|
|
||||||
this.debounceTimeout && clearTimeout (this.debounceTimeout)
|
|
||||||
|
|
||||||
this.state = 'close'
|
this.state = 'close'
|
||||||
this.phoneConnected = false
|
this.phoneConnected = false
|
||||||
this.lastDisconnectReason = reason
|
this.lastDisconnectReason = reason
|
||||||
@@ -358,7 +384,12 @@ export class WAConnection extends EventEmitter {
|
|||||||
this.conn?.removeAllListeners ('open')
|
this.conn?.removeAllListeners ('open')
|
||||||
this.conn?.removeAllListeners ('message')
|
this.conn?.removeAllListeners ('message')
|
||||||
|
|
||||||
|
this.qrTimeout && clearTimeout (this.qrTimeout)
|
||||||
|
this.debounceTimeout && clearTimeout (this.debounceTimeout)
|
||||||
this.keepAliveReq && clearInterval(this.keepAliveReq)
|
this.keepAliveReq && clearInterval(this.keepAliveReq)
|
||||||
|
this.clearPhoneCheckInterval ()
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.conn?.close()
|
this.conn?.close()
|
||||||
this.conn?.terminate()
|
this.conn?.terminate()
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export class WAConnection extends Base {
|
|||||||
json: ['admin', 'init', this.version, this.browserDescription, this.authInfo?.clientID, true],
|
json: ['admin', 'init', this.version, this.browserDescription, this.authInfo?.clientID, true],
|
||||||
expect200: true,
|
expect200: true,
|
||||||
waitForOpen: false,
|
waitForOpen: false,
|
||||||
longTag: true
|
longTag: true,
|
||||||
|
requiresPhoneConnection: false
|
||||||
})
|
})
|
||||||
if (!canLogin) {
|
if (!canLogin) {
|
||||||
stopDebouncedTimeout () // stop the debounced timeout for QR gen
|
stopDebouncedTimeout () // stop the debounced timeout for QR gen
|
||||||
@@ -48,11 +49,11 @@ export class WAConnection extends Base {
|
|||||||
if (reconnect) json.push(...['reconnect', reconnect.replace('@s.whatsapp.net', '@c.us')])
|
if (reconnect) json.push(...['reconnect', reconnect.replace('@s.whatsapp.net', '@c.us')])
|
||||||
else json.push ('takeover')
|
else json.push ('takeover')
|
||||||
|
|
||||||
let response = await this.query({ json, tag: 's1', waitForOpen: false, expect200: true, longTag: true }) // wait for response with tag "s1"
|
let response = await this.query({ json, tag: 's1', waitForOpen: false, expect200: true, longTag: true, requiresPhoneConnection: false }) // wait for response with tag "s1"
|
||||||
// if its a challenge request (we get it when logging in)
|
// if its a challenge request (we get it when logging in)
|
||||||
if (response[1]?.challenge) {
|
if (response[1]?.challenge) {
|
||||||
await this.respondToChallenge(response[1].challenge)
|
await this.respondToChallenge(response[1].challenge)
|
||||||
response = await this.waitForMessage('s2', [])
|
response = await this.waitForMessage('s2', [], true)
|
||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
})()
|
})()
|
||||||
@@ -64,7 +65,7 @@ export class WAConnection extends Base {
|
|||||||
|
|
||||||
this.logger.info('validated connection successfully')
|
this.logger.info('validated connection successfully')
|
||||||
|
|
||||||
const response = await this.query({ json: ['query', 'ProfilePicThumb', this.user.jid], waitForOpen: false, expect200: false })
|
const response = await this.query({ json: ['query', 'ProfilePicThumb', this.user.jid], waitForOpen: false, expect200: false, requiresPhoneConnection: false })
|
||||||
this.user.imgUrl = response?.eurl || ''
|
this.user.imgUrl = response?.eurl || ''
|
||||||
|
|
||||||
this.sendPostConnectQueries ()
|
this.sendPostConnectQueries ()
|
||||||
@@ -93,7 +94,8 @@ export class WAConnection extends Base {
|
|||||||
expect200: true,
|
expect200: true,
|
||||||
waitForOpen: false,
|
waitForOpen: false,
|
||||||
longTag: true,
|
longTag: true,
|
||||||
timeoutMs: this.connectOptions.maxIdleTimeMs
|
timeoutMs: this.connectOptions.maxIdleTimeMs,
|
||||||
|
requiresPhoneConnection: false
|
||||||
})
|
})
|
||||||
return response.ref as string
|
return response.ref as string
|
||||||
}
|
}
|
||||||
@@ -212,7 +214,7 @@ export class WAConnection extends Base {
|
|||||||
emitQR ()
|
emitQR ()
|
||||||
if (this.connectOptions.regenerateQRIntervalMs) regenQR ()
|
if (this.connectOptions.regenerateQRIntervalMs) regenQR ()
|
||||||
|
|
||||||
const json = await this.waitForMessage('s1', [])
|
const json = await this.waitForMessage('s1', [], false)
|
||||||
this.qrTimeout && clearTimeout (this.qrTimeout)
|
this.qrTimeout && clearTimeout (this.qrTimeout)
|
||||||
this.qrTimeout = null
|
this.qrTimeout = null
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export class WAConnection extends Base {
|
|||||||
const willReconnect = !loggedOut && (tries <= (options?.maxRetries || 5)) && this.state === 'connecting'
|
const willReconnect = !loggedOut && (tries <= (options?.maxRetries || 5)) && this.state === 'connecting'
|
||||||
const reason = loggedOut ? DisconnectReason.invalidSession : error.message
|
const reason = loggedOut ? DisconnectReason.invalidSession : error.message
|
||||||
|
|
||||||
this.logger.warn (`connect attempt ${tries} failed${ willReconnect ? ', retrying...' : ''}`, error)
|
this.logger.warn ({ error }, `connect attempt ${tries} failed${ willReconnect ? ', retrying...' : ''}`)
|
||||||
|
|
||||||
if ((this.state as string) !== 'close' && !willReconnect) {
|
if ((this.state as string) !== 'close' && !willReconnect) {
|
||||||
this.closeInternal (reason)
|
this.closeInternal (reason)
|
||||||
@@ -317,10 +317,6 @@ export class WAConnection extends Base {
|
|||||||
if (this.logger.level === 'trace') {
|
if (this.logger.level === 'trace') {
|
||||||
this.logger.trace(messageTag + ', ' + JSON.stringify(json))
|
this.logger.trace(messageTag + ', ' + JSON.stringify(json))
|
||||||
}
|
}
|
||||||
if (!this.phoneConnected && this.state === 'open') {
|
|
||||||
this.phoneConnected = true
|
|
||||||
this.emit ('connection-phone-change', { connected: true })
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
Check if this is a response to a message we sent
|
Check if this is a response to a message we sent
|
||||||
*/
|
*/
|
||||||
@@ -365,11 +361,18 @@ export class WAConnection extends Base {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this.state === 'open' && json[0] === 'Pong') {
|
||||||
|
if (this.phoneConnected !== json[1]) {
|
||||||
|
this.phoneConnected = json[1]
|
||||||
|
this.emit ('connection-phone-change', { connected: this.phoneConnected })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
if (this.logger.level === 'debug') {
|
if (this.logger.level === 'debug') {
|
||||||
this.logger.debug({ unhandled: true }, messageTag + ', ' + JSON.stringify(json))
|
this.logger.debug({ unhandled: true }, messageTag + ',' + JSON.stringify(json))
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error (`encountered error in decrypting message, closing`, error)
|
this.logger.error ({ error }, `encountered error in decrypting message, closing`)
|
||||||
|
|
||||||
if (this.state === 'open') this.unexpectedDisconnect (DisconnectReason.badSession)
|
if (this.state === 'open') this.unexpectedDisconnect (DisconnectReason.badSession)
|
||||||
else this.endConnection ()
|
else this.endConnection ()
|
||||||
@@ -389,29 +392,6 @@ export class WAConnection extends Base {
|
|||||||
*/
|
*/
|
||||||
if (diff > KEEP_ALIVE_INTERVAL_MS+5000) this.unexpectedDisconnect (DisconnectReason.lost)
|
if (diff > KEEP_ALIVE_INTERVAL_MS+5000) this.unexpectedDisconnect (DisconnectReason.lost)
|
||||||
else if (this.conn) this.send ('?,,') // if its all good, send a keep alive request
|
else if (this.conn) this.send ('?,,') // if its all good, send a keep alive request
|
||||||
|
|
||||||
// poll phone connection as well,
|
|
||||||
// 5000 ms for timeout
|
|
||||||
this.checkPhoneConnection (this.connectOptions.phoneResponseTime || 7500)
|
|
||||||
.then (connected => {
|
|
||||||
this.phoneConnected !== connected && this.emit ('connection-phone-change', {connected})
|
|
||||||
this.phoneConnected = connected
|
|
||||||
})
|
|
||||||
|
|
||||||
}, KEEP_ALIVE_INTERVAL_MS)
|
}, KEEP_ALIVE_INTERVAL_MS)
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Check if your phone is connected
|
|
||||||
* @param timeoutMs max time for the phone to respond
|
|
||||||
*/
|
|
||||||
async checkPhoneConnection(timeoutMs = 5000) {
|
|
||||||
if (this.state !== 'open') return false
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await this.query({json: ['admin', 'test'], timeoutMs, waitForOpen: false})
|
|
||||||
return response[1] as boolean
|
|
||||||
} catch (error) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as QR from 'qrcode-terminal'
|
import * as QR from 'qrcode-terminal'
|
||||||
import { WAConnection as Base } from './3.Connect'
|
import { WAConnection as Base } from './3.Connect'
|
||||||
import { WAMessageStatusUpdate, WAMessage, WAContact, WAChat, WAMessageProto, WA_MESSAGE_STUB_TYPE, WA_MESSAGE_STATUS_TYPE, PresenceUpdate, BaileysEvent, DisconnectReason, WANode, WAOpenResult, Presence, AuthenticationCredentials } from './Constants'
|
import { WAMessageStatusUpdate, WAMessage, WAContact, WAChat, WAMessageProto, WA_MESSAGE_STUB_TYPE, WA_MESSAGE_STATUS_TYPE, PresenceUpdate, BaileysEvent, DisconnectReason, WANode, WAOpenResult, Presence, AuthenticationCredentials } from './Constants'
|
||||||
import { whatsappID, unixTimestampSeconds, isGroupID, toNumber, GET_MESSAGE_ID, WA_MESSAGE_ID, waMessageKey } from './Utils'
|
import { whatsappID, unixTimestampSeconds, isGroupID, GET_MESSAGE_ID, WA_MESSAGE_ID, waMessageKey } from './Utils'
|
||||||
import KeyedDB from '@adiwajshing/keyed-db'
|
import KeyedDB from '@adiwajshing/keyed-db'
|
||||||
import { Mutex } from './Mutex'
|
import { Mutex } from './Mutex'
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ export class WAConnection extends Base {
|
|||||||
/** Get the URL to download the profile picture of a person/group */
|
/** Get the URL to download the profile picture of a person/group */
|
||||||
@Mutex (jid => jid)
|
@Mutex (jid => jid)
|
||||||
async getProfilePicture(jid: string | null) {
|
async getProfilePicture(jid: string | null) {
|
||||||
const response = await this.query({ json: ['query', 'ProfilePicThumb', jid || this.user.jid], expect200: true })
|
const response = await this.query({ json: ['query', 'ProfilePicThumb', jid || this.user.jid], expect200: true, requiresPhoneConnection: false })
|
||||||
return response.eurl as string
|
return response.eurl as string
|
||||||
}
|
}
|
||||||
protected forwardStatusUpdate (update: WAMessageStatusUpdate) {
|
protected forwardStatusUpdate (update: WAMessageStatusUpdate) {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { Mutex } from './Mutex'
|
|||||||
|
|
||||||
export class WAConnection extends Base {
|
export class WAConnection extends Base {
|
||||||
/** Query whether a given number is registered on WhatsApp */
|
/** Query whether a given number is registered on WhatsApp */
|
||||||
isOnWhatsApp = (jid: string) => this.query({json: ['query', 'exist', jid]}).then((m) => m.status === 200)
|
isOnWhatsApp = (jid: string) => this.query({json: ['query', 'exist', jid], requiresPhoneConnection: false}).then((m) => m.status === 200)
|
||||||
/**
|
/**
|
||||||
* Tell someone about your presence -- online, typing, offline etc.
|
* Tell someone about your presence -- online, typing, offline etc.
|
||||||
* @param jid the ID of the person/group who you are updating
|
* @param jid the ID of the person/group who you are updating
|
||||||
@@ -35,7 +35,7 @@ export class WAConnection extends Base {
|
|||||||
requestPresenceUpdate = async (jid: string) => this.query({ json: ['action', 'presence', 'subscribe', jid] })
|
requestPresenceUpdate = async (jid: string) => this.query({ json: ['action', 'presence', 'subscribe', jid] })
|
||||||
/** Query the status of the person (see groupMetadata() for groups) */
|
/** Query the status of the person (see groupMetadata() for groups) */
|
||||||
async getStatus (jid?: string) {
|
async getStatus (jid?: string) {
|
||||||
const status: { status: string } = await this.query({ json: ['query', 'Status', jid || this.user.jid] })
|
const status: { status: string } = await this.query({ json: ['query', 'Status', jid || this.user.jid], requiresPhoneConnection: false })
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
async setStatus (status: string) {
|
async setStatus (status: string) {
|
||||||
@@ -60,7 +60,7 @@ export class WAConnection extends Base {
|
|||||||
/** Get the stories of your contacts */
|
/** Get the stories of your contacts */
|
||||||
async getStories() {
|
async getStories() {
|
||||||
const json = ['query', { epoch: this.msgCount.toString(), type: 'status' }, null]
|
const json = ['query', { epoch: this.msgCount.toString(), type: 'status' }, null]
|
||||||
const response = await this.query({json, binaryTags: [30, WAFlag.ignore], expect200: true}) as WANode
|
const response = await this.query({json, binaryTags: [30, WAFlag.ignore], expect200: true }) as WANode
|
||||||
if (Array.isArray(response[2])) {
|
if (Array.isArray(response[2])) {
|
||||||
return response[2].map (row => (
|
return response[2].map (row => (
|
||||||
{
|
{
|
||||||
@@ -78,7 +78,7 @@ export class WAConnection extends Base {
|
|||||||
return this.query({ json, binaryTags: [5, WAFlag.ignore], expect200: true }) // this has to be an encrypted query
|
return this.query({ json, binaryTags: [5, WAFlag.ignore], expect200: true }) // this has to be an encrypted query
|
||||||
}
|
}
|
||||||
/** Query broadcast list info */
|
/** Query broadcast list info */
|
||||||
async getBroadcastListInfo(jid: string) { return this.query({json: ['query', 'contact', jid], expect200: true}) as Promise<WABroadcastListInfo> }
|
async getBroadcastListInfo(jid: string) { return this.query({json: ['query', 'contact', jid], expect200: true }) as Promise<WABroadcastListInfo> }
|
||||||
/** Delete the chat of a given ID */
|
/** Delete the chat of a given ID */
|
||||||
async deleteChat (jid: string) {
|
async deleteChat (jid: string) {
|
||||||
const response = await this.setQuery ([ ['chat', {type: 'delete', jid: jid}, null] ], [12, WAFlag.ignore]) as {status: number}
|
const response = await this.setQuery ([ ['chat', {type: 'delete', jid: jid}, null] ], [12, WAFlag.ignore]) as {status: number}
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ export class WAConnection extends Base {
|
|||||||
/** Query a string to check if it has a url, if it does, return required extended text message */
|
/** Query a string to check if it has a url, if it does, return required extended text message */
|
||||||
async generateLinkPreview (text: string) {
|
async generateLinkPreview (text: string) {
|
||||||
const query = ['query', {type: 'url', url: text, epoch: this.msgCount.toString()}, null]
|
const query = ['query', {type: 'url', url: text, epoch: this.msgCount.toString()}, null]
|
||||||
const response = await this.query ({json: query, binaryTags: [26, WAFlag.ignore], expect200: true})
|
const response = await this.query ({json: query, binaryTags: [26, WAFlag.ignore], expect200: true, requiresPhoneConnection: false})
|
||||||
|
|
||||||
if (response[1]) response[1].jpegThumbnail = response[2]
|
if (response[1]) response[1].jpegThumbnail = response[2]
|
||||||
const data = response[1] as WAUrlInfo
|
const data = response[1] as WAUrlInfo
|
||||||
@@ -289,7 +289,7 @@ export class WAConnection extends Base {
|
|||||||
return this.mediaConn
|
return this.mediaConn
|
||||||
}
|
}
|
||||||
protected async getNewMediaConn () {
|
protected async getNewMediaConn () {
|
||||||
const {media_conn} = await this.query({json: ['query', 'mediaConn']})
|
const {media_conn} = await this.query({json: ['query', 'mediaConn'], requiresPhoneConnection: false})
|
||||||
return media_conn as MediaConnInfo
|
return media_conn as MediaConnInfo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ export class WAConnection extends Base {
|
|||||||
/** Get the invite link of the given group */
|
/** Get the invite link of the given group */
|
||||||
async groupInviteCode(jid: string) {
|
async groupInviteCode(jid: string) {
|
||||||
const json = ['query', 'inviteCode', jid]
|
const json = ['query', 'inviteCode', jid]
|
||||||
const response = await this.query({json, expect200: true})
|
const response = await this.query({json, expect200: true, requiresPhoneConnection: false})
|
||||||
return response.code as string
|
return response.code as string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,6 +56,7 @@ export interface WAQuery {
|
|||||||
expect200?: boolean
|
expect200?: boolean
|
||||||
waitForOpen?: boolean
|
waitForOpen?: boolean
|
||||||
longTag?: boolean
|
longTag?: boolean
|
||||||
|
requiresPhoneConnection?: boolean
|
||||||
}
|
}
|
||||||
export enum ReconnectMode {
|
export enum ReconnectMode {
|
||||||
/** does not reconnect */
|
/** does not reconnect */
|
||||||
|
|||||||
Reference in New Issue
Block a user