From 6bc6d7e706eb2a6a30e8f24a81e466f35a2c2c10 Mon Sep 17 00:00:00 2001 From: Edgard Date: Sun, 20 Jun 2021 21:43:46 -0300 Subject: [PATCH] =?UTF-8?q?fix:=20Corrigido=20e=20melhorado=20a=20fun?= =?UTF-8?q?=C3=A7=C3=A3o=20de=20onLiveLocation=20(fix=20#258)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/helpers/exposed.enum.ts | 1 + src/api/layers/listener.layer.ts | 76 ++++++++----- src/api/model/live-location.ts | 50 ++++++++- .../wapi/listeners/add-on-live-location.js | 101 +++++++++++++----- src/lib/wapi/wapi.js | 19 ++++ src/types/WAPI.d.ts | 2 +- 6 files changed, 194 insertions(+), 55 deletions(-) diff --git a/src/api/helpers/exposed.enum.ts b/src/api/helpers/exposed.enum.ts index 05a61d2a2..581a0914e 100644 --- a/src/api/helpers/exposed.enum.ts +++ b/src/api/helpers/exposed.enum.ts @@ -26,4 +26,5 @@ export enum ExposedFn { onIncomingCall = 'onIncomingCall', onInterfaceChange = 'onInterfaceChange', onPresenceChanged = 'onPresenceChanged', + onLiveLocation = 'onLiveLocation', } diff --git a/src/api/layers/listener.layer.ts b/src/api/layers/listener.layer.ts index 9aa574268..342ad3f04 100644 --- a/src/api/layers/listener.layer.ts +++ b/src/api/layers/listener.layer.ts @@ -125,6 +125,10 @@ export class ListenerLayer extends ProfileLayer { window.WAPI.onPresenceChanged(window['onPresenceChanged']); window['onPresenceChanged'].exposed = true; } + if (!window['onLiveLocation'].exposed) { + window.WAPI.onLiveLocation(window['onLiveLocation']); + window['onLiveLocation'].exposed = true; + } }) .catch(() => {}); } @@ -213,30 +217,49 @@ export class ListenerLayer extends ProfileLayer { } /** - * @event Listens to live locations from a chat that already has valid live locations - * @param chatId the chat from which you want to subscribes to live location updates - * @param fn callback that takes in a LiveLocation - * @returns boolean, if returns false then there were no valid live locations in the chat of chatId - * @emits LiveLocation + * Escuta os eventos de Localização em tempo real de todos os chats + * @event Eventos de Localização em tempo real + * @param callback Função para ser executada quando houver alterações + * @returns Objeto descartável para parar de ouvir + */ + public onLiveLocation(callback: (liveLocationEvent: LiveLocation) => void): { + dispose: () => void; + }; + /** + * Escuta os eventos de Localização em tempo real + * @event Eventos de Localização em tempo real + * @param id Único ID ou lista de IDs de contatos para acompanhar a localização + * @param callback Função para ser executada quando houver alterações + * @returns Objeto descartável para parar de ouvir */ - public async onLiveLocation( - chatId: string, - fn: (liveLocationChangedEvent: LiveLocation) => void + public onLiveLocation( + id: string | string[], + callback: (liveLocationEvent: LiveLocation) => void + ): { dispose: () => void }; + public onLiveLocation( + id: any, + callback?: (liveLocationEvent: LiveLocation) => void ) { - const method = 'onLiveLocation_' + chatId.replace('_', '').replace('_', ''); - return this.page - .exposeFunction(method, (liveLocationChangedEvent: LiveLocation) => - fn(liveLocationChangedEvent) - ) - .then((_) => - this.page.evaluate( - ({ chatId, method }) => { - //@ts-ignore - return WAPI.onLiveLocation(chatId, window[method]); - }, - { chatId, method } - ) - ); + const ids: string[] = []; + + if (typeof id === 'function') { + callback = id; + } else if (Array.isArray(id)) { + ids.push(...id); + } else { + ids.push(id); + } + + return this.registerEvent( + ExposedFn.onLiveLocation, + (event: LiveLocation) => { + // Only group events + if (ids.length && !ids.includes(event.id)) { + return; + } + callback(event); + } + ); } /** @@ -332,13 +355,14 @@ export class ListenerLayer extends ProfileLayer { id: any, callback?: (presenceChangedEvent: PresenceEvent) => void ): { dispose: () => void } { - let ids = []; + const ids = []; if (typeof id === 'function') { callback = id; - ids = []; - } else if (!Array.isArray(id)) { - ids = [id]; + } else if (Array.isArray(id)) { + ids.push(...id); + } else { + ids.push(id); } if (ids.length) { diff --git a/src/api/model/live-location.ts b/src/api/model/live-location.ts index 4697f7ef0..c9de3d766 100644 --- a/src/api/model/live-location.ts +++ b/src/api/model/live-location.ts @@ -15,12 +15,56 @@ * along with WPPConnect. If not, see . */ +/** + * Interface de dados para os eventos de Localização em tempo real + */ export interface LiveLocation { + /** + * Tipo de evento de Localização em tempo real + * * enable - Quando inicia o compartilhamento + * * update - Atualzação de localização + * * disable - Fim do compartilhamento + */ + type: 'enable' | 'update' | 'disable'; + + /** + * ID de contato que realizou o compartilhamento + */ id: string; + + /** + * Latitude em graus + */ lat: number; + + /** + * Longitude em graus + */ lng: number; + + /** + * Velocidade atual em milhar por hora (mp/h) + */ speed: number; - lastUpdated: number; - accuracy: number; - degrees: any; + + /** + * Precisão da localização em metros + */ + accuracy?: number; + + /** + * Tempo em segundos após o último compartilhamento + */ + elapsed?: number; + + /** + * Graus de direção + */ + degrees?: number; + + /** + * Tempo em segundos para o compartilhamento + * Somente no type:enable + */ + shareDuration?: number; } diff --git a/src/lib/wapi/listeners/add-on-live-location.js b/src/lib/wapi/listeners/add-on-live-location.js index c9700aeb7..4126c765c 100644 --- a/src/lib/wapi/listeners/add-on-live-location.js +++ b/src/lib/wapi/listeners/add-on-live-location.js @@ -16,32 +16,83 @@ */ export function addOnLiveLocation() { - window.WAPI.onLiveLocation = async function (chatId, callback) { - return await window.WAPI.waitForStore(['LiveLocation'], () => { - var lLChat = Store.LiveLocation.get(chatId); - if (lLChat) { - var validLocs = lLChat.participants.validLocations(); - validLocs.map((x) => - x.on('change:lastUpdated', (x, y, z) => { - console.log(x, y, z); - const { id, lat, lng, accuracy, degrees, speed, lastUpdated } = x; - const l = { - id: id.toString(), - lat, - lng, - accuracy, - degrees, - speed, - lastUpdated, - }; - // console.log('newloc',l) - callback(l); - }) - ); - return true; - } else { - return false; + const callbacks = []; + + /** + * Dispara o evento com dados formatados + */ + function fireCallback(data) { + const location = Object.assign({}, data); + if (location.jid) { + location.id = location.jid.toString(); + } + delete location.jid; + delete location.body; + delete location.isLive; + delete location.sequence; + + for (const callback of callbacks) { + try { + callback(location); + } catch (error) {} + } + } + + window.WAPI.waitForStore(['LiveLocation'], async () => { + /** + * Substitui o manipulador original para capturar todos eventos, + * pois o Store.LiveLocation só inicializa a partir de uma mensagem, + * caso a mensagem fique muito para atrás (após troca de 50 mensagens), + * ele não é inicializado até carregar a mensage. + */ + const originalHandle = Store.LiveLocation.handle; + Store.LiveLocation.handle = function (list) { + originalHandle.apply(this, arguments); + + for (const p of list) { + fireCallback(p); } + }; + + // Para cada novo LiveLocation inicializado, força a vizualização de mapa de todos + Store.LiveLocation.on('add', () => { + setTimeout(() => { + Store.LiveLocation.forEach((l) => { + l.startViewingMap(); + setTimeout(() => { + try { + l._startKeepAlive(); + } catch (error) {} + }, 1000); + }); + }, 100); }); + + // Força a inicialização de localização para todos chats ativos + Store.Chat.map((c) => Store.LiveLocation.find(c.id)); + }); + + // Caso receba nova mensagem de localização, inicializa o LiveLocation e dispara o primeiro evento + WAPI.waitNewMessages(false, (messages) => { + for (const message of messages) { + if (message.isLive) { + fireCallback({ + type: 'enable', + isLive: message.isLive, + id: message.sender.id, + lat: message.lat, + lng: message.lng, + accuracy: message.accuracy, + speed: message.speed, + degrees: message.degrees, + sequence: message.sequence, + shareDuration: message.shareDuration, + }); + } + } + }); + + window.WAPI.onLiveLocation = async function (callback) { + callbacks.push(callback); }; } diff --git a/src/lib/wapi/wapi.js b/src/lib/wapi/wapi.js index 5f58ef31a..1b73434ac 100644 --- a/src/lib/wapi/wapi.js +++ b/src/lib/wapi/wapi.js @@ -188,6 +188,25 @@ if (typeof window.Store === 'undefined') { }; } +// setTimeout(() => { +// window.WAPI.waitForStore(['LiveLocation'], async () => { +// console.log('handle'); +// // Store.LiveLocation.handle = (e) => console.log(e[0]); +// Store.LiveLocation.handle = (e) => +// console.log(e[0].jid.user, (e[0].speed * 3.6).toFixed(2) + ' km/h'); + +// const livePromises = Store.Chat.map((c) => Store.LiveLocation.find(c.id)); + +// await Promise.all(livePromises); +// console.log('find'); + +// setTimeout(() => { +// Store.LiveLocation.forEach((l) => l.startViewingMap()); +// console.log('start'); +// }, 1000); +// }); +// }, 100); + if (typeof window.WAPI === 'undefined') { window.WAPI = { lastRead: {}, diff --git a/src/types/WAPI.d.ts b/src/types/WAPI.d.ts index 6175bceec..59d9540f9 100644 --- a/src/types/WAPI.d.ts +++ b/src/types/WAPI.d.ts @@ -112,7 +112,7 @@ interface WAPI { onAddedToGroup: (callback: Function) => any; onIncomingCall: (callback: Function) => any; onInterfaceChange: (callback: Function) => void; - onLiveLocation: (chatId: string, callback: Function) => any; + onLiveLocation: (callback: Function) => any; onNotificationMessage: (callback: (message: Message) => void) => any; onParticipantsChanged: (groupId: string, callback: Function) => any; onStateChange: (callback: Function) => void;