Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4f734d8ff | ||
|
|
983e8dbbd3 | ||
|
|
b2150477d7 | ||
|
|
f83eeac33a | ||
|
|
37c4a85e76 | ||
|
|
8732af0f43 | ||
|
|
dfa7bc2ca8 | ||
|
|
f857bab540 | ||
|
|
59f2e1526d | ||
|
|
abe273166b | ||
|
|
3e37e933b2 | ||
|
|
6d2cae0784 | ||
|
|
0bf44dae88 | ||
|
|
9c9d6fda10 | ||
|
|
8b82f76668 |
No files matched your search
@@ -1,3 +1,4 @@
|
|||||||
|
Dockerfile
|
||||||
tokens
|
tokens
|
||||||
files
|
files
|
||||||
venv
|
venv
|
||||||
|
|||||||
@@ -40,5 +40,5 @@ jobs:
|
|||||||
push: ${{ github.ref_type == 'tag' }}
|
push: ${{ github.ref_type == 'tag' }}
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
cache-from: type=gha
|
# cache-from: type=gha
|
||||||
cache-to: type=gha
|
cache-to: type=gha
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
repos:
|
||||||
|
- repo: https://github.com/Lucas-C/pre-commit-hooks-nodejs
|
||||||
|
rev: v1.1.2
|
||||||
|
hooks:
|
||||||
|
- id: markdown-toc
|
||||||
+3
-2
@@ -5,7 +5,7 @@ RUN apt-get update \
|
|||||||
&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
|
&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
|
||||||
&& sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
|
&& sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
|
||||||
&& apt-get update \
|
&& apt-get update \
|
||||||
&& apt-get install -y google-chrome-unstable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf \
|
&& apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf \
|
||||||
--no-install-recommends \
|
--no-install-recommends \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
@@ -19,5 +19,6 @@ RUN npm install
|
|||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ADD . /app
|
ADD . /app
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
ENTRYPOINT npm run start:prod
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD npm run start:prod
|
||||||
@@ -5,8 +5,28 @@ WhatsApp HTTP API that you can configure in a click! It's really Free! :)
|
|||||||
The project provides you HTTP API for Whatsapp that you can use to send and receive messages. You can
|
The project provides you HTTP API for Whatsapp that you can use to send and receive messages. You can
|
||||||
go [through currently supported methods in Swagger](https://allburov.github.io/whatsapp-http-api/)
|
go [through currently supported methods in Swagger](https://allburov.github.io/whatsapp-http-api/)
|
||||||
|
|
||||||
The project is an HTTP API wrapper around https://github.com/orkestral/venom
|
> The project is an HTTP API wrapper around https://github.com/orkestral/venom
|
||||||
|
|
||||||
|
# Tables of Contents
|
||||||
|
|
||||||
|
<!-- toc -->
|
||||||
|
|
||||||
|
- [Installation](#installation)
|
||||||
|
- [First Steps](#first-steps)
|
||||||
|
* [Run WhatsAPP HTTP API](#run-whatsapp-http-api)
|
||||||
|
* [Create a new session and login](#create-a-new-session-and-login)
|
||||||
|
* [Send a text message](#send-a-text-message)
|
||||||
|
- [Receive messages](#receive-messages)
|
||||||
|
+ [Python echo server](#python-echo-server)
|
||||||
|
- [Environment variables](#environment-variables)
|
||||||
|
* [Common](#common)
|
||||||
|
* [Webhooks](#webhooks)
|
||||||
|
* [File storage](#file-storage)
|
||||||
|
- [How to](#how-to)
|
||||||
|
* [How to build the newest Docker image locally](#how-to-build-the-newest-docker-image-locally)
|
||||||
|
- [Support](#support)
|
||||||
|
|
||||||
|
<!-- tocstop -->
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
@@ -116,6 +136,7 @@ If you try to send an image the "echo server" will send a path to the downloaded
|
|||||||
- `DEBUG` - show debug and verbose logs, set in any value
|
- `DEBUG` - show debug and verbose logs, set in any value
|
||||||
- `WHATSAPP_API_PORT` - listen port for HTTP server (default: `3000`)
|
- `WHATSAPP_API_PORT` - listen port for HTTP server (default: `3000`)
|
||||||
- `WHATSAPP_API_HOSTNAME` - Hostname for HTTP server (default: `localhost`)
|
- `WHATSAPP_API_HOSTNAME` - Hostname for HTTP server (default: `localhost`)
|
||||||
|
- `WHATSAPP_START_SESSION` - start session with that name right after launching the app
|
||||||
|
|
||||||
## Webhooks
|
## Webhooks
|
||||||
|
|
||||||
@@ -123,11 +144,18 @@ The description of [webhooks you can in Venom README.md, section Events](https:/
|
|||||||
|
|
||||||
All webhooks are disabled by default:
|
All webhooks are disabled by default:
|
||||||
|
|
||||||
|
- `WHATSAPP_HOOK_ONANYMESSAGE=http://localhost/uri`
|
||||||
- `WHATSAPP_HOOK_ONMESSAGE=http://localhost/uri`
|
- `WHATSAPP_HOOK_ONMESSAGE=http://localhost/uri`
|
||||||
- `WHATSAPP_HOOK_ONSTATECHANGE=http://localhost/uri`
|
- `WHATSAPP_HOOK_ONSTATECHANGE=http://localhost/uri`
|
||||||
- `WHATSAPP_HOOK_ONACK=http://localhost/uri`
|
- `WHATSAPP_HOOK_ONACK=http://localhost/uri`
|
||||||
- `WHATSAPP_HOOK_ONADDEDTOGROUP=http://localhost/uri`
|
- `WHATSAPP_HOOK_ONADDEDTOGROUP=http://localhost/uri`
|
||||||
|
|
||||||
|
If you want to look at the payload of the webhooks - use the url for that `https://httpbin.org/post`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -it -v `pwd`/tokens:/app/tokens --network=host -e WHATSAPP_HOOK_ONMESSAGE=https://httpbin.org/post allburov/whatsapp-http-api
|
||||||
|
```
|
||||||
|
|
||||||
## File storage
|
## File storage
|
||||||
|
|
||||||
- `WHATSAPP_FILES_FOLDER` - folder where will be stored files from chats (images, voice messages) (
|
- `WHATSAPP_FILES_FOLDER` - folder where will be stored files from chats (images, voice messages) (
|
||||||
@@ -137,10 +165,21 @@ All webhooks are disabled by default:
|
|||||||
like `audio,image`).
|
like `audio,image`).
|
||||||
- `WHATSAPP_FILES_LIFETIME`- to keep free space files will be removed after this time (default: `180`, in seconds)
|
- `WHATSAPP_FILES_LIFETIME`- to keep free space files will be removed after this time (default: `180`, in seconds)
|
||||||
|
|
||||||
|
# How to
|
||||||
|
## How to build the newest Docker image locally
|
||||||
|
|
||||||
|
If the changes haven't been released yet from `main` branch - you can build your own version from the git repository
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/allburov/whatsapp-http-api.git
|
||||||
|
cd whatsapp-http-api
|
||||||
|
docker build . -t allburov/whatsapp-http-api
|
||||||
|
```
|
||||||
|
|
||||||
# Support
|
# Support
|
||||||
|
|
||||||
If you want to support the project - you can either:
|
If you want to support the project - you can either:
|
||||||
|
|
||||||
1. Create a Pull Request for desired functionality
|
1. Create a Pull Request for desired functionality
|
||||||
2. Support [the project one time, every month or get access to telegram channel on Boosty](https://boosty.to/allburov)
|
2. Support [the project one time, every month or get access to telegram channel on Boosty](https://boosty.to/allburov)
|
||||||
|
3. Looking for the personal support, have an important feature request for your business, need to develop a whatsapp bot? [Reach me out at Telegram](https://t.me/allburov)!
|
||||||
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
version: '3.4'
|
|
||||||
|
|
||||||
services:
|
|
||||||
whatsapp-http-api:
|
|
||||||
build: .
|
|
||||||
image: allburov/whatsapp-http-api
|
|
||||||
restart: always
|
|
||||||
ports:
|
|
||||||
- 3000:3000
|
|
||||||
shm_size: "1gb"
|
|
||||||
environment:
|
|
||||||
- WHATSAPP_DOWNLOADS_FOLDER=/app/files/downloads
|
|
||||||
volumes:
|
|
||||||
- ./tokens:/app/tokens
|
|
||||||
- ./files:/app/files
|
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
"start:dev": "nest start --watch",
|
"start:dev": "nest start --watch",
|
||||||
"start:debug": "nest start --debug --watch",
|
"start:debug": "nest start --debug --watch",
|
||||||
"start:prod": "node --unhandled-rejections=none dist/main",
|
"start:prod": "node --unhandled-rejections=none dist/main",
|
||||||
|
"start:prod-exit": "node dist/main",
|
||||||
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"test:watch": "jest --watch",
|
"test:watch": "jest --watch",
|
||||||
|
|||||||
@@ -53,6 +53,12 @@ export class MessageText extends ChatRequest {
|
|||||||
text: string;
|
text: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class MessageTextButtons extends ChatRequest {
|
||||||
|
text: string;
|
||||||
|
title: string;
|
||||||
|
buttons: any[];
|
||||||
|
}
|
||||||
|
|
||||||
export class MessageReply extends ChatRequest {
|
export class MessageReply extends ChatRequest {
|
||||||
text: string;
|
text: string;
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
MessageLocation,
|
MessageLocation,
|
||||||
MessageReply,
|
MessageReply,
|
||||||
MessageText,
|
MessageText,
|
||||||
|
MessageTextButtons,
|
||||||
MessageTextQuery
|
MessageTextQuery
|
||||||
} from "./all.dto";
|
} from "./all.dto";
|
||||||
import {ensureSuffix, WhatsappSessionManager} from "../whatsapp.service";
|
import {ensureSuffix, WhatsappSessionManager} from "../whatsapp.service";
|
||||||
@@ -29,7 +30,11 @@ export class ChattingController {
|
|||||||
try {
|
try {
|
||||||
const result = await whatsapp.checkNumberStatus(ensureSuffix(request.phone))
|
const result = await whatsapp.checkNumberStatus(ensureSuffix(request.phone))
|
||||||
return {numberExists: result['numberExists']}
|
return {numberExists: result['numberExists']}
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
|
// We need to "touch" the error in order to get unhandled rejections
|
||||||
|
// It logs out the session and stop the app
|
||||||
|
console.log(typeof error)
|
||||||
|
console.log(error)
|
||||||
return {numberExists: false}
|
return {numberExists: false}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,6 +61,13 @@ export class ChattingController {
|
|||||||
return whatsapp.sendText(ensureSuffix(message.chatId), message.text)
|
return whatsapp.sendText(ensureSuffix(message.chatId), message.text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post('/sendTextButtons')
|
||||||
|
@ApiOperation({summary: 'Send a text message with buttons'})
|
||||||
|
sendTextButtons(@Body() message: MessageTextButtons) {
|
||||||
|
const whatsapp = this.whatsappSessionManager.getSession(message.sessionName)
|
||||||
|
return whatsapp.sendButtons(ensureSuffix(message.chatId), message.title, message.buttons, message.text)
|
||||||
|
}
|
||||||
|
|
||||||
@Post('/sendLocation')
|
@Post('/sendLocation')
|
||||||
sendLocation(@Body() message: MessageLocation) {
|
sendLocation(@Body() message: MessageLocation) {
|
||||||
const whatsapp = this.whatsappSessionManager.getSession(message.sessionName)
|
const whatsapp = this.whatsappSessionManager.getSession(message.sessionName)
|
||||||
|
|||||||
@@ -46,6 +46,10 @@ export class WhatsappConfigService {
|
|||||||
return types ? types.split(',') : null
|
return types ? types.split(',') : null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get startSession(): string | undefined {
|
||||||
|
return this.configService.get('WHATSAPP_START_SESSION', undefined)
|
||||||
|
}
|
||||||
|
|
||||||
get(name: string): any {
|
get(name: string): any {
|
||||||
return this.configService.get(name)
|
return this.configService.get(name)
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-4
@@ -15,9 +15,11 @@ const writeFileAsync = promisify(fs.writeFile)
|
|||||||
|
|
||||||
const SECOND = 1000;
|
const SECOND = 1000;
|
||||||
|
|
||||||
const ONMESSAGE_HOOK = "onMessage"
|
const ON_ANY_MESSAGE_HOOK = "onAnyMessage"
|
||||||
|
const ON_MESSAGE_HOOK = "onMessage"
|
||||||
const HOOKS = [
|
const HOOKS = [
|
||||||
ONMESSAGE_HOOK,
|
ON_ANY_MESSAGE_HOOK,
|
||||||
|
ON_MESSAGE_HOOK,
|
||||||
"onStateChange",
|
"onStateChange",
|
||||||
"onAck",
|
"onAck",
|
||||||
// TODO: IMPLEMENTED THESE TOO
|
// TODO: IMPLEMENTED THESE TOO
|
||||||
@@ -65,7 +67,8 @@ export class WhatsappService {
|
|||||||
this.saveQRCode(base64Qrimg)
|
this.saveQRCode(base64Qrimg)
|
||||||
this.status = WhatsappStatus.SCAN_QR_CODE
|
this.status = WhatsappStatus.SCAN_QR_CODE
|
||||||
console.log('Number of attempts to read the qrcode: ', attempts);
|
console.log('Number of attempts to read the qrcode: ', attempts);
|
||||||
console.log('Terminal qrcode: ', asciiQR);
|
console.log('Terminal qrcode:');
|
||||||
|
console.log(asciiQR);
|
||||||
},
|
},
|
||||||
undefined,
|
undefined,
|
||||||
{
|
{
|
||||||
@@ -190,7 +193,7 @@ export class WhatsappService {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hook === ONMESSAGE_HOOK) {
|
if (hook === ON_MESSAGE_HOOK || hook == ON_ANY_MESSAGE_HOOK) {
|
||||||
this.whatsapp[hook](data => this.onMessageHook(data, url))
|
this.whatsapp[hook](data => this.onMessageHook(data, url))
|
||||||
} else {
|
} else {
|
||||||
this.whatsapp[hook](data => this.callWebhook(data, url))
|
this.whatsapp[hook](data => this.callWebhook(data, url))
|
||||||
@@ -221,6 +224,9 @@ export class WhatsappSessionManager implements OnApplicationShutdown {
|
|||||||
this.log.setContext('WhatsappSessionManager')
|
this.log.setContext('WhatsappSessionManager')
|
||||||
this.cleanDownloadsFolder(this.config.filesFolder)
|
this.cleanDownloadsFolder(this.config.filesFolder)
|
||||||
this.sessions = {}
|
this.sessions = {}
|
||||||
|
if (config.startSession) {
|
||||||
|
this.startSession(config.startSession)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async startSession(name: string) {
|
async startSession(name: string) {
|
||||||
|
|||||||
Reference in new issue
Block a user