Skip to content

Commit

Permalink
Update Lib Baileys Version 4
Browse files Browse the repository at this point in the history
  • Loading branch information
saifulcoder committed Mar 1, 2022
1 parent a4a5934 commit 8858ac5
Show file tree
Hide file tree
Showing 23 changed files with 902 additions and 16,505 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,9 @@ Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
package-lock.json
/.idea
/.vscode
/backend/node_modules
/backend2
/.history
10 changes: 5 additions & 5 deletions app/Http/Controllers/AdminDeviceController.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,22 +77,22 @@ public function Scan($name)
$find = Http::get(env('URL_WA_SERVER').'/session/find/'.$name);
$cek = json_decode($find->getBody());
// dd($cek)
if($cek->success == true){
if($cek->message == "Session found."){
$image = asset('image/connect.gif');
DB::table('device')->where('name', $name)->update(['status' => 'connected','updated_at' => now()]);

}
else{
DB::table('device')->where('name', $name)->update(['status' => 'disconnected','updated_at' => now()]);
$response = Http::post(env('URL_WA_SERVER').'/session/add', ['id' => $name,]);
$response = Http::post(env('URL_WA_SERVER').'/session/add', ['id' => $name, 'isLegacy' => 'true']);
$res = json_decode($response->getBody());
$image = $res->data->qr;
}

$data = [];
$data['page_title'] = 'Scan Device';
$data['result'] = $image;
$data['script_js'] = 'setTimeout(function(){window.location.reload(1);}, 10000);';
$data['script_js'] = 'setTimeout(function(){window.location.reload(1);}, 20000);';

//Please use view method instead view method from laravel
return $this->view('device.scan',$data);
Expand All @@ -107,10 +107,10 @@ public function hook_query_index(&$query) {
$find = Http::get(env('URL_WA_SERVER').'/session/find/'.$cek->name);
$getres = json_decode($find->getBody());
// dd($getres->success);
if($getres->success == true){
if($getres->message == "Session found."){
$status= "connected";
}
else if($getres->success == false)
else if($getres->message == "Session not found.")
{
$status= "disconnected";
}
Expand Down
3 changes: 2 additions & 1 deletion backend/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"no-unused-expressions": ["error", { "allowTernary": true }],
"curly": "error",
"new-cap": "off",
"no-return-assign": "off"
"no-return-assign": "off",
"no-await-in-loop": "off"
},
"plugins": ["prettier"]
}
1 change: 0 additions & 1 deletion backend/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
node_modules/
package-lock.json
2 changes: 2 additions & 0 deletions backend/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
package.json
package-lock.json
2 changes: 2 additions & 0 deletions backend/.prettierrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"printWidth": 120,
"tabWidth": 4,
"useTabs": false,
"endOfLine": "lf",
"semi": false,
"singleQuote": true
}
37 changes: 31 additions & 6 deletions backend/README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,57 @@
# Baileys API

An implementation of [@adiwajshing/Baileys](https://github.com/adiwajshing/Baileys) as a simple RESTful API service with multiple device support.
An implementation of [@adiwajshing/Baileys](https://github.com/adiwajshing/Baileys) as a simple RESTful API service with multiple device support. This project implements both **Legacy** (Normal WhatsApp Web) and **Beta Multi-Device** client so that you can choose and use one of them easily.

## Installation

1. Download or clone this repo.
2. Enter to the project directory.
3. Execute `npm i` to install the dependencies.

## `.env` Configurations

```env
# Listening Host
HOST=127.0.0.1
# Listening Port
PORT=8000
# Maximum Reconnect Attempts
MAX_RETRIES=5
# Reconnect Interval (in Milliseconds)
RECONNECT_INTERVAL=5000
```

## Usage

1. You can start the app by executing `npm run start` or `node .`.
2. Now the endpoint should be available according to your environment variable settings. Default is at `http://localhost:8000`.
2. Now the endpoint should be available according to your environment variable configurations. Default is at `http://localhost:8000`.

## API Docs

The API documentation is available online at [here](https://documenter.getpostman.com/view/18988925/UVRHiNne). You can also import the **Postman Collection File** `(postman_collection.json)` into your Postman App alternatively.
The API documentation is available online [here](https://documenter.getpostman.com/view/18988925/UVeNni36). You can also import the **Postman Collection File** `(postman_collection.json)` into your Postman App alternatively.

The server will respond in JSON format:
The server will respond in following JSON format:

```javascript
{
success: true|false, // bool
message: "", // string
data: {} // object
data: {}|[] // object or array of object
}
```

## Known Issue
- Logging out from your phone manually when the session is still active **will kill the entire app** after a few minutes. As for now you should only destroy a session by using the **delete session endpoint** to avoid this issue. This issue only occurs for **Beta Multi-Device** users.

## Notes
- The app only provide a very simple validation, you may want to implement your own.
- There's no authentication, you may want to implement your own.
- The **Beta Multi-Device** client use provided baileys's `makeInMemoryStore` method which will store your data in memory and a json file, you may want to use a better data management.
- **There's no reading message occured before sending message**. The reading message only occurs when the client received message from someone, it will read them immediately. You should always read messages before starting the app and start sending messages to avoid abnormal detection.

## Notice

This project is intended for learning purpose only, don't use this for spam or any activities that is prohibited by **WhatsApp**.
This project is intended for learning purpose only, don't use it for spamming or any activities that's prohibited by **WhatsApp**.
8 changes: 6 additions & 2 deletions backend/app.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import 'dotenv/config'
import express from 'express'
import nodeCleanup from 'node-cleanup'
import routes from './routes.js'
import { init } from './whatsapp.js'
import { init, cleanup } from './whatsapp.js'

const app = express()
const host = process.env.HOST ?? '127.0.0.1'
const port = process.env.PORT ?? 8000
const port = parseInt(process.env.PORT ?? 8000)

app.use(express.urlencoded({ extended: true }))
app.use(express.json())
Expand All @@ -15,4 +17,6 @@ app.listen(port, host, () => {
console.log(`Server is listening on http://${host}:${port}`)
})

nodeCleanup(cleanup)

export default app
84 changes: 59 additions & 25 deletions backend/controllers/chatController.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,71 @@
import { MessageType } from '@adiwajshing/baileys'
import { getChatList, formatPhone } from './../whatsapp.js'
import { getSession, getChatList, isExists, sendMessage, formatPhone } from './../whatsapp.js'
import response from './../response.js'

const getList = (req, res) => {
const { session } = res.locals

return response(res, 200, true, '', getChatList(session))
return response(res, 200, true, '', getChatList(res.locals.sessionId))
}

const send = (req, res) => {
const { session } = res.locals
const send = async (req, res) => {
const session = getSession(res.locals.sessionId)
const receiver = formatPhone(req.body.receiver)
const { message } = req.body

session
.isOnWhatsApp(receiver)
.then((data) => {
if (!data.exists) {
return response(res, 400, false, 'The receiver number cannot be found.')
try {
const exists = await isExists(session, receiver)

if (!exists) {
return response(res, 400, false, 'The receiver number is not exists.')
}

await sendMessage(session, receiver, { text: message })

response(res, 200, true, 'The message has been successfully sent.')
} catch {
response(res, 500, false, 'Failed to send the message.')
}
}

const sendBulk = async (req, res) => {
const session = getSession(res.locals.sessionId)
const errors = []

for (const [key, data] of req.body.entries()) {
if (!data.receiver || !data.message) {
errors.push(key)

continue
}

data.receiver = formatPhone(data.receiver)

try {
const exists = await isExists(session, data.receiver)

if (!exists) {
errors.push(key)

continue
}

session
.sendMessage(receiver, message, MessageType.text)
.then(() => {
return response(res, 200, true, 'The message has been successfully sent.')
})
.catch(() => {
return response(res, 500, false, 'Failed to send the message.')
})
})
.catch(() => {
return response(res, 500, false, 'Cannot validate receiver number.')
})
await sendMessage(session, data.receiver, { text: data.message })
} catch {
errors.push(key)
}
}

if (errors.length === 0) {
return response(res, 200, true, 'All messages has been successfully sent.')
}

const isAllFailed = errors.length === req.body.length

response(
res,
isAllFailed ? 500 : 200,
!isAllFailed,
isAllFailed ? 'Failed to send all messages.' : 'Some messages has been successfully sent.',
{ errors }
)
}

export { getList, send }
export { getList, send, sendBulk }
39 changes: 26 additions & 13 deletions backend/controllers/getMessages.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
import { getSession } from '../whatsapp.js'
import response from './../response.js'

const getMessages = (req, res) => {
const getMessages = async (req, res) => {
const session = getSession(res.locals.sessionId)

/* eslint-disable camelcase */
const { session } = res.locals
const { jid } = req.params
const { limit = 25, cursor_id = null, cursor_fromMe = null } = req.query
const cursor = {
id: cursor_id,
fromMe: cursor_fromMe === null ? cursor_fromMe : cursor_fromMe === 'true',

const cursor = {}

if (cursor_id) {
cursor.before = {
id: cursor_id,
fromMe: Boolean(cursor_fromMe && cursor_fromMe === 'true'),
}
}
/* eslint-enable camelcase */

session
.loadMessages(jid, limit, cursor)
.then((messages) => {
return response(res, 200, true, '', messages)
})
.catch(() => {
return response(res, 500, false, 'Failed to load messages.')
})
try {
let messages
const useCursor = 'before' in cursor ? cursor : null

if (session.isLegacy) {
messages = await session.fetchMessagesFromWA(jid, limit, useCursor)
} else {
messages = await session.store.loadMessages(jid, limit, useCursor)
}

response(res, 200, true, '', messages)
} catch {
response(res, 500, false, 'Failed to load messages.')
}
}

export default getMessages
41 changes: 16 additions & 25 deletions backend/controllers/groupController.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,28 @@
import { MessageType } from '@adiwajshing/baileys'
import { getChatList, formatGroup } from './../whatsapp.js'
import { getSession, getChatList, isExists, sendMessage, formatGroup } from './../whatsapp.js'
import response from './../response.js'

const getList = (req, res) => {
const { session } = res.locals

return response(res, 200, true, '', getChatList(session, true))
return response(res, 200, true, '', getChatList(res.locals.sessionId, true))
}

const send = (req, res) => {
const { session } = res.locals
const send = async (req, res) => {
const session = getSession(res.locals.sessionId)
const receiver = formatGroup(req.body.receiver)
const { message } = req.body

session
.fetchGroupMetadataFromWA(receiver)
.then((data) => {
if (!data.id) {
return response(res, 400, false, 'The group cannot be found.')
}
try {
const exists = await isExists(session, receiver, true)

if (!exists) {
return response(res, 400, false, 'The group is not exists.')
}

await sendMessage(session, receiver, { text: message })

session
.sendMessage(receiver, message, MessageType.text)
.then(() => {
return response(res, 200, true, 'The message has been successfully sent.')
})
.catch(() => {
return response(res, 500, false, 'Failed to send the message.')
})
})
.catch(() => {
return response(res, 500, false, 'Cannot validate group.')
})
response(res, 200, true, 'The message has been successfully sent.')
} catch {
response(res, 500, false, 'Failed to send the message.')
}
}

export { getList, send }
Loading

0 comments on commit 8858ac5

Please sign in to comment.