Use idempotent exposeFunctionIfAbsent (no reinject flag) (#3233)
* Add exposeFunctionIfAbsent function * use exposeFunctionIfAbsent function instead of original exposeFunction * Remove "reinject" flag * exposeFunctionIfAbsent - onQRChangedEvent * exposeFunctionIfAbsent - onLogoutEvent
This commit is contained in:
parent
796a0a2367
commit
e470c82237
2 changed files with 235 additions and 227 deletions
|
|
@ -17,6 +17,7 @@ const ContactFactory = require('./factories/ContactFactory');
|
|||
const WebCacheFactory = require('./webCache/WebCacheFactory');
|
||||
const { ClientInfo, Message, MessageMedia, Contact, Location, Poll, PollVote, GroupNotification, Label, Call, Buttons, List, Reaction } = require('./structures');
|
||||
const NoAuth = require('./authStrategies/NoAuth');
|
||||
const {exposeFunctionIfAbsent} = require('./util/Puppeteer');
|
||||
|
||||
/**
|
||||
* Starting point for interacting with the WhatsApp Web API
|
||||
|
|
@ -90,9 +91,8 @@ class Client extends EventEmitter {
|
|||
/**
|
||||
* Injection logic
|
||||
* Private function
|
||||
* @property {boolean} reinject is this a reinject?
|
||||
*/
|
||||
async inject(reinject = false) {
|
||||
async inject() {
|
||||
await this.pupPage.waitForFunction('window.Debug?.VERSION != undefined', {timeout: this.options.authTimeoutMs});
|
||||
|
||||
const version = await this.getWWebVersion();
|
||||
|
|
@ -142,11 +142,7 @@ class Client extends EventEmitter {
|
|||
|
||||
// Register qr events
|
||||
let qrRetries = 0;
|
||||
const injected = await this.pupPage.evaluate(() => {
|
||||
return typeof window.onQRChangedEvent !== 'undefined';
|
||||
});
|
||||
if (!injected) {
|
||||
await this.pupPage.exposeFunction('onQRChangedEvent', async (qr) => {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onQRChangedEvent', async (qr) => {
|
||||
/**
|
||||
* Emitted when a QR code is received
|
||||
* @event Client#qr
|
||||
|
|
@ -161,7 +157,6 @@ class Client extends EventEmitter {
|
|||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
await this.pupPage.evaluate(async () => {
|
||||
|
|
@ -178,15 +173,14 @@ class Client extends EventEmitter {
|
|||
});
|
||||
}
|
||||
|
||||
if (!reinject) {
|
||||
await this.pupPage.exposeFunction('onAuthAppStateChangedEvent', async (state) => {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onAuthAppStateChangedEvent', async (state) => {
|
||||
if (state == 'UNPAIRED_IDLE') {
|
||||
// refresh qr code
|
||||
window.Store.Cmd.refreshQR();
|
||||
}
|
||||
});
|
||||
|
||||
await this.pupPage.exposeFunction('onAppStateHasSyncedEvent', async () => {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onAppStateHasSyncedEvent', async () => {
|
||||
const authEventPayload = await this.authStrategy.getAuthEventPayload();
|
||||
/**
|
||||
* Emitted when authentication is successful
|
||||
|
|
@ -231,8 +225,7 @@ class Client extends EventEmitter {
|
|||
//Load util functions (serializers, helper functions)
|
||||
await this.pupPage.evaluate(LoadUtils);
|
||||
|
||||
await this.attachEventListeners(reinject);
|
||||
reinject = true;
|
||||
await this.attachEventListeners();
|
||||
}
|
||||
/**
|
||||
* Emitted when the client has initialized and is ready to receive messages.
|
||||
|
|
@ -242,22 +235,16 @@ class Client extends EventEmitter {
|
|||
this.authStrategy.afterAuthReady();
|
||||
});
|
||||
let lastPercent = null;
|
||||
await this.pupPage.exposeFunction('onOfflineProgressUpdateEvent', async (percent) => {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onOfflineProgressUpdateEvent', async (percent) => {
|
||||
if (lastPercent !== percent) {
|
||||
lastPercent = percent;
|
||||
this.emit(Events.LOADING_SCREEN, percent, 'WhatsApp'); // Message is hardcoded as "WhatsApp" for now
|
||||
}
|
||||
});
|
||||
}
|
||||
const logoutCatchInjected = await this.pupPage.evaluate(() => {
|
||||
return typeof window.onLogoutEvent !== 'undefined';
|
||||
});
|
||||
if (!logoutCatchInjected) {
|
||||
await this.pupPage.exposeFunction('onLogoutEvent', async () => {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onLogoutEvent', async () => {
|
||||
this.lastLoggedOut = true;
|
||||
await this.pupPage.waitForNavigation({waitUntil: 'load', timeout: 5000}).catch((_) => _);
|
||||
});
|
||||
}
|
||||
await this.pupPage.evaluate(() => {
|
||||
window.AuthStore.AppState.on('change:state', (_AppState, state) => { window.onAuthAppStateChangedEvent(state); });
|
||||
window.AuthStore.AppState.on('change:hasSynced', () => { window.onAppStateHasSyncedEvent(); });
|
||||
|
|
@ -349,7 +336,7 @@ class Client extends EventEmitter {
|
|||
await this.authStrategy.afterBrowserInitialized();
|
||||
this.lastLoggedOut = false;
|
||||
}
|
||||
await this.inject(true);
|
||||
await this.inject();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -372,9 +359,8 @@ class Client extends EventEmitter {
|
|||
* Private function
|
||||
* @property {boolean} reinject is this a reinject?
|
||||
*/
|
||||
async attachEventListeners(reinject = false) {
|
||||
if (!reinject) {
|
||||
await this.pupPage.exposeFunction('onAddMessageEvent', msg => {
|
||||
async attachEventListeners() {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onAddMessageEvent', msg => {
|
||||
if (msg.type === 'gp2') {
|
||||
const notification = new GroupNotification(this, msg);
|
||||
if (['add', 'invite', 'linked_group_join'].includes(msg.subtype)) {
|
||||
|
|
@ -441,7 +427,7 @@ class Client extends EventEmitter {
|
|||
|
||||
let last_message;
|
||||
|
||||
await this.pupPage.exposeFunction('onChangeMessageTypeEvent', (msg) => {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onChangeMessageTypeEvent', (msg) => {
|
||||
|
||||
if (msg.type === 'revoked') {
|
||||
const message = new Message(this, msg);
|
||||
|
|
@ -462,7 +448,7 @@ class Client extends EventEmitter {
|
|||
|
||||
});
|
||||
|
||||
await this.pupPage.exposeFunction('onChangeMessageEvent', (msg) => {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onChangeMessageEvent', (msg) => {
|
||||
|
||||
if (msg.type !== 'revoked') {
|
||||
last_message = msg;
|
||||
|
|
@ -500,7 +486,7 @@ class Client extends EventEmitter {
|
|||
}
|
||||
});
|
||||
|
||||
await this.pupPage.exposeFunction('onRemoveMessageEvent', (msg) => {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onRemoveMessageEvent', (msg) => {
|
||||
|
||||
if (!msg.isNewMsg) return;
|
||||
|
||||
|
|
@ -515,7 +501,7 @@ class Client extends EventEmitter {
|
|||
|
||||
});
|
||||
|
||||
await this.pupPage.exposeFunction('onMessageAckEvent', (msg, ack) => {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onMessageAckEvent', (msg, ack) => {
|
||||
|
||||
const message = new Message(this, msg);
|
||||
|
||||
|
|
@ -529,7 +515,7 @@ class Client extends EventEmitter {
|
|||
|
||||
});
|
||||
|
||||
await this.pupPage.exposeFunction('onChatUnreadCountEvent', async (data) =>{
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onChatUnreadCountEvent', async (data) =>{
|
||||
const chat = await this.getChatById(data.id);
|
||||
|
||||
/**
|
||||
|
|
@ -538,7 +524,7 @@ class Client extends EventEmitter {
|
|||
this.emit(Events.UNREAD_COUNT, chat);
|
||||
});
|
||||
|
||||
await this.pupPage.exposeFunction('onMessageMediaUploadedEvent', (msg) => {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onMessageMediaUploadedEvent', (msg) => {
|
||||
|
||||
const message = new Message(this, msg);
|
||||
|
||||
|
|
@ -550,7 +536,7 @@ class Client extends EventEmitter {
|
|||
this.emit(Events.MEDIA_UPLOADED, message);
|
||||
});
|
||||
|
||||
await this.pupPage.exposeFunction('onAppStateChangedEvent', async (state) => {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onAppStateChangedEvent', async (state) => {
|
||||
/**
|
||||
* Emitted when the connection state changes
|
||||
* @event Client#change_state
|
||||
|
|
@ -582,7 +568,7 @@ class Client extends EventEmitter {
|
|||
}
|
||||
});
|
||||
|
||||
await this.pupPage.exposeFunction('onBatteryStateChangedEvent', (state) => {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onBatteryStateChangedEvent', (state) => {
|
||||
const { battery, plugged } = state;
|
||||
|
||||
if (battery === undefined) return;
|
||||
|
|
@ -598,7 +584,7 @@ class Client extends EventEmitter {
|
|||
this.emit(Events.BATTERY_CHANGED, { battery, plugged });
|
||||
});
|
||||
|
||||
await this.pupPage.exposeFunction('onIncomingCall', (call) => {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onIncomingCall', (call) => {
|
||||
/**
|
||||
* Emitted when a call is received
|
||||
* @event Client#incoming_call
|
||||
|
|
@ -616,7 +602,7 @@ class Client extends EventEmitter {
|
|||
this.emit(Events.INCOMING_CALL, cll);
|
||||
});
|
||||
|
||||
await this.pupPage.exposeFunction('onReaction', (reactions) => {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onReaction', (reactions) => {
|
||||
for (const reaction of reactions) {
|
||||
/**
|
||||
* Emitted when a reaction is sent, received, updated or removed
|
||||
|
|
@ -637,7 +623,7 @@ class Client extends EventEmitter {
|
|||
}
|
||||
});
|
||||
|
||||
await this.pupPage.exposeFunction('onRemoveChatEvent', async (chat) => {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onRemoveChatEvent', async (chat) => {
|
||||
const _chat = await this.getChatById(chat.id);
|
||||
|
||||
/**
|
||||
|
|
@ -648,7 +634,7 @@ class Client extends EventEmitter {
|
|||
this.emit(Events.CHAT_REMOVED, _chat);
|
||||
});
|
||||
|
||||
await this.pupPage.exposeFunction('onArchiveChatEvent', async (chat, currState, prevState) => {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onArchiveChatEvent', async (chat, currState, prevState) => {
|
||||
const _chat = await this.getChatById(chat.id);
|
||||
|
||||
/**
|
||||
|
|
@ -661,7 +647,7 @@ class Client extends EventEmitter {
|
|||
this.emit(Events.CHAT_ARCHIVED, _chat, currState, prevState);
|
||||
});
|
||||
|
||||
await this.pupPage.exposeFunction('onEditMessageEvent', (msg, newBody, prevBody) => {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onEditMessageEvent', (msg, newBody, prevBody) => {
|
||||
|
||||
if(msg.type === 'revoked'){
|
||||
return;
|
||||
|
|
@ -676,7 +662,7 @@ class Client extends EventEmitter {
|
|||
this.emit(Events.MESSAGE_EDIT, new Message(this, msg), newBody, prevBody);
|
||||
});
|
||||
|
||||
await this.pupPage.exposeFunction('onAddMessageCiphertextEvent', msg => {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onAddMessageCiphertextEvent', msg => {
|
||||
|
||||
/**
|
||||
* Emitted when messages are edited
|
||||
|
|
@ -686,7 +672,7 @@ class Client extends EventEmitter {
|
|||
this.emit(Events.MESSAGE_CIPHERTEXT, new Message(this, msg));
|
||||
});
|
||||
|
||||
await this.pupPage.exposeFunction('onPollVoteEvent', (vote) => {
|
||||
await exposeFunctionIfAbsent(this.pupPage, 'onPollVoteEvent', (vote) => {
|
||||
const _vote = new PollVote(this, vote);
|
||||
/**
|
||||
* Emitted when some poll option is selected or deselected,
|
||||
|
|
@ -695,7 +681,6 @@ class Client extends EventEmitter {
|
|||
*/
|
||||
this.emit(Events.VOTE_UPDATE, _vote);
|
||||
});
|
||||
}
|
||||
|
||||
await this.pupPage.evaluate(() => {
|
||||
window.Store.Msg.on('change', (msg) => { window.onChangeMessageEvent(window.WWebJS.getMessageModel(msg)); });
|
||||
|
|
|
|||
23
src/util/Puppeteer.js
Normal file
23
src/util/Puppeteer.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Expose a function to the page if it does not exist
|
||||
*
|
||||
* NOTE:
|
||||
* Rewrite it to 'upsertFunction' after updating Puppeteer to 20.6 or higher
|
||||
* using page.removeExposedFunction
|
||||
* https://pptr.dev/api/puppeteer.page.removeExposedFunction
|
||||
*
|
||||
* @param {import(puppeteer).Page} page
|
||||
* @param {string} name
|
||||
* @param {Function} fn
|
||||
*/
|
||||
async function exposeFunctionIfAbsent(page, name, fn) {
|
||||
const exist = await page.evaluate((name) => {
|
||||
return !!window[name];
|
||||
}, name);
|
||||
if (exist) {
|
||||
return;
|
||||
}
|
||||
await page.exposeFunction(name, fn);
|
||||
}
|
||||
|
||||
module.exports = {exposeFunctionIfAbsent};
|
||||
Loading…
Reference in a new issue