File size: 4,919 Bytes
9844ee9
 
87ab1e4
1be4e49
87ab1e4
aa2e717
9844ee9
1fd158f
aa2e717
9844ee9
1be4e49
 
aa2e717
c6a52f3
1be4e49
8240bb3
 
 
 
aa2e717
7a12d0e
8240bb3
9844ee9
 
 
1fd158f
 
 
 
 
 
 
 
 
 
 
 
aca0d15
 
c6a52f3
 
36d7482
fcb47be
36d7482
 
e6b9d7d
36d7482
 
 
 
 
 
be6512c
40ae9f8
aa2e717
 
36d7482
 
 
 
1be4e49
 
1a89404
c46657d
1a89404
 
 
7a12d0e
 
 
 
c46657d
1a89404
 
 
 
 
1fd158f
 
 
 
 
 
40ae9f8
aa2e717
 
c46657d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
aca0d15
1be4e49
 
aca0d15
c46657d
 
 
 
 
 
 
 
aa2e717
c46657d
7a12d0e
87ab1e4
bdf4689
 
34728cc
1be4e49
 
1fd158f
7a12d0e
1fd158f
 
 
be6512c
36d7482
1fd158f
bdf4689
aa2e717
bdf4689
aa2e717
1be4e49
 
 
 
 
7a12d0e
c46657d
 
bdf4689
 
aa2e717
1fd158f
bdf4689
be6512c
 
c46657d
 
7a12d0e
c46657d
 
 
be6512c
 
7a12d0e
40ae9f8
3d88f91
aca0d15
40ae9f8
1be4e49
9844ee9
 
 
 
c46657d
34728cc
9844ee9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
import express from 'express';
import * as wppconnect from './index';
import { Resolver } from 'dns';
import fs from 'fs';
import path from 'path';

const app = express();
const port = process.env.NODE_PORT || 3000;

let whatsappClient: wppconnect.Whatsapp | null = null;
let lastQR: { ascii: string, base64: string } | null = null;
let statusMsg: string = 'Disconnected';
let appLogs: string[] = [];
let isReady = false;
let isInitializing = false;

const log = (msg: string) => {
  const entry = `${new Date().toISOString()} - ${msg}`;
  console.log(entry);
  appLogs.push(entry);
  if (appLogs.length > 500) appLogs.shift();
};

app.use(express.json());

app.get('/health', (req, res) => {
  res.json({ 
    status: 'UP', 
    connected: !!whatsappClient, 
    ready: isReady, 
    whatsappStatus: statusMsg,
    hasQR: !!lastQR,
    logs: appLogs 
  });
});

app.get('/qr-data', (req, res) => {
  if (lastQR) res.json(lastQR);
  else res.status(404).json({ error: 'No QR' });
});

app.get('/screenshot', async (req, res) => {
  if (whatsappClient && whatsappClient.page && !whatsappClient.page.isClosed()) {
    try {
      const screenshot = await whatsappClient.page.screenshot({ encoding: 'base64' });
      const img = Buffer.from(screenshot as string, 'base64');
      res.writeHead(200, { 'Content-Type': 'image/png', 'Content-Length': img.length });
      res.end(img);
    } catch (e: any) {
      res.status(500).json({ error: e.message });
    }
  } else {
    res.status(404).json({ error: 'Browser not active' });
  }
});

app.post('/init', (req, res) => {
  if (isInitializing) return res.json({ success: false, message: 'Already initializing' });
  startWPP();
  res.json({ success: true });
});

app.post('/clear-session', (req, res) => {
  log('Manual session clear');
  try {
    const tokensDir = path.join(process.cwd(), 'tokens');
    if (fs.existsSync(tokensDir)) fs.rmSync(tokensDir, { recursive: true, force: true });
    whatsappClient = null;
    isReady = false;
    lastQR = null;
    statusMsg = 'Cleared';
    res.json({ success: true });
  } catch (e: any) {
    res.status(500).json({ error: e.message });
  }
});

app.post('/send-poll', async (req, res) => {
  const { telnumber, name, choices } = req.body;
  if (!whatsappClient || !isReady) return res.status(503).json({ error: 'WhatsApp not ready' });
  try {
    const result = await whatsappClient.sendPollMessage(`${telnumber}@c.us`, name, choices);
    res.json({ success: true, result });
  } catch (e: any) { res.status(500).json({ error: e.message }); }
});

async function resolveMany(hosts: string[]): Promise<string[]> {
  const resolver = new Resolver();
  resolver.setServers(['8.8.8.8', '1.1.1.1']);
  const rules: string[] = [];
  for (const host of hosts) {
    try {
      const addrs = await new Promise<string[]>((resolve, reject) => {
        resolver.resolve4(host, (err, addresses) => err ? reject(err) : resolve(addresses));
      });
      if (addrs.length > 0) {
        rules.push(`MAP ${host} ${addrs[0]}`);
      }
    } catch (e) {}
  }
  return rules;
}

async function startWPP() {
  if (isInitializing) return;
  isInitializing = true;
  statusMsg = 'Initializing...';
  log('Starting initialization...');

  const dnsRules = await resolveMany([
    'web.whatsapp.com',
    'static.whatsapp.net',
    'pps.whatsapp.net',
    'mms.whatsapp.net'
  ]);
  
  const hostRules = dnsRules.join(',');
  if (hostRules) log(`Host Rules: ${hostRules}`);

  try {
    whatsappClient = await wppconnect.create({
      session: 'hf-session',
      catchQR: (base64, ascii) => { 
        lastQR = { base64, ascii }; 
        statusMsg = 'Waiting for scan'; 
        log('QR code updated');
      },
      statusFind: (status) => { 
        statusMsg = status; 
        log('Status: ' + status);
        if (status === 'inChat') { isReady = true; lastQR = null; } 
      },
      headless: true,
      useChrome: false,
      puppeteerOptions: {
        executablePath: '/usr/bin/chromium',
        args: [
          '--no-sandbox',
          '--disable-setuid-sandbox',
          '--disable-dev-shm-usage',
          '--disable-gpu',
          '--disable-web-security',
          hostRules ? `--host-resolver-rules=${hostRules}` : ''
        ].filter(Boolean),
      },
      autoClose: 0,
      updatesLog: false,
      waitForLogin: false,
    });
    
    if (whatsappClient.page) {
      whatsappClient.page.on('console', msg => {
          const text = msg.text();
          if (!text.includes('TypeError: window.WAPI') && !text.includes('WAPI is not defined')) {
             log(`Browser: ${text}`);
          }
      });
    }

    log('Client Object Created');
  } catch (e: any) {
    log('Init Error: ' + e.message);
    statusMsg = 'Error: ' + e.message;
  } finally {
    isInitializing = false;
  }
}

app.listen(port, () => {
  log(`Node Backend on port ${port}`);
  setTimeout(startWPP, 5000);
});