Skip to content

Commit

Permalink
init md
Browse files Browse the repository at this point in the history
  • Loading branch information
ookamiiixd committed Feb 14, 2022
1 parent fc0848f commit 08aa94a
Show file tree
Hide file tree
Showing 18 changed files with 8,614 additions and 190 deletions.
4 changes: 4 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
HOST=127.0.0.1
PORT=8000
MAX_RETRIES=5
RECONNECT_INTERVAL=5000
3 changes: 2 additions & 1 deletion .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 .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 .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
package.json
package-lock.json
33 changes: 28 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,54 @@

An implementation of [@adiwajshing/Baileys](https://github.com/adiwajshing/Baileys) as a simple RESTful API service with multiple device support.

---

Note: this branch is intended for the **Beta Multi-Device** user, use the master branch instead if you're using the normal WhatsApp Web.

## 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 configrations. 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_md.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.

## 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 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 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, 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 [isExists] = await session.onWhatsApp(receiver)

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

await session.sendMessage(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 [isExists] = await session.onWhatsApp(data.receiver)

if (!isExists.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 session.sendMessage(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 }
31 changes: 17 additions & 14 deletions controllers/getMessages.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
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 { limit = 25, cursor_id = null } = req.query

const cursor = {}

if (cursor_id) {
cursor.before = { id: cursor_id }
}
/* 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 {
const messages = await session.store.loadMessages(jid, limit, 'before' in cursor ? cursor : null)

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

export default getMessages
41 changes: 16 additions & 25 deletions 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, 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 groupMeta = await session.groupMetadata(receiver)

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

await session.sendMessage(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 }
19 changes: 13 additions & 6 deletions controllers/sessionController.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
import { isSessionExists, createSession, triggerDeleteSession } from './../whatsapp.js'
import { isSessionExists, createSession, getSession, deleteSession } from './../whatsapp.js'
import response from './../response.js'

const find = (req, res) => {
if (isSessionExists(req.params.id)) {
return response(res, 200, true, 'Session found.')
}

return response(res, 404, false, 'Session not found.')
response(res, 404, false, 'Session not found.')
}

const add = (req, res) => {
const sessionId = req.body.id

if (isSessionExists(sessionId)) {
return response(res, 409, false, 'Session already exists, please use other id.')
return response(res, 409, false, 'Session already exists, please use another id.')
}

createSession(sessionId, res)
}

const del = (req, res) => {
triggerDeleteSession(req.params.id)
const del = async (req, res) => {
const sessionId = req.params.id

return response(res, 200, true, 'The session has been successfully deleted.')
try {
await getSession(sessionId).logout()
} catch {
} finally {
deleteSession(sessionId)
}

response(res, 200, true, 'The session has been successfully deleted.')
}

export { find, add, del }
6 changes: 6 additions & 0 deletions dirname.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { dirname } from 'path'
import { fileURLToPath } from 'url'

const __dirname = dirname(fileURLToPath(import.meta.url))

export default __dirname
8 changes: 4 additions & 4 deletions middleware/sessionValidator.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { getSession } from '../whatsapp.js'
import { isSessionExists } from '../whatsapp.js'
import response from './../response.js'

const validate = (req, res, next) => {
const session = getSession(req.query.id)
const sessionId = req.query.id

if (!session) {
if (!isSessionExists(sessionId)) {
return response(res, 404, false, 'Session not found.')
}

res.locals.session = session
res.locals.sessionId = sessionId
next()
}

Expand Down
Loading

0 comments on commit 08aa94a

Please sign in to comment.