Skip to content

Commit deca77f

Browse files
committed
limit connect to 3 for 5 minutes, prevent looping restart and full storage off qrcode message
1 parent c8973af commit deca77f

File tree

10 files changed

+87
-13
lines changed

10 files changed

+87
-13
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,8 @@ WHATSAPP_VERSION=Version of whatsapp, default to local Baileys version.
367367
CONSUMER_TIMEOUT_MS=miliseconds in timeout for consume job, default is 30000
368368
DEFAULT_LOCALE=locale for notifications status, now possibile is en, pt_BR and pt, default is en
369369
ONLY_HELLO_TEMPLATE=true sets hello template as the only default template, default false.
370+
MAX_CONNECT_RETRY=3 max try connect
371+
MAX_CONNECT_TIME_MS=300000 interval of max connect, 5 minutes
370372
```
371373

372374
Bucket env to config assets media compatible with S3, this config can't save in redis:

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "unoapi-cloud",
3-
"version": "1.26.7",
3+
"version": "1.27.0",
44
"description": "Unoapi Cloud",
55
"exports": "./dist/index.js",
66
"types": "./dist/index.d.ts",

src/controllers/session_controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ export class SessionController {
118118
const store = await config.getStore(phone, config)
119119
const { sessionStore } = store
120120

121-
const generateQrcode = (await sessionStore.isStatusIsDisconnect(phone)) || (await sessionStore.isStatusOffline(phone))
121+
const generateQrcode = (await sessionStore.isStatusDisconnect(phone)) || (await sessionStore.isStatusOffline(phone))
122122
const html = generateQrcode ? await qrcode(phone, this.getConfig, this.onNewLogin, this.socket) : await configuration(phone, this.getConfig)
123123
return res.send(html)
124124
}

src/defaults.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ export const UNOAPI_DELAY_AFTER_FIRST_MESSAGE_MS = parseInt(process.env.UNOAPI_D
7878
export const UNOAPI_DELAY_AFTER_FIRST_MESSAGE_WEBHOOK_MS = parseInt(process.env.UNOAPI_DELAY_AFTER_FIRST_MESSAGE_WEBHOOK_MS || '0')
7979
export const UNOAPI_BULK_BATCH = parseInt(process.env.UNOAPI_BULK_BATCH || '5')
8080
export const UNOAPI_BULK_DELAY = parseInt(process.env.UNOAPI_BULK_DELAY || '60')
81+
export const MAX_CONNECT_RETRY = parseInt(process.env.MAX_CONNECT_RETRY || '3')
82+
export const MAX_CONNECT_TIME_MS = parseInt(process.env.MAX_CONNECT_TIME || '600000')
8183
export const UNOAPI_BULK_MESSAGE_DELAY = parseInt(process.env.UNOAPI_BULK_DELAY || '12')
8284
export const PORT: number = parseInt(process.env.PORT || '9876')
8385
export const BASE_URL = process.env.BASE_URL || `http://localhost:${PORT}`

src/services/auto_connect.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const autoConnect = async (
1616
onNewLogin: OnNewLogin,
1717
) => {
1818
try {
19-
await sessionStore.syncConnecting()
19+
await sessionStore.syncConnections()
2020
const phones = await sessionStore.getPhones()
2121
logger.info(`${phones.length} phones to verify if is auto connect`)
2222
for (let i = 0, j = phones.length; i < j; i++) {

src/services/client_baileys.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ export class ClientBaileys implements Client {
566566
}
567567

568568
async getMessageMetadata<T>(message: T) {
569-
if (!this.store || !(await this.store.sessionStore.isStatusOnline(this.phone))) {
569+
if (!this.store || !await this.store.sessionStore.isStatusOnline(this.phone)) {
570570
return message
571571
}
572572
const key = message && message['key']

src/services/redis.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ const authKey = (phone: string) => {
135135
return `${BASE_KEY}auth:${phone}`
136136
}
137137

138+
const connectCountKey = (phone: string, ordinal: number | string) => {
139+
return `${BASE_KEY}connect-count:${phone}:${ordinal}`
140+
}
141+
138142
export const sessionStatusKey = (phone: string) => {
139143
return `${BASE_KEY}status:${phone}`
140144
}
@@ -383,6 +387,18 @@ export const getMessage = async <T>(phone: string, jid: string, id: string): Pro
383387
}
384388
}
385389

390+
export const getConnectCount = async(phone: string) => {
391+
const keyPattern = connectCountKey(phone, '*')
392+
const keys = await redisKeys(keyPattern)
393+
return keys.length || 0
394+
}
395+
396+
export const setConnectCount = async (phone: string, ttl: number) => {
397+
const last = await getConnectCount(phone)
398+
const key = connectCountKey(phone, last + 1)
399+
await redisSetAndExpire(key, 1, ttl)
400+
}
401+
386402
// eslint-disable-next-line @typescript-eslint/no-explicit-any
387403
export const setMessage = async (phone: string, jid: string, id: string, value: any) => {
388404
const key = messageKey(phone, jid, id)

src/services/session_store.ts

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import { MAX_CONNECT_RETRY } from '../defaults'
12
import logger from './logger'
23

3-
export type sessionStatus = 'offline' | 'online' | 'disconnected' | 'connecting'
4+
export type sessionStatus = 'offline' | 'online' | 'disconnected' | 'connecting' | 'blocked'
45

56
const statuses: Map<string, string> = new Map<string, string>()
7+
const retries: Map<string, number> = new Map<string, number>()
68

79

810
export abstract class SessionStore {
@@ -29,9 +31,38 @@ export abstract class SessionStore {
2931
return await this.getStatus(phone) == 'offline'
3032
}
3133

32-
async isStatusIsDisconnect(phone: string) {
34+
async isStatusDisconnect(phone: string) {
3335
return await this.getStatus(phone) == 'disconnected'
3436
}
3537

36-
async syncConnecting() {}
38+
async isStatusBlocked(phone: string) {
39+
return await this.getStatus(phone) == 'blocked'
40+
}
41+
42+
async getConnectCount(phone: string) {
43+
return retries.get(phone) || 0
44+
}
45+
46+
async incrementConnectCountAndVerify(phone: string) {
47+
const count = retries.get(phone) || 0
48+
retries.set(phone, count + 1)
49+
if (retries.get(phone)! >= MAX_CONNECT_RETRY) {
50+
this.setStatus(phone, 'blocked')
51+
return true
52+
}
53+
}
54+
55+
async isStatusBlockedAndVerify(phone: string) {
56+
if (await this.isStatusBlocked(phone)) {
57+
if (await this.getConnectCount(phone) < MAX_CONNECT_RETRY) {
58+
await this.setStatus(phone, 'offline')
59+
return false
60+
}
61+
logger.warn('Blocked %s', phone)
62+
return true
63+
}
64+
return this.incrementConnectCountAndVerify(phone)
65+
}
66+
67+
async syncConnections() {}
3768
}

src/services/session_store_redis.ts

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { SessionStore, sessionStatus } from './session_store'
2-
import { configKey, redisKeys, getSessionStatus, setSessionStatus, sessionStatusKey, redisGet, getConfig } from './redis'
2+
import { configKey, redisKeys, getSessionStatus, setSessionStatus, sessionStatusKey, redisGet, getConfig, getConnectCount, setConnectCount } from './redis'
33
import logger from './logger'
4+
import { MAX_CONNECT_RETRY } from '../defaults'
45

56
const toReplaceConfig = configKey('')
67
const toReplaceStatus = sessionStatusKey('')
@@ -26,18 +27,36 @@ export class SessionStoreRedis extends SessionStore {
2627
return setSessionStatus(phone, status)
2728
}
2829

29-
async syncConnecting() {
30-
logger.info(`Syncing lost connections...`)
30+
async getConnectCount(phone: string) {
31+
return getConnectCount(phone)
32+
}
33+
34+
async incrementConnectCountAndVerify(phone: string) {
35+
const count = await this.getConnectCount(phone)
36+
await setConnectCount(phone, count + 1)
37+
38+
if (await this.getConnectCount(phone) >= MAX_CONNECT_RETRY) {
39+
this.setStatus(phone, 'blocked')
40+
return true
41+
}
42+
}
43+
44+
async syncConnections() {
45+
logger.info(`Syncing lost and blocked connections...`)
3146
try {
3247
const pattern = sessionStatusKey('*')
3348
const keys = await redisKeys(pattern)
3449
for (let i = 0; i < keys.length; i++) {
3550
const key = keys[i];
3651
const phone = key.replace(toReplaceStatus, '')
37-
if ((await redisGet(key)) == 'connecting' || !getConfig(phone) ) {
52+
if (await redisGet(key) == 'connecting' || !await getConfig(phone) ) {
3853
logger.info(`Sync ${phone} lost connecting!`)
3954
await this.setStatus(phone, 'disconnected')
4055
}
56+
if (await redisGet(key) == 'blocked' && await this.getConnectCount(phone) < MAX_CONNECT_RETRY) {
57+
logger.info(`Sync ${phone} blocked!`)
58+
await this.setStatus(phone, 'offline')
59+
}
4160
}
4261
} catch (error) {
4362
logger.error(error, 'Error on sync lost connecting')

src/services/socket.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ export const connect = async ({
227227
sock = undefined
228228
return
229229
}
230-
if (await sessionStore.isStatusIsDisconnect(phone)) {
230+
if (await sessionStore.isStatusDisconnect(phone)) {
231231
logger.warn('Already Disconnected %s', phone)
232232
sock = undefined
233233
return
@@ -365,7 +365,7 @@ export const connect = async ({
365365
if (await sessionStore.isStatusConnecting(phone)) {
366366
await verifyConnectingTimeout()
367367
throw new SendError(5, t('connecting_session'))
368-
} else if (await sessionStore.isStatusIsDisconnect(phone) || !sock) {
368+
} else if (await sessionStore.isStatusDisconnect(phone) || !sock) {
369369
throw new SendError(3, t('disconnected_session'))
370370
} else if (await sessionStore.isStatusOffline(phone)) {
371371
throw new SendError(12, t('offline_session'))
@@ -444,6 +444,10 @@ export const connect = async ({
444444
logger.warn('Already Connected %s', phone)
445445
return
446446
}
447+
if (await sessionStore.isStatusBlockedAndVerify(phone)) {
448+
logger.warn('Blocked %s', phone)
449+
return
450+
}
447451
logger.debug('Connecting %s', phone)
448452

449453
const browser: WABrowserDescription = config.ignoreHistoryMessages ? DEFAULT_BROWSER as WABrowserDescription : Browsers.windows('Desktop')

0 commit comments

Comments
 (0)