refactor: replace axios with fetch API and update related types (#1666)
This commit is contained in:
committed by
GitHub
parent
cfe7a2b2b3
commit
fb12f6d9d3
@@ -1,5 +1,4 @@
|
||||
import { Boom } from '@hapi/boom'
|
||||
import type { AxiosRequestConfig } from 'axios'
|
||||
import { proto } from '../../WAProto/index.js'
|
||||
import type {
|
||||
BaileysEventEmitter,
|
||||
@@ -303,7 +302,7 @@ export const decodeSyncdPatch = async (
|
||||
return result
|
||||
}
|
||||
|
||||
export const extractSyncdPatches = async (result: BinaryNode, options: AxiosRequestConfig<{}>) => {
|
||||
export const extractSyncdPatches = async (result: BinaryNode, options: RequestInit) => {
|
||||
const syncNode = getBinaryNodeChild(result, 'sync')
|
||||
const collectionNodes = getBinaryNodeChildren(syncNode, 'collection')
|
||||
|
||||
@@ -355,7 +354,7 @@ export const extractSyncdPatches = async (result: BinaryNode, options: AxiosRequ
|
||||
return final
|
||||
}
|
||||
|
||||
export const downloadExternalBlob = async (blob: proto.IExternalBlobReference, options: AxiosRequestConfig<{}>) => {
|
||||
export const downloadExternalBlob = async (blob: proto.IExternalBlobReference, options: RequestInit) => {
|
||||
const stream = await downloadContentFromMessage(blob, 'md-app-state', { options })
|
||||
const bufferArray: Buffer[] = []
|
||||
for await (const chunk of stream) {
|
||||
@@ -365,7 +364,7 @@ export const downloadExternalBlob = async (blob: proto.IExternalBlobReference, o
|
||||
return Buffer.concat(bufferArray)
|
||||
}
|
||||
|
||||
export const downloadExternalPatch = async (blob: proto.IExternalBlobReference, options: AxiosRequestConfig<{}>) => {
|
||||
export const downloadExternalPatch = async (blob: proto.IExternalBlobReference, options: RequestInit) => {
|
||||
const buffer = await downloadExternalBlob(blob, options)
|
||||
const syncData = decodeAndHydrate(proto.SyncdMutations, buffer)
|
||||
return syncData
|
||||
@@ -424,7 +423,7 @@ export const decodePatches = async (
|
||||
syncds: proto.ISyncdPatch[],
|
||||
initial: LTHashState,
|
||||
getAppStateSyncKey: FetchAppStateSyncKey,
|
||||
options: AxiosRequestConfig<{}>,
|
||||
options: RequestInit,
|
||||
minimumVersionNumber?: number,
|
||||
logger?: ILogger,
|
||||
validateMacs = true
|
||||
|
||||
+20
-10
@@ -1,5 +1,4 @@
|
||||
import { Boom } from '@hapi/boom'
|
||||
import axios, { type AxiosRequestConfig } from 'axios'
|
||||
import { createHash, randomBytes } from 'crypto'
|
||||
import { proto } from '../../WAProto/index.js'
|
||||
const baileysVersion = [2, 3000, 1023223821]
|
||||
@@ -225,16 +224,21 @@ export const bindWaitForConnectionUpdate = (ev: BaileysEventEmitter) => bindWait
|
||||
* utility that fetches latest baileys version from the master branch.
|
||||
* Use to ensure your WA connection is always on the latest version
|
||||
*/
|
||||
export const fetchLatestBaileysVersion = async (options: AxiosRequestConfig<{}> = {}) => {
|
||||
export const fetchLatestBaileysVersion = async (options: RequestInit = {}) => {
|
||||
const URL = 'https://raw.githubusercontent.com/WhiskeySockets/Baileys/master/src/Defaults/index.ts'
|
||||
try {
|
||||
const result = await axios.get<string>(URL, {
|
||||
...options,
|
||||
responseType: 'text'
|
||||
const response = await fetch(URL, {
|
||||
dispatcher: options.dispatcher,
|
||||
method: 'GET',
|
||||
headers: options.headers
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Boom(`Failed to fetch latest Baileys version: ${response.statusText}`, { statusCode: response.status })
|
||||
}
|
||||
|
||||
const text = await response.text()
|
||||
// Extract version from line 7 (const version = [...])
|
||||
const lines = result.data.split('\n')
|
||||
const lines = text.split('\n')
|
||||
const versionLine = lines[6] // Line 7 (0-indexed)
|
||||
const versionMatch = versionLine!.match(/const version = \[(\d+),\s*(\d+),\s*(\d+)\]/)
|
||||
|
||||
@@ -261,12 +265,18 @@ export const fetchLatestBaileysVersion = async (options: AxiosRequestConfig<{}>
|
||||
* A utility that fetches the latest web version of whatsapp.
|
||||
* Use to ensure your WA connection is always on the latest version
|
||||
*/
|
||||
export const fetchLatestWaWebVersion = async (options: AxiosRequestConfig<{}>) => {
|
||||
export const fetchLatestWaWebVersion = async (options: RequestInit = {}) => {
|
||||
try {
|
||||
const { data } = await axios.get('https://web.whatsapp.com/sw.js', {
|
||||
...options,
|
||||
responseType: 'json'
|
||||
const response = await fetch('https://web.whatsapp.com/sw.js', {
|
||||
dispatcher: options.dispatcher,
|
||||
method: 'GET',
|
||||
headers: options.headers
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Boom(`Failed to fetch sw.js: ${response.statusText}`, { statusCode: response.status })
|
||||
}
|
||||
|
||||
const data = await response.text()
|
||||
|
||||
const regex = /\\?"client_revision\\?":\s*(\d+)/
|
||||
const match = data.match(regex)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { AxiosRequestConfig } from 'axios'
|
||||
import { promisify } from 'util'
|
||||
import { inflate } from 'zlib'
|
||||
import { proto } from '../../WAProto/index.js'
|
||||
@@ -11,7 +10,7 @@ import { decodeAndHydrate } from './proto-utils'
|
||||
|
||||
const inflatePromise = promisify(inflate)
|
||||
|
||||
export const downloadHistory = async (msg: proto.Message.IHistorySyncNotification, options: AxiosRequestConfig<{}>) => {
|
||||
export const downloadHistory = async (msg: proto.Message.IHistorySyncNotification, options: RequestInit) => {
|
||||
const stream = await downloadContentFromMessage(msg, 'md-msg-hist', { options })
|
||||
const bufferArray: Buffer[] = []
|
||||
for await (const chunk of stream) {
|
||||
@@ -96,7 +95,7 @@ export const processHistoryMessage = (item: proto.IHistorySync) => {
|
||||
|
||||
export const downloadAndProcessHistorySyncNotification = async (
|
||||
msg: proto.Message.IHistorySyncNotification,
|
||||
options: AxiosRequestConfig<{}>
|
||||
options: RequestInit
|
||||
) => {
|
||||
const historyMsg = await downloadHistory(msg, options)
|
||||
return processHistoryMessage(historyMsg)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { AxiosRequestConfig } from 'axios'
|
||||
import type { WAMediaUploadFunction, WAUrlInfo } from '../Types'
|
||||
import type { ILogger } from './logger'
|
||||
import { prepareWAMessageMedia } from './messages'
|
||||
@@ -19,7 +18,7 @@ export type URLGenerationOptions = {
|
||||
/** Timeout in ms */
|
||||
timeout: number
|
||||
proxyUrl?: string
|
||||
headers?: AxiosRequestConfig<{}>['headers']
|
||||
headers?: HeadersInit
|
||||
}
|
||||
uploadImage?: WAMediaUploadFunction
|
||||
logger?: ILogger
|
||||
@@ -70,7 +69,7 @@ export const getUrlInfo = async (
|
||||
return false
|
||||
}
|
||||
},
|
||||
headers: opts.fetchOpts as {}
|
||||
headers: opts.fetchOpts?.headers as {}
|
||||
})
|
||||
if (info && 'title' in info && info.title) {
|
||||
const [image] = info.images
|
||||
|
||||
+49
-28
@@ -1,5 +1,4 @@
|
||||
import { Boom } from '@hapi/boom'
|
||||
import axios, { type AxiosRequestConfig } from 'axios'
|
||||
import { exec } from 'child_process'
|
||||
import * as Crypto from 'crypto'
|
||||
import { once } from 'events'
|
||||
@@ -301,7 +300,7 @@ export const toBuffer = async (stream: Readable) => {
|
||||
return Buffer.concat(chunks)
|
||||
}
|
||||
|
||||
export const getStream = async (item: WAMediaUpload, opts?: AxiosRequestConfig) => {
|
||||
export const getStream = async (item: WAMediaUpload, opts?: RequestInit & { maxContentLength?: number }) => {
|
||||
if (Buffer.isBuffer(item)) {
|
||||
return { stream: toReadable(item), type: 'buffer' } as const
|
||||
}
|
||||
@@ -362,15 +361,24 @@ export async function generateThumbnail(
|
||||
}
|
||||
}
|
||||
|
||||
export const getHttpStream = async (url: string | URL, options: AxiosRequestConfig & { isStream?: true } = {}) => {
|
||||
const fetched = await axios.get(url.toString(), { ...options, responseType: 'stream' })
|
||||
return fetched.data as Readable
|
||||
export const getHttpStream = async (url: string | URL, options: RequestInit & { isStream?: true } = {}) => {
|
||||
const response = await fetch(url.toString(), {
|
||||
dispatcher: options.dispatcher,
|
||||
method: 'GET',
|
||||
headers: options.headers as HeadersInit
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Boom(`Failed to fetch stream from ${url}`, { statusCode: response.status, data: { url } })
|
||||
}
|
||||
|
||||
// @ts-ignore Node18+ Readable.fromWeb exists
|
||||
return Readable.fromWeb(response.body as any)
|
||||
}
|
||||
|
||||
type EncryptedStreamOptions = {
|
||||
saveOriginalFileIfRequired?: boolean
|
||||
logger?: ILogger
|
||||
opts?: AxiosRequestConfig
|
||||
opts?: RequestInit
|
||||
}
|
||||
|
||||
export const encryptedStream = async (
|
||||
@@ -412,7 +420,11 @@ export const encryptedStream = async (
|
||||
for await (const data of stream) {
|
||||
fileLength += data.length
|
||||
|
||||
if (type === 'remote' && opts?.maxContentLength && fileLength + data.length > opts.maxContentLength) {
|
||||
if (
|
||||
type === 'remote' &&
|
||||
(opts as any)?.maxContentLength &&
|
||||
fileLength + data.length > (opts as any).maxContentLength
|
||||
) {
|
||||
throw new Boom(`content length exceeded when encrypting "${type}"`, {
|
||||
data: { media, type }
|
||||
})
|
||||
@@ -486,7 +498,7 @@ const toSmallestChunkSize = (num: number) => {
|
||||
export type MediaDownloadOptions = {
|
||||
startByte?: number
|
||||
endByte?: number
|
||||
options?: AxiosRequestConfig<{}>
|
||||
options?: RequestInit
|
||||
}
|
||||
|
||||
export const getUrlFromDirectPath = (directPath: string) => `https://${DEF_HOST}${directPath}`
|
||||
@@ -532,8 +544,13 @@ export const downloadEncryptedContent = async (
|
||||
|
||||
const endChunk = endByte ? toSmallestChunkSize(endByte || 0) + AES_CHUNK_SIZE : undefined
|
||||
|
||||
const headers: AxiosRequestConfig['headers'] = {
|
||||
...(options?.headers || {}),
|
||||
const headersInit = options?.headers ? options.headers : undefined
|
||||
const headers: Record<string, string> = {
|
||||
...(headersInit
|
||||
? Array.isArray(headersInit)
|
||||
? Object.fromEntries(headersInit)
|
||||
: (headersInit as Record<string, string>)
|
||||
: {}),
|
||||
Origin: DEFAULT_ORIGIN
|
||||
}
|
||||
if (startChunk || endChunk) {
|
||||
@@ -546,9 +563,7 @@ export const downloadEncryptedContent = async (
|
||||
// download the message
|
||||
const fetched = await getHttpStream(downloadUrl, {
|
||||
...(options || {}),
|
||||
headers,
|
||||
maxBodyLength: Infinity,
|
||||
maxContentLength: Infinity
|
||||
headers
|
||||
})
|
||||
|
||||
let remainingBytes = Buffer.from([])
|
||||
@@ -645,21 +660,31 @@ export const getWAUploadToServer = (
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let result: any
|
||||
try {
|
||||
const body = await axios.post(url, createReadStream(filePath), {
|
||||
...options,
|
||||
maxRedirects: 0,
|
||||
const stream = createReadStream(filePath)
|
||||
const response = await fetch(url, {
|
||||
dispatcher: fetchAgent,
|
||||
method: 'POST',
|
||||
body: stream as any,
|
||||
headers: {
|
||||
...(options.headers || {}),
|
||||
...(() => {
|
||||
const hdrs = options?.headers
|
||||
if (!hdrs) return {}
|
||||
return Array.isArray(hdrs) ? Object.fromEntries(hdrs) : (hdrs as Record<string, string>)
|
||||
})(),
|
||||
'Content-Type': 'application/octet-stream',
|
||||
Origin: DEFAULT_ORIGIN
|
||||
},
|
||||
httpsAgent: fetchAgent,
|
||||
timeout: timeoutMs,
|
||||
responseType: 'json',
|
||||
maxBodyLength: Infinity,
|
||||
maxContentLength: Infinity
|
||||
// Note: custom agents/proxy require undici Agent; omitted here.
|
||||
signal: timeoutMs ? AbortSignal.timeout(timeoutMs) : undefined
|
||||
})
|
||||
result = body.data
|
||||
let parsed: any = undefined
|
||||
try {
|
||||
parsed = await response.json()
|
||||
} catch {
|
||||
parsed = undefined
|
||||
}
|
||||
|
||||
result = parsed
|
||||
|
||||
if (result?.url || result?.directPath) {
|
||||
urls = {
|
||||
@@ -675,13 +700,9 @@ export const getWAUploadToServer = (
|
||||
throw new Error(`upload failed, reason: ${JSON.stringify(result)}`)
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
result = error.response?.data
|
||||
}
|
||||
|
||||
const isLast = hostname === hosts[uploadInfo.hosts.length - 1]?.hostname
|
||||
logger.warn(
|
||||
{ trace: error.stack, uploadResult: result },
|
||||
{ trace: error?.stack, uploadResult: result },
|
||||
`Error in uploading to ${hostname} ${isLast ? '' : ', retrying...'}`
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Boom } from '@hapi/boom'
|
||||
import axios from 'axios'
|
||||
import { randomBytes } from 'crypto'
|
||||
import { promises as fs } from 'fs'
|
||||
import { type Transform } from 'stream'
|
||||
@@ -455,9 +454,10 @@ export const generateWAMessageContent = async (
|
||||
if (options.getProfilePicUrl) {
|
||||
const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid, 'preview')
|
||||
if (pfpUrl) {
|
||||
const resp = await axios.get(pfpUrl, { responseType: 'arraybuffer' })
|
||||
if (resp.status === 200) {
|
||||
m.groupInviteMessage.jpegThumbnail = resp.data
|
||||
const resp = await fetch(pfpUrl, { method: 'GET', dispatcher: options?.options?.dispatcher })
|
||||
if (resp.ok) {
|
||||
const buf = Buffer.from(await resp.arrayBuffer())
|
||||
m.groupInviteMessage.jpegThumbnail = buf
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -933,8 +933,8 @@ export const downloadMediaMessage = async <Type extends 'buffer' | 'stream'>(
|
||||
const result = await downloadMsg().catch(async error => {
|
||||
if (
|
||||
ctx &&
|
||||
axios.isAxiosError(error) && // check if the message requires a reupload
|
||||
REUPLOAD_REQUIRED_STATUS.includes(error.response?.status!)
|
||||
typeof error?.status === 'number' && // treat errors with status as HTTP failures requiring reupload
|
||||
REUPLOAD_REQUIRED_STATUS.includes(error.status as number)
|
||||
) {
|
||||
ctx.logger.info({ key: message.key }, 'sending reupload media request...')
|
||||
// request reupload
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { AxiosRequestConfig } from 'axios'
|
||||
import { proto } from '../../WAProto/index.js'
|
||||
import type {
|
||||
AuthenticationCreds,
|
||||
@@ -28,7 +27,7 @@ type ProcessMessageContext = {
|
||||
keyStore: SignalKeyStoreWithTransaction
|
||||
ev: BaileysEventEmitter
|
||||
logger?: ILogger
|
||||
options: AxiosRequestConfig<{}>
|
||||
options: RequestInit
|
||||
signalRepository: SignalRepositoryWithLIDStore
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user