diff --git a/src/main.jsx b/src/main.jsx
index f457424..b644f78 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -27,6 +27,7 @@ import ChatAssign from '@/views/Conversations/ChatAssign'
import DingdingLogin from '@/views/dingding/Login'
import DingdingQRCode from '@/views/dingding/QRCode'
import DingdingAuthCode from '@/views/dingding/AuthCode'
+import LocalWhatsAppQRCode from '@/views/accounts/LocalWhatsAppQRCode'
import useAuthStore from '@/stores/AuthStore'
import '@/assets/index.css'
@@ -107,6 +108,7 @@ const router = createBrowserRouter([
{ path: 'dingding/callback', element: },
{ path: 'dingding/qr-code', element: },
{ path: 'dingding/auth-code', element: },
+ { path: 'whatsapp/qr-code', element: },
],
},
])
diff --git a/src/utils/request.js b/src/utils/request.js
index e13b98a..4d46a82 100644
--- a/src/utils/request.js
+++ b/src/utils/request.js
@@ -1,6 +1,8 @@
import { BUILD_VERSION } from '@/config'
+// Ref: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
+
const customHeaders = []
// 添加 HTTP Reuqest 自定义头部
diff --git a/src/views/accounts/LocalWhatsAppQRCode.jsx b/src/views/accounts/LocalWhatsAppQRCode.jsx
new file mode 100644
index 0000000..a5639ff
--- /dev/null
+++ b/src/views/accounts/LocalWhatsAppQRCode.jsx
@@ -0,0 +1,24 @@
+import { useEffect, useCallback, useState } from 'react'
+import { Typography, App, Flex, Input, QRCode } from 'antd'
+import { ReloadOutlined, CheckCircleFilled, ExclamationCircleFilled } from '@ant-design/icons'
+import useAuthStore from '@/stores/AuthStore'
+import { fetchQRCode } from '@/actions/WaiAction'
+import useConversationStore from '@/stores/ConversationStore'
+import { isEmpty } from '@/utils/commons'
+
+// 把 QR Code 转换成二维码,用来本地测试 WhatsApp Baileys 框架
+const LocalWhatsAppQRCode = () => {
+
+ const [qrCode, setQRCode] = useState('expired')
+
+ return (
+
+ WhatsApp Baileys
+
+ {
+ setQRCode(e.target.value)
+ }}/>
+
+ )
+}
+export default LocalWhatsAppQRCode
diff --git a/wai-server/core/baileys/index.js b/wai-server/core/baileys/index.js
index 3446512..8756aec 100644
--- a/wai-server/core/baileys/index.js
+++ b/wai-server/core/baileys/index.js
@@ -240,6 +240,35 @@ const createWhatsApp = async phone => {
}
}
+ const handleTemplateMessage = async msgObj => {
+ const text = msgObj.message.templateMessage?.hydratedTemplate?.hydratedContentText;
+
+ waEmitter.emit(emitEventName, {
+ id: msgObj.key.id,
+ externalId,
+ status: msgStatus,
+ direction: msgDirection,
+ from: msgFrom,
+ to: msgTo,
+ type: 'text',
+ text: {
+ body: text,
+ },
+ conversation: {
+ type: conversationType,
+ name: groupSubject,
+ },
+ customerProfile: {
+ id: decodeJid(msgObj.key.remoteJid),
+ name: msgObj.verifiedBizName || msgObj.pushName,
+ },
+ whatsAppNo,
+ fromMe: msgObj.key.fromMe,
+ eventSource: serverConfig.name + '.messages.upsert.notify',
+ updateTime: formatTimestamp(msgObj.messageTimestamp),
+ });
+ };
+
const handleMessagesUpdate = async messageUpdate => {
console.info('messages.update: ', JSON.stringify(messageUpdate, undefined, 2));
@@ -354,6 +383,7 @@ const createWhatsApp = async phone => {
// 第一次一分钟,后面是 20 秒更新一次
if (qrCode === null) {
qrCode = qr;
+ console.info('QR Code: ' + qrCode);
waEmitter.emit('creds:update', {
id: generateId(),
qr, whatsAppNo,
diff --git a/wai-server/core/baileys/local.js b/wai-server/core/baileys/local.js
deleted file mode 100644
index 9924ec1..0000000
--- a/wai-server/core/baileys/local.js
+++ /dev/null
@@ -1,164 +0,0 @@
-const {
- makeWASocket,
- Browsers,
- DisconnectReason,
- fetchLatestBaileysVersion,
- makeCacheableSignalKeyStore,
- makeInMemoryStore,
- useMultiFileAuthState,
- delay,
- downloadMediaMessage,
- isJidUser
-} = require('@whiskeysockets/baileys');
-
-const { formatPhoneNumber, parsePhoneNumber, formatStatus, formatTimestamp } = require('./helper');
-const NodeCache = require('node-cache');
-const P = require('pino');
-
-const logger = P({ timestamp: () => `,"time":"${new Date().toJSON()}"` }, P.destination('./wa-logs.txt'))
-logger.level = 'trace'
-
-// external map to store retry counts of messages when decryption/encryption fails
-// keep this out of the socket itself, so as to prevent a message decryption/encryption loop across socket restarts
-const msgRetryCounterCache = new NodeCache()
-
-// the store maintains the data of the WA connection in memory
-// can be written out to a file & read from it
-const store = makeInMemoryStore({ logger })
-store?.readFromFile('./baileys_store_multi.json')
-// save every 10s
-setInterval(() => {
- store?.writeToFile('./baileys_store_multi.json')
-}, 10_000)
-
-// start a connection
-const startSock = async() => {
- const { state, saveCreds } = await useMultiFileAuthState('baileys_auth_info')
- // fetch latest version of WA Web
- const { version, isLatest } = await fetchLatestBaileysVersion()
- console.log(`using WA v${version.join('.')}, isLatest: ${isLatest}`)
-
- const sock = makeWASocket({
- version,
- logger,
- auth: {
- creds: state.creds,
- /** caching makes the store faster to send/recv messages */
- keys: makeCacheableSignalKeyStore(state.keys, logger),
- },
- msgRetryCounterCache,
- generateHighQualityLinkPreview: true,
- })
-
- store?.bind(sock.ev)
-
-
- const sendMessageWTyping = async(msg, jid) => {
- await sock.presenceSubscribe(jid)
- await delay(500)
-
- await sock.sendPresenceUpdate('composing', jid)
- await delay(2000)
-
- await sock.sendPresenceUpdate('paused', jid)
-
- await sock.sendMessage(jid, msg)
- }
-
-
- return new Promise((resolve) => {
- // the process function lets you process all events that just occurred
- // efficiently in a batch
- sock.ev.process(
- // events is a map for event name => event data
- async(events) => {
- // something about the connection changed
- // maybe it closed, or we received all offline message or connection opened
- if(events['connection.update']) {
- const update = events['connection.update']
- const { connection, qr, lastDisconnect } = update
- if(connection === 'close') {
- // reconnect if not logged out
- if((lastDisconnect?.error)?.output?.statusCode !== DisconnectReason.loggedOut) {
- startSock()
- } else {
- console.log('Connection closed. You are logged out.')
- }
- }
- if (connection === 'open') {
- console.log('Connection open.')
-
- // setInterval(async() => {
-
- const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
- let result = '';
- const charactersLength = characters.length;
- for (let i = 0; i < 10; i++) {
- result += characters.charAt(Math.floor(Math.random() * charactersLength));
- }
- sendMessageWTyping({ text: result + "-local.Connection open 发送:" + new Date().toString() }, '8613317835586@s.whatsapp.net')
- // }, 1000*60*5)
-
-
-
- setInterval(async() => {
-
- const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
- let result = '';
- const charactersLength = characters.length;
- for (let i = 0; i < 10; i++) {
- result += characters.charAt(Math.floor(Math.random() * charactersLength));
- }
- sendMessageWTyping({ text: result + "-setInterval(5min) 发送:" + new Date().toString() }, '8613317835586@s.whatsapp.net')
- }, 1000*60*5)
- }
-
- if (qr !== undefined) {
- resolve(qr);
- }
-
- console.log('connection update', update)
- }
-
- if(events['creds.update']) {
- await saveCreds()
- }
-
- // received a new message
- if(events['messages.upsert']) {
- const upsert = events['messages.upsert']
- console.log('recv messages ', JSON.stringify(upsert, undefined, 2))
-
- if(upsert.type === 'notify') {
- for (const msg of upsert.messages) {
-
- if (msg.message?.conversation || msg.message?.extendedTextMessage?.text) {
- const text = msg.message?.conversation || msg.message?.extendedTextMessage?.text
- if (text == "requestPlaceholder" && !upsert.requestId) {
- const messageId = await sock.requestPlaceholderResend(msg.key)
- console.log('requested placeholder resync, id=', messageId)
- } else if (upsert.requestId) {
- console.log('Message received from phone, id=', upsert.requestId, msg)
- }
- }
- }
- }
- }
-
-
- }
- )
-
-
-
- })
-
- //return sock
-}
-
-async function go() {
-const qrCode = await startSock();
-console.info('qr code: ', qrCode);
-}
-
-go();
\ No newline at end of file
diff --git a/wai-server/core/baileys/test.js b/wai-server/core/baileys/test.js
deleted file mode 100644
index adb8e1f..0000000
--- a/wai-server/core/baileys/test.js
+++ /dev/null
@@ -1,100 +0,0 @@
-function generateRandomString(length) {
- const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
- let result = '';
- const charactersLength = characters.length;
- for (let i = 0; i < length; i++) {
- result += characters.charAt(Math.floor(Math.random() * charactersLength));
- }
- return result;
-}
-
-const start = () => {
-
- setInterval(() => {
-
- const randomString = generateRandomString(10);
- var myHeaders = new Headers();
- myHeaders.append("Content-Type", "application/json");
- myHeaders.append("Accept", "*/*");
- myHeaders.append("Host", "wai-server-01-qq4qmtq7wc9he4.chinahighlights.cn");
- myHeaders.append("Connection", "keep-alive");
-
- var raw = JSON.stringify({
- "from": "8618777396951",
- "to": "8613557032060",
- "content": randomString + "-setInterval(2min) 发送:" + new Date().toString()
- });
-
- var requestOptions = {
- method: 'POST',
- headers: myHeaders,
- body: raw,
- redirect: 'follow'
- };
-
- fetch("http://wai-server-01-qq4qmtq7wc9he4.chinahighlights.cn/api/v1/channels/send", requestOptions)
- .then(rsp => rsp.json())
- .then(json => console.info('8613557032060: ', json))
- .catch(ex => console.error(ex));
- }, 1000*60*2);
- //
-
- setInterval(() => {
-
- const randomString = generateRandomString(10);
- var myHeaders = new Headers();
- myHeaders.append("Content-Type", "application/json");
- myHeaders.append("Accept", "*/*");
- myHeaders.append("Host", "wai-server-01-qq4qmtq7wc9he4.chinahighlights.cn");
- myHeaders.append("Connection", "keep-alive");
-
- var raw = JSON.stringify({
- "from": "8618777396951",
- "to": "8613317835586",
- "content": randomString + "-setInterval(3min) 发送:" + new Date().toString()
- });
-
- var requestOptions = {
- method: 'POST',
- headers: myHeaders,
- body: raw,
- redirect: 'follow'
- };
-
- fetch("http://wai-server-01-qq4qmtq7wc9he4.chinahighlights.cn/api/v1/channels/send", requestOptions)
- .then(rsp => rsp.json())
- .then(json => console.info('8613317835586: ', json))
- .catch(ex => console.error(ex));
- }, 1000*60*3);
- //
-
- setInterval(() => {
-
- const randomString = generateRandomString(10);
- var myHeaders = new Headers();
- myHeaders.append("Content-Type", "application/json");
- myHeaders.append("Accept", "*/*");
- myHeaders.append("Host", "wai-server-01-qq4qmtq7wc9he4.chinahighlights.cn");
- myHeaders.append("Connection", "keep-alive");
-
- var raw = JSON.stringify({
- "from": "8618777396951",
- "to": "8617607735120",
- "content": randomString + "-setInterval(5min) 发送:" + new Date().toString()
- });
-
- var requestOptions = {
- method: 'POST',
- headers: myHeaders,
- body: raw,
- redirect: 'follow'
- };
-
- fetch("http://wai-server-01-qq4qmtq7wc9he4.chinahighlights.cn/api/v1/channels/send", requestOptions)
- .then(rsp => rsp.json())
- .then(json => console.info('8613317835586: ', json))
- .catch(ex => console.error(ex));
- }, 1000*60*5);
-}
-
-start();
\ No newline at end of file
diff --git a/wai-server/local.js b/wai-server/local.js
new file mode 100644
index 0000000..8e3fe22
--- /dev/null
+++ b/wai-server/local.js
@@ -0,0 +1,8 @@
+const { createWhatsApp } = require('./core/baileys');
+
+const go = async () => {
+ const whatsApp = await createWhatsApp('8618777396951');
+ whatsApp.start();
+}
+
+go();
\ No newline at end of file