vantuz 3.1.0 β 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/channels.js +23 -283
- package/package.json +1 -1
package/core/channels.js
CHANGED
|
@@ -1,255 +1,45 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* π± CHANNEL MANAGER
|
|
3
|
-
*
|
|
2
|
+
* π± CHANNEL MANAGER (OpenClaw)
|
|
3
|
+
* OpenClaw Gateway entegrasyonu
|
|
4
4
|
*
|
|
5
|
-
* OpenClaw
|
|
5
|
+
* NOT: WhatsApp baΔlantΔ±sΔ± iΓ§in OpenClaw Gateway CLI kullanΔ±lmalΔ±dΔ±r:
|
|
6
|
+
* > openclaw channels login
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
9
|
import fs from 'fs';
|
|
9
10
|
import path from 'path';
|
|
10
11
|
import os from 'os';
|
|
11
|
-
import axios from 'axios';
|
|
12
12
|
import { log } from './ai-provider.js';
|
|
13
13
|
|
|
14
14
|
const VANTUZ_HOME = path.join(os.homedir(), '.vantuz');
|
|
15
15
|
const CONFIG_PATH = path.join(VANTUZ_HOME, '.env');
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
this.name = name;
|
|
24
|
-
this.config = config;
|
|
25
|
-
this.connected = false;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async connect() {
|
|
29
|
-
throw new Error('connect() must be implemented');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async send(to, message) {
|
|
33
|
-
throw new Error('send() must be implemented');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async startListening(onMessage) {
|
|
37
|
-
throw new Error('startListening() must be implemented');
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
42
|
-
// WHATSAPP (via WhatsApp Business API / Twilio / Meta Cloud API)
|
|
43
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
44
|
-
|
|
45
|
-
export class WhatsAppChannel extends Channel {
|
|
46
|
-
constructor(config) {
|
|
47
|
-
super('whatsapp', config);
|
|
48
|
-
this.apiUrl = config.apiUrl || 'https://graph.facebook.com/v17.0';
|
|
49
|
-
this.phoneNumberId = config.phoneNumberId;
|
|
50
|
-
this.accessToken = config.accessToken;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async connect() {
|
|
54
|
-
if (!this.phoneNumberId || !this.accessToken) {
|
|
55
|
-
log('ERROR', 'WhatsApp: phoneNumberId veya accessToken eksik');
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
try {
|
|
60
|
-
// Verify connection
|
|
61
|
-
const response = await axios.get(
|
|
62
|
-
`${this.apiUrl}/${this.phoneNumberId}`,
|
|
63
|
-
{
|
|
64
|
-
headers: { 'Authorization': `Bearer ${this.accessToken}` }
|
|
65
|
-
}
|
|
66
|
-
);
|
|
67
|
-
this.connected = response.status === 200;
|
|
68
|
-
log('INFO', 'WhatsApp baΔlantΔ±sΔ± kuruldu', { phoneNumberId: this.phoneNumberId });
|
|
69
|
-
return true;
|
|
70
|
-
} catch (e) {
|
|
71
|
-
log('ERROR', 'WhatsApp baΔlantΔ± hatasΔ±', { error: e.message });
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async send(to, message) {
|
|
77
|
-
if (!this.connected) {
|
|
78
|
-
await this.connect();
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
try {
|
|
82
|
-
const response = await axios.post(
|
|
83
|
-
`${this.apiUrl}/${this.phoneNumberId}/messages`,
|
|
84
|
-
{
|
|
85
|
-
messaging_product: 'whatsapp',
|
|
86
|
-
recipient_type: 'individual',
|
|
87
|
-
to: to,
|
|
88
|
-
type: 'text',
|
|
89
|
-
text: { body: message }
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
headers: {
|
|
93
|
-
'Authorization': `Bearer ${this.accessToken}`,
|
|
94
|
-
'Content-Type': 'application/json'
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
log('INFO', 'WhatsApp mesaj gΓΆnderildi', { to, messageId: response.data?.messages?.[0]?.id });
|
|
100
|
-
return { success: true, messageId: response.data?.messages?.[0]?.id };
|
|
101
|
-
} catch (e) {
|
|
102
|
-
log('ERROR', 'WhatsApp gΓΆnderme hatasΔ±', { error: e.message });
|
|
103
|
-
return { success: false, error: e.message };
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Webhook handler iΓ§in
|
|
108
|
-
handleWebhook(body) {
|
|
109
|
-
const entry = body.entry?.[0];
|
|
110
|
-
const changes = entry?.changes?.[0];
|
|
111
|
-
const value = changes?.value;
|
|
112
|
-
const message = value?.messages?.[0];
|
|
113
|
-
|
|
114
|
-
if (message) {
|
|
115
|
-
return {
|
|
116
|
-
from: message.from,
|
|
117
|
-
text: message.text?.body || '',
|
|
118
|
-
timestamp: message.timestamp,
|
|
119
|
-
messageId: message.id
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
127
|
-
// TELEGRAM (via Telegram Bot API)
|
|
128
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
129
|
-
|
|
130
|
-
export class TelegramChannel extends Channel {
|
|
131
|
-
constructor(config) {
|
|
132
|
-
super('telegram', config);
|
|
133
|
-
this.botToken = config.botToken;
|
|
134
|
-
this.apiUrl = `https://api.telegram.org/bot${this.botToken}`;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
async connect() {
|
|
138
|
-
if (!this.botToken) {
|
|
139
|
-
log('ERROR', 'Telegram: botToken eksik');
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
try {
|
|
144
|
-
const response = await axios.get(`${this.apiUrl}/getMe`);
|
|
145
|
-
if (response.data.ok) {
|
|
146
|
-
this.botInfo = response.data.result;
|
|
147
|
-
this.connected = true;
|
|
148
|
-
log('INFO', 'Telegram baΔlantΔ±sΔ± kuruldu', { username: this.botInfo.username });
|
|
149
|
-
return true;
|
|
150
|
-
}
|
|
151
|
-
return false;
|
|
152
|
-
} catch (e) {
|
|
153
|
-
log('ERROR', 'Telegram baΔlantΔ± hatasΔ±', { error: e.message });
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
async send(chatId, message, options = {}) {
|
|
159
|
-
if (!this.connected) {
|
|
160
|
-
await this.connect();
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
try {
|
|
164
|
-
const response = await axios.post(`${this.apiUrl}/sendMessage`, {
|
|
165
|
-
chat_id: chatId,
|
|
166
|
-
text: message,
|
|
167
|
-
parse_mode: options.parseMode || 'HTML',
|
|
168
|
-
...options
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
log('INFO', 'Telegram mesaj gΓΆnderildi', { chatId, messageId: response.data?.result?.message_id });
|
|
172
|
-
return { success: true, messageId: response.data?.result?.message_id };
|
|
173
|
-
} catch (e) {
|
|
174
|
-
log('ERROR', 'Telegram gΓΆnderme hatasΔ±', { error: e.message });
|
|
175
|
-
return { success: false, error: e.message };
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
async setWebhook(url) {
|
|
180
|
-
try {
|
|
181
|
-
const response = await axios.post(`${this.apiUrl}/setWebhook`, {
|
|
182
|
-
url: url,
|
|
183
|
-
allowed_updates: ['message', 'callback_query']
|
|
184
|
-
});
|
|
185
|
-
log('INFO', 'Telegram webhook ayarlandΔ±', { url });
|
|
186
|
-
return response.data.ok;
|
|
187
|
-
} catch (e) {
|
|
188
|
-
log('ERROR', 'Telegram webhook hatasΔ±', { error: e.message });
|
|
189
|
-
return false;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
async getUpdates(offset = 0) {
|
|
194
|
-
try {
|
|
195
|
-
const response = await axios.post(`${this.apiUrl}/getUpdates`, {
|
|
196
|
-
offset,
|
|
197
|
-
timeout: 30
|
|
198
|
-
});
|
|
199
|
-
return response.data.result || [];
|
|
200
|
-
} catch (e) {
|
|
201
|
-
log('ERROR', 'Telegram getUpdates hatasΔ±', { error: e.message });
|
|
202
|
-
return [];
|
|
203
|
-
}
|
|
17
|
+
export class ChannelManager {
|
|
18
|
+
constructor() {
|
|
19
|
+
this.status = {
|
|
20
|
+
whatsapp: { connected: false, mode: 'gateway' },
|
|
21
|
+
telegram: { connected: false, mode: 'gateway' }
|
|
22
|
+
};
|
|
204
23
|
}
|
|
205
24
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
log('INFO', 'Telegram polling baΕlatΔ±ldΔ±');
|
|
210
|
-
|
|
211
|
-
while (true) {
|
|
212
|
-
try {
|
|
213
|
-
const updates = await this.getUpdates(offset);
|
|
214
|
-
|
|
215
|
-
for (const update of updates) {
|
|
216
|
-
offset = update.update_id + 1;
|
|
25
|
+
async initAll() {
|
|
26
|
+
// OpenClaw Gateway durumunu kontrol et (varsayΔ±m)
|
|
27
|
+
// GerΓ§ekte Gateway ayrΔ± bir process olarak Γ§alΔ±ΕΔ±r
|
|
217
28
|
|
|
218
|
-
|
|
219
|
-
const msg = {
|
|
220
|
-
chatId: update.message.chat.id,
|
|
221
|
-
from: update.message.from,
|
|
222
|
-
text: update.message.text,
|
|
223
|
-
messageId: update.message.message_id
|
|
224
|
-
};
|
|
29
|
+
const env = this._loadEnv();
|
|
225
30
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
if (response) {
|
|
230
|
-
await this.send(msg.chatId, response);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
} catch (e) {
|
|
236
|
-
log('ERROR', 'Polling hatasΔ±', { error: e.message });
|
|
237
|
-
await new Promise(r => setTimeout(r, 5000));
|
|
238
|
-
}
|
|
31
|
+
if (env.TELEGRAM_BOT_TOKEN) {
|
|
32
|
+
this.status.telegram.connected = true;
|
|
33
|
+
this.status.telegram.info = 'Bot Token Configured';
|
|
239
34
|
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
35
|
|
|
243
|
-
//
|
|
244
|
-
|
|
245
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
36
|
+
// WhatsApp iΓ§in kullanΔ±cΔ± manuel login olmalΔ±
|
|
37
|
+
this.status.whatsapp.info = 'Run "openclaw channels login" to connect';
|
|
246
38
|
|
|
247
|
-
|
|
248
|
-
constructor() {
|
|
249
|
-
this.channels = {};
|
|
39
|
+
return this.status;
|
|
250
40
|
}
|
|
251
41
|
|
|
252
|
-
|
|
42
|
+
_loadEnv() {
|
|
253
43
|
const env = {};
|
|
254
44
|
try {
|
|
255
45
|
if (fs.existsSync(CONFIG_PATH)) {
|
|
@@ -265,58 +55,8 @@ export class ChannelManager {
|
|
|
265
55
|
return env;
|
|
266
56
|
}
|
|
267
57
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const results = {};
|
|
271
|
-
|
|
272
|
-
// WhatsApp
|
|
273
|
-
if (env.WHATSAPP_PHONE_NUMBER_ID && env.WHATSAPP_ACCESS_TOKEN) {
|
|
274
|
-
const wa = new WhatsAppChannel({
|
|
275
|
-
phoneNumberId: env.WHATSAPP_PHONE_NUMBER_ID,
|
|
276
|
-
accessToken: env.WHATSAPP_ACCESS_TOKEN
|
|
277
|
-
});
|
|
278
|
-
if (await wa.connect()) {
|
|
279
|
-
this.channels.whatsapp = wa;
|
|
280
|
-
results.whatsapp = true;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Telegram
|
|
285
|
-
if (env.TELEGRAM_BOT_TOKEN) {
|
|
286
|
-
const tg = new TelegramChannel({
|
|
287
|
-
botToken: env.TELEGRAM_BOT_TOKEN
|
|
288
|
-
});
|
|
289
|
-
if (await tg.connect()) {
|
|
290
|
-
this.channels.telegram = tg;
|
|
291
|
-
results.telegram = true;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
return results;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
getChannel(name) {
|
|
299
|
-
return this.channels[name];
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
getConnected() {
|
|
303
|
-
return Object.keys(this.channels);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
async broadcast(message, channels = 'all') {
|
|
307
|
-
const targets = channels === 'all'
|
|
308
|
-
? Object.keys(this.channels)
|
|
309
|
-
: channels.split(',');
|
|
310
|
-
|
|
311
|
-
const results = {};
|
|
312
|
-
for (const ch of targets) {
|
|
313
|
-
if (this.channels[ch]) {
|
|
314
|
-
// Not: WhatsApp ve Telegram iΓ§in farklΔ± recipient gerekir
|
|
315
|
-
// Bu ΓΆrnek bir demonstration, gerΓ§ek kullanΔ±mda recipient listesi lazΔ±m
|
|
316
|
-
results[ch] = 'Channel ready';
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
return results;
|
|
58
|
+
getStatus() {
|
|
59
|
+
return this.status;
|
|
320
60
|
}
|
|
321
61
|
}
|
|
322
62
|
|