From d04718e27a023b31fb2e5ad483755e71d865fd1b Mon Sep 17 00:00:00 2001 From: Adhiraj Singh Date: Tue, 26 Jul 2022 13:29:29 +0530 Subject: [PATCH] feat: add desktop + full history sync opts --- README.md | 57 ++++++++++++++++++-------------- src/Defaults/index.ts | 1 + src/Socket/socket.ts | 7 ++-- src/Types/index.ts | 2 ++ src/Utils/history.ts | 2 +- src/Utils/validate-connection.ts | 22 ++++++++---- 6 files changed, 58 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 02ee08d..d53e36d 100644 --- a/README.md +++ b/README.md @@ -103,35 +103,44 @@ The entire `SocketConfig` structure is mentioned here with default values: ``` ts type SocketConfig = { /** provide an auth state object to maintain the auth state */ - auth?: AuthenticationState - /** the WS url to connect to WA */ - waWebSocketUrl: string | URL - /** Fails the connection if the connection times out in this time interval or no data is received */ - connectTimeoutMs: number - /** Default timeout for queries, undefined for no timeout */ - defaultQueryTimeoutMs: number | undefined - /** ping-pong interval for WS connection */ - keepAliveIntervalMs: number - /** proxy agent */ - agent?: Agent - /** pino logger */ - logger: Logger - /** version to connect with */ - version: WAVersion - /** override browser config */ - browser: WABrowserDescription - /** agent used for fetch requests -- uploading/downloading media */ - fetchAgent?: Agent - /** should the QR be printed in the terminal */ - printQRInTerminal: boolean - /** - * fetch a message from your store - * implement this so that messages that failed to send (solves the "this message can take a while" issue) can be retried + auth: AuthenticationState + /** By default true, should history messages be downloaded and processed */ + downloadHistory: boolean + /** transaction capability options for SignalKeyStore */ + transactionOpts: TransactionCapabilityOptions + /** provide a cache to store a user's device list */ + userDevicesCache?: NodeCache + /** marks the client as online whenever the socket successfully connects */ + markOnlineOnConnect: boolean + /** + * map to store the retry counts for failed messages; + * used to determine whether to retry a message or not */ + msgRetryCounterMap?: MessageRetryMap + /** width for link preview images */ + linkPreviewImageThumbnailWidth: number + /** Should Baileys ask the phone for full history, will be received async */ + syncFullHistory: boolean + /** + * fetch a message from your store + * implement this so that messages failed to send (solves the "this message can take a while" issue) can be retried * */ getMessage: (key: proto.IMessageKey) => Promise } ``` +### Emulating the Desktop app instead of the web + +1. Baileys, by default, emulates a chrome web session +2. If you'd like to emulate a desktop connection (and receive more message history), add this to your Socket config: + ``` ts + const conn = makeWASocket({ + ...otherOpts, + // can use Windows, Ubuntu here too + browser: Browsers.macOS('Desktop'), + syncFullHistory: true + }) + ``` + ## Saving & Restoring Sessions You obviously don't want to keep scanning the QR code every time you want to connect. diff --git a/src/Defaults/index.ts b/src/Defaults/index.ts index 62c9647..b46a079 100644 --- a/src/Defaults/index.ts +++ b/src/Defaults/index.ts @@ -45,6 +45,7 @@ export const DEFAULT_CONNECTION_CONFIG: SocketConfig = { auth: undefined as any, downloadHistory: true, markOnlineOnConnect: true, + syncFullHistory: false, linkPreviewImageThumbnailWidth: 192, transactionOpts: { maxCommitRetries: 10, delayBetweenTriesMs: 3000 }, getMessage: async() => undefined diff --git a/src/Socket/socket.ts b/src/Socket/socket.ts index f7362a9..e65ad2d 100644 --- a/src/Socket/socket.ts +++ b/src/Socket/socket.ts @@ -25,6 +25,7 @@ export const makeSocket = ({ auth: authState, printQRInTerminal, defaultQueryTimeoutMs, + syncFullHistory, transactionOpts }: SocketConfig) => { const ws = new WebSocket(waWebSocketUrl, undefined, { @@ -178,12 +179,14 @@ export const makeSocket = ({ const keyEnc = noise.processHandshake(handshake, creds.noiseKey) + const config = { version, browser, syncFullHistory } + let node: proto.IClientPayload if(!creds.me) { - node = generateRegistrationNode(creds, { version, browser }) + node = generateRegistrationNode(creds, config) logger.info({ node }, 'not logged in, attempting registration...') } else { - node = generateLoginNode(creds.me!.id, { version, browser }) + node = generateLoginNode(creds.me!.id, config) logger.info({ node }, 'logging in...') } diff --git a/src/Types/index.ts b/src/Types/index.ts index 41503af..6660ec2 100644 --- a/src/Types/index.ts +++ b/src/Types/index.ts @@ -34,6 +34,8 @@ export type SocketConfig = CommonSocketConfig & { msgRetryCounterMap?: MessageRetryMap /** width for link preview images */ linkPreviewImageThumbnailWidth: number + /** Should Baileys ask the phone for full history, will be received async */ + syncFullHistory: boolean /** * fetch a message from your store * implement this so that messages failed to send (solves the "this message can take a while" issue) can be retried diff --git a/src/Utils/history.ts b/src/Utils/history.ts index c3249bc..3f4360a 100644 --- a/src/Utils/history.ts +++ b/src/Utils/history.ts @@ -52,7 +52,7 @@ export const processHistoryMessage = ( const curItem = recvChats[message.key.remoteJid!] const timestamp = toNumber(message.messageTimestamp) if(!message.key.fromMe && (!curItem || timestamp > curItem.lastMsgRecvTimestamp)) { - recvChats[message.key.remoteJid!] = { lastMsgRecvTimestamp: timestamp } + recvChats[chat.id] = { lastMsgRecvTimestamp: timestamp } // keep only the most recent message in the chat array chat.messages = [{ message }] } diff --git a/src/Utils/validate-connection.ts b/src/Utils/validate-connection.ts index af718d1..0ba3733 100644 --- a/src/Utils/validate-connection.ts +++ b/src/Utils/validate-connection.ts @@ -8,7 +8,7 @@ import { Curve, hmacSign } from './crypto' import { encodeBigEndian } from './generics' import { createSignalIdentity } from './signal' -type ClientPayloadConfig = Pick +type ClientPayloadConfig = Pick const getUserAgent = ({ version }: ClientPayloadConfig): proto.IUserAgent => { const osVersion = '0.1' @@ -31,16 +31,26 @@ const getUserAgent = ({ version }: ClientPayloadConfig): proto.IUserAgent => { } } -const getWebInfo = (): proto.IWebInfo => ({ - webSubPlatform: proto.WebInfo.WebInfoWebSubPlatform.WEB_BROWSER -}) +const PLATFORM_MAP = { + 'Mac OS': proto.WebInfo.WebInfoWebSubPlatform.DARWIN, + 'Windows': proto.WebInfo.WebInfoWebSubPlatform.WIN32 +} + +const getWebInfo = (config: ClientPayloadConfig): proto.IWebInfo => { + let webSubPlatform = proto.WebInfo.WebInfoWebSubPlatform.WEB_BROWSER + if(config.syncFullHistory && PLATFORM_MAP[config.browser[0]]) { + webSubPlatform = PLATFORM_MAP[config.browser[0]] + } + + return { webSubPlatform } +} const getClientPayload = (config: ClientPayloadConfig): proto.IClientPayload => { return { connectType: proto.ClientPayload.ClientPayloadConnectType.WIFI_UNKNOWN, connectReason: proto.ClientPayload.ClientPayloadConnectReason.USER_ACTIVATED, userAgent: getUserAgent(config), - webInfo: getWebInfo(), + webInfo: getWebInfo(config), } } @@ -75,7 +85,7 @@ export const generateRegistrationNode = ( }, platformType: proto.DeviceProps.DevicePropsPlatformType[config.browser[1].toUpperCase()] || proto.DeviceProps.DevicePropsPlatformType.UNKNOWN, - requireFullSync: false, + requireFullSync: config.syncFullHistory, } const companionProto = proto.DeviceProps.encode(companion).finish()