AUXteam commited on
Commit
aa2e717
·
verified ·
1 Parent(s): 85d94e0

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. Dockerfile +20 -3
  2. src/app.ts +116 -47
Dockerfile CHANGED
@@ -1,20 +1,37 @@
1
  FROM node:22
2
 
 
3
  RUN apt-get update && apt-get install -y \
4
  chromium \
5
- procps \
6
- libxss1 \
7
  --no-install-recommends \
8
  && rm -rf /var/lib/apt/lists/*
9
 
 
10
  ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \
11
- PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
 
12
 
13
  WORKDIR /app
 
 
14
  COPY package*.json ./
 
 
15
  RUN node -e "const fs = require('fs'); const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8')); pkg.scripts.prepare = ''; pkg.scripts.start = 'node dist/app.js'; pkg.dependencies.express = '^4.18.2'; pkg.devDependencies['@types/express'] = '^4.17.17'; fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2));"
 
 
16
  RUN npm install --legacy-peer-deps
 
 
17
  COPY . .
 
 
18
  RUN npm run build
 
 
19
  EXPOSE 7860
 
 
20
  CMD ["node", "dist/app.js"]
 
1
  FROM node:22
2
 
3
+ # Install dependencies and Chromium
4
  RUN apt-get update && apt-get install -y \
5
  chromium \
6
+ fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf \
7
+ procps libxss1 \
8
  --no-install-recommends \
9
  && rm -rf /var/lib/apt/lists/*
10
 
11
+ # Set environment variables
12
  ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \
13
+ PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium \
14
+ PORT=7860
15
 
16
  WORKDIR /app
17
+
18
+ # Copy package files
19
  COPY package*.json ./
20
+
21
+ # Prepare package.json: ensure dependencies are present and scripts are safe for container
22
  RUN node -e "const fs = require('fs'); const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8')); pkg.scripts.prepare = ''; pkg.scripts.start = 'node dist/app.js'; pkg.dependencies.express = '^4.18.2'; pkg.devDependencies['@types/express'] = '^4.17.17'; fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2));"
23
+
24
+ # Install dependencies
25
  RUN npm install --legacy-peer-deps
26
+
27
+ # Copy all source
28
  COPY . .
29
+
30
+ # Build
31
  RUN npm run build
32
+
33
+ # Expose port
34
  EXPOSE 7860
35
+
36
+ # Start
37
  CMD ["node", "dist/app.js"]
src/app.ts CHANGED
@@ -1,69 +1,127 @@
1
  import express from 'express';
2
  import * as wppconnect from './index';
 
3
  import { Resolver } from 'dns';
4
 
 
 
 
 
 
 
 
 
5
  const app = express();
6
  const port = process.env.PORT || 7860;
 
7
  let whatsappClient: wppconnect.Whatsapp | null = null;
8
  let lastQR: string | null = null;
9
- let logs: string[] = [];
 
10
  let isReady = false;
11
 
12
  const log = (msg: string) => {
13
  const entry = `${new Date().toISOString()} - ${msg}`;
14
  console.log(entry);
15
- logs.push(entry);
16
- if (logs.length > 500) logs.shift();
17
  };
18
 
19
  app.use(express.json());
20
 
21
- app.get('/health', (req, res) => {
22
- res.json({
23
- status: 'UP',
24
- connected: !!whatsappClient,
25
- ready: isReady,
26
- hasQR: !!lastQR,
27
- uptime: process.uptime(),
28
- logs
29
- });
30
- });
31
-
32
  app.get('/', (req, res) => {
33
  if (lastQR) {
34
  res.send(`
35
  <html>
36
- <head><title>WPPConnect QR</title><meta http-equiv="refresh" content="30"></head>
37
- <body style="background:#111; color:#eee; display:flex; flex-direction:column; align-items:center; justify-content:center; height:100vh; margin:0; font-family:sans-serif;">
 
 
 
 
 
 
 
 
 
 
38
  <h2>Scan with WhatsApp</h2>
39
- <div style="background:white; padding:20px; border-radius:10px;">
40
- <pre style="font-size: 8px; line-height: 1; color: black; margin:0;">${lastQR}</pre>
41
  </div>
42
- <p>Last updated: ${new Date().toLocaleTimeString()}</p>
43
- <p>Status: ${isReady ? 'READY' : 'Waiting for scan...'}</p>
44
  </body>
45
  </html>
46
  `);
47
  } else if (isReady) {
48
- res.send('<h1>WhatsApp Connected and Ready!</h1><p>Check <a href="/api-docs">API Docs</a>.</p>');
 
 
 
 
 
 
 
 
 
 
 
 
49
  } else {
50
- res.send('<h1>Initializing...</h1><p>Please wait 1-2 minutes. Check <a href="/health">Health</a> for status.</p><script>setTimeout(()=>location.reload(), 10000)</script>');
 
 
 
 
 
 
 
 
 
 
 
 
51
  }
52
  });
53
 
 
 
 
 
 
 
 
 
 
 
54
  app.get('/api-docs', (req, res) => {
55
  res.json({
 
56
  endpoints: {
57
- '/health': 'Status and logs',
58
- '/send-poll': 'POST { telnumber, name, choices: [] }',
59
- '/send-message': 'POST { telnumber, message }'
 
60
  }
61
  });
62
  });
63
 
 
 
 
 
 
 
 
 
 
 
 
64
  app.post('/send-poll', async (req, res) => {
65
  const { telnumber, name, choices } = req.body;
66
- if (!whatsappClient) return res.status(503).json({ error: 'Not ready' });
67
  try {
68
  const result = await whatsappClient.sendPollMessage(`${telnumber}@c.us`, name, choices);
69
  res.json({ success: true, result });
@@ -72,57 +130,68 @@ app.post('/send-poll', async (req, res) => {
72
  }
73
  });
74
 
75
- async function getIP(host: string): Promise<string | null> {
 
 
 
76
  const resolver = new Resolver();
77
  resolver.setServers(['8.8.8.8', '1.1.1.1']);
 
78
  try {
79
  const addrs = await new Promise<string[]>((resolve, reject) => {
80
- resolver.resolve4(host, (err, addresses) => err ? reject(err) : resolve(addresses));
81
  });
82
- return addrs[0];
 
83
  } catch (e) {
84
- log(`Failed to resolve ${host}: ${e.message}`);
85
- return null;
86
  }
87
- }
88
 
89
- async function init() {
90
- log('Init starting...');
91
-
92
- const waIP = await getIP('web.whatsapp.com');
93
  const resolverRule = waIP ? `--host-resolver-rules="MAP web.whatsapp.com ${waIP}"` : '';
94
- if (waIP) log(`Using DNS bypass: web.whatsapp.com -> ${waIP}`);
95
 
96
  try {
97
  whatsappClient = await wppconnect.create({
98
  session: 'hf-session',
99
- catchQR: (b64, ascii) => { lastQR = ascii; log('QR updated'); },
 
 
 
 
100
  statusFind: (status) => {
101
- log('Status: ' + status);
102
- if (status === 'inChat') { isReady = true; lastQR = null; }
 
 
 
 
103
  },
104
  headless: true,
105
- useChrome: true,
106
  puppeteerOptions: {
107
- executablePath: process.env.PUPPETEER_EXECUTABLE_PATH,
108
  args: [
109
  '--no-sandbox',
110
  '--disable-setuid-sandbox',
111
  '--disable-dev-shm-usage',
112
  '--disable-gpu',
 
 
 
113
  resolverRule
114
  ].filter(Boolean),
115
  },
116
  autoClose: 0,
 
117
  });
118
- log('Init success');
119
  } catch (e) {
120
- log('Init error: ' + e.message);
121
- setTimeout(init, 60000);
122
  }
123
  }
124
 
125
  app.listen(port, () => {
126
- log('API on ' + port);
127
- setTimeout(init, 30000);
 
128
  });
 
1
  import express from 'express';
2
  import * as wppconnect from './index';
3
+ import dns from 'dns';
4
  import { Resolver } from 'dns';
5
 
6
+ // Configure global DNS for Node.js
7
+ try {
8
+ dns.setServers(['8.8.8.8', '1.1.1.1']);
9
+ console.log('Global DNS set to 8.8.8.8');
10
+ } catch (e) {
11
+ console.warn('Could not set global DNS:', e.message);
12
+ }
13
+
14
  const app = express();
15
  const port = process.env.PORT || 7860;
16
+
17
  let whatsappClient: wppconnect.Whatsapp | null = null;
18
  let lastQR: string | null = null;
19
+ let statusMsg: string = 'Initializing...';
20
+ let appLogs: string[] = [];
21
  let isReady = false;
22
 
23
  const log = (msg: string) => {
24
  const entry = `${new Date().toISOString()} - ${msg}`;
25
  console.log(entry);
26
+ appLogs.push(entry);
27
+ if (appLogs.length > 500) appLogs.shift();
28
  };
29
 
30
  app.use(express.json());
31
 
32
+ // Main status page
 
 
 
 
 
 
 
 
 
 
33
  app.get('/', (req, res) => {
34
  if (lastQR) {
35
  res.send(`
36
  <html>
37
+ <head>
38
+ <title>WPPConnect QR</title>
39
+ <meta http-equiv="refresh" content="30">
40
+ <style>
41
+ body { background: #121212; color: #eee; font-family: sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; margin: 0; }
42
+ .qr-container { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 4px 15px rgba(0,0,0,0.5); }
43
+ pre { font-size: 8px; line-height: 1; color: black; margin: 0; }
44
+ .status { margin-top: 20px; font-weight: bold; color: #4caf50; }
45
+ .logs { width: 80%; max-height: 200px; overflow-y: auto; background: #000; padding: 10px; font-size: 12px; margin-top: 20px; border: 1px solid #333; }
46
+ </style>
47
+ </head>
48
+ <body>
49
  <h2>Scan with WhatsApp</h2>
50
+ <div class="qr-container">
51
+ <pre>${lastQR}</pre>
52
  </div>
53
+ <p class="status">Status: ${statusMsg}</p>
54
+ <div class="logs">${appLogs.join('<br>') }</div>
55
  </body>
56
  </html>
57
  `);
58
  } else if (isReady) {
59
+ res.send(`
60
+ <html>
61
+ <head><title>WPPConnect Connected</title></head>
62
+ <body style="background: #121212; color: #eee; font-family: sans-serif; text-align: center; padding-top: 50px;">
63
+ <h1 style="color: #4caf50;">WhatsApp Connected!</h1>
64
+ <p>The API is ready for use.</p>
65
+ <a href="/api-docs" style="color: #2196f3;">View API Docs</a>
66
+ <div style="text-align: left; margin: 20px auto; width: 80%; background: #000; padding: 10px; font-size: 12px;">
67
+ ${appLogs.join('<br>')}
68
+ </div>
69
+ </body>
70
+ </html>
71
+ `);
72
  } else {
73
+ res.send(`
74
+ <html>
75
+ <head><title>WPPConnect Starting</title><meta http-equiv="refresh" content="10"></head>
76
+ <body style="background: #121212; color: #eee; font-family: sans-serif; text-align: center; padding-top: 50px;">
77
+ <h1>Initializing WPPConnect...</h1>
78
+ <p>${statusMsg}</p>
79
+ <p>Please wait a few moments. This page will refresh automatically.</p>
80
+ <div style="text-align: left; margin: 20px auto; width: 80%; background: #000; padding: 10px; font-size: 12px;">
81
+ ${appLogs.join('<br>')}
82
+ </div>
83
+ </body>
84
+ </html>
85
+ `);
86
  }
87
  });
88
 
89
+ app.get('/health', (req, res) => {
90
+ res.json({
91
+ status: 'UP',
92
+ connected: !!whatsappClient,
93
+ ready: isReady,
94
+ uptime: process.uptime(),
95
+ whatsappStatus: statusMsg
96
+ });
97
+ });
98
+
99
  app.get('/api-docs', (req, res) => {
100
  res.json({
101
+ name: "WPPConnect API",
102
  endpoints: {
103
+ "/": "GET - Web Interface / QR Code",
104
+ "/health": "GET - JSON health status",
105
+ "/send-message": "POST - { telnumber, message }",
106
+ "/send-poll": "POST - { telnumber, name, choices: [] }"
107
  }
108
  });
109
  });
110
 
111
+ app.post('/send-message', async (req, res) => {
112
+ const { telnumber, message } = req.body;
113
+ if (!whatsappClient || !isReady) return res.status(503).json({ error: 'WhatsApp not ready' });
114
+ try {
115
+ const result = await whatsappClient.sendText(`${telnumber}@c.us`, message);
116
+ res.json({ success: true, result });
117
+ } catch (e) {
118
+ res.status(500).json({ error: e.message });
119
+ }
120
+ });
121
+
122
  app.post('/send-poll', async (req, res) => {
123
  const { telnumber, name, choices } = req.body;
124
+ if (!whatsappClient || !isReady) return res.status(503).json({ error: 'WhatsApp not ready' });
125
  try {
126
  const result = await whatsappClient.sendPollMessage(`${telnumber}@c.us`, name, choices);
127
  res.json({ success: true, result });
 
130
  }
131
  });
132
 
133
+ async function start() {
134
+ log('Starting WPPConnect with DNS bypass strategy...');
135
+
136
+ // Try to resolve WA IP manually to bypass system DNS issues
137
  const resolver = new Resolver();
138
  resolver.setServers(['8.8.8.8', '1.1.1.1']);
139
+ let waIP = null;
140
  try {
141
  const addrs = await new Promise<string[]>((resolve, reject) => {
142
+ resolver.resolve4('web.whatsapp.com', (err, addresses) => err ? reject(err) : resolve(addresses));
143
  });
144
+ waIP = addrs[0];
145
+ log(`Resolved web.whatsapp.com to ${waIP}`);
146
  } catch (e) {
147
+ log(`DNS resolution failed even with 8.8.8.8: ${e.message}`);
 
148
  }
 
149
 
 
 
 
 
150
  const resolverRule = waIP ? `--host-resolver-rules="MAP web.whatsapp.com ${waIP}"` : '';
 
151
 
152
  try {
153
  whatsappClient = await wppconnect.create({
154
  session: 'hf-session',
155
+ catchQR: (b64, ascii) => {
156
+ lastQR = ascii;
157
+ statusMsg = 'Waiting for scan';
158
+ log('New QR generated');
159
+ },
160
  statusFind: (status) => {
161
+ statusMsg = status;
162
+ log('WhatsApp Status: ' + status);
163
+ if (status === 'inChat') {
164
+ isReady = true;
165
+ lastQR = null;
166
+ }
167
  },
168
  headless: true,
169
+ useChrome: false,
170
  puppeteerOptions: {
171
+ executablePath: '/usr/bin/chromium',
172
  args: [
173
  '--no-sandbox',
174
  '--disable-setuid-sandbox',
175
  '--disable-dev-shm-usage',
176
  '--disable-gpu',
177
+ '--no-zygote',
178
+ '--single-process',
179
+ '--dns-servers=8.8.8.8,1.1.1.1',
180
  resolverRule
181
  ].filter(Boolean),
182
  },
183
  autoClose: 0,
184
+ updatesLog: false,
185
  });
186
+ log('WPPConnect client initialized');
187
  } catch (e) {
188
+ log('Initialization Failed: ' + e.message);
189
+ setTimeout(start, 30000);
190
  }
191
  }
192
 
193
  app.listen(port, () => {
194
+ log(`API Server running on port ${port}`);
195
+ // Start init with a small delay to ensure express is serving /health
196
+ setTimeout(start, 5000);
197
  });