waengine 1.0.7 → 1.0.9
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/CHANGELOG.md +89 -0
- package/FEATURES.md +2354 -0
- package/PLUGIN-SYSTEM.md +271 -0
- package/package.json +14 -3
- package/plugins/analytics-plugin/config.json +91 -0
- package/plugins/analytics-plugin/index.js +461 -0
- package/plugins/creative-plugin/config.json +87 -0
- package/plugins/creative-plugin/index.js +320 -0
- package/plugins/economy-system/config.json +48 -0
- package/plugins/economy-system/index.js +237 -0
- package/plugins/education-plugin/index.js +275 -0
- package/plugins/games-plugin/config.json +35 -0
- package/plugins/games-plugin/index.js +300 -0
- package/plugins/moderation-plugin/config.json +86 -0
- package/plugins/moderation-plugin/index.js +458 -0
- package/plugins/music-plugin/config.json +32 -0
- package/plugins/music-plugin/index.js +221 -0
- package/plugins/travel-plugin/index.js +230 -0
- package/src/ai-integration.js +185 -0
- package/src/client.js +41 -0
- package/src/http-client.js +276 -0
- package/src/index.js +6 -0
- package/src/message.js +127 -1
- package/src/plugin-manager-fixed.js +116 -0
- package/src/plugin-manager.js +105 -0
- package/src/scheduler.js +322 -0
- package/src/sticker-creator.js +413 -0
- package/src/storage.js +422 -0
package/src/scheduler.js
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
// Scheduler System für WAEngine
|
|
2
|
+
import cron from 'node-cron';
|
|
3
|
+
|
|
4
|
+
export class Scheduler {
|
|
5
|
+
constructor(client) {
|
|
6
|
+
this.client = client;
|
|
7
|
+
this.jobs = new Map();
|
|
8
|
+
this.storage = client.storage;
|
|
9
|
+
|
|
10
|
+
// Gespeicherte Jobs beim Start laden
|
|
11
|
+
this.loadScheduledJobs();
|
|
12
|
+
|
|
13
|
+
console.log('📅 Scheduler initialisiert');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// ===== CRON SCHEDULING =====
|
|
17
|
+
|
|
18
|
+
schedule(cronExpression, chatId, message, options = {}) {
|
|
19
|
+
const jobId = options.id || `job_${Date.now()}`;
|
|
20
|
+
|
|
21
|
+
if (!cron.validate(cronExpression)) {
|
|
22
|
+
throw new Error(`❌ Ungültiger Cron-Ausdruck: ${cronExpression}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const job = cron.schedule(cronExpression, async () => {
|
|
26
|
+
try {
|
|
27
|
+
await this.executeJob(chatId, message, options);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error(`❌ Scheduled Job Fehler (${jobId}):`, error);
|
|
30
|
+
}
|
|
31
|
+
}, {
|
|
32
|
+
scheduled: false,
|
|
33
|
+
timezone: options.timezone || 'Europe/Berlin'
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Job speichern
|
|
37
|
+
const jobData = {
|
|
38
|
+
id: jobId,
|
|
39
|
+
type: 'cron',
|
|
40
|
+
cronExpression,
|
|
41
|
+
chatId,
|
|
42
|
+
message,
|
|
43
|
+
options,
|
|
44
|
+
createdAt: new Date().toISOString(),
|
|
45
|
+
active: true
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
this.jobs.set(jobId, { job, data: jobData });
|
|
49
|
+
this.saveJob(jobData);
|
|
50
|
+
|
|
51
|
+
// Job starten
|
|
52
|
+
job.start();
|
|
53
|
+
|
|
54
|
+
console.log(`📅 Cron Job erstellt: ${jobId} (${cronExpression})`);
|
|
55
|
+
return jobId;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ===== ONE-TIME SCHEDULING =====
|
|
59
|
+
|
|
60
|
+
scheduleOnce(date, chatId, message, options = {}) {
|
|
61
|
+
const jobId = options.id || `once_${Date.now()}`;
|
|
62
|
+
const targetDate = new Date(date);
|
|
63
|
+
const now = new Date();
|
|
64
|
+
|
|
65
|
+
if (targetDate <= now) {
|
|
66
|
+
throw new Error('❌ Datum muss in der Zukunft liegen!');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const delay = targetDate - now;
|
|
70
|
+
|
|
71
|
+
const timeout = setTimeout(async () => {
|
|
72
|
+
try {
|
|
73
|
+
await this.executeJob(chatId, message, options);
|
|
74
|
+
this.removeJob(jobId); // Job nach Ausführung entfernen
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.error(`❌ Scheduled Job Fehler (${jobId}):`, error);
|
|
77
|
+
}
|
|
78
|
+
}, delay);
|
|
79
|
+
|
|
80
|
+
// Job speichern
|
|
81
|
+
const jobData = {
|
|
82
|
+
id: jobId,
|
|
83
|
+
type: 'once',
|
|
84
|
+
scheduledFor: targetDate.toISOString(),
|
|
85
|
+
chatId,
|
|
86
|
+
message,
|
|
87
|
+
options,
|
|
88
|
+
createdAt: new Date().toISOString(),
|
|
89
|
+
active: true
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
this.jobs.set(jobId, { timeout, data: jobData });
|
|
93
|
+
this.saveJob(jobData);
|
|
94
|
+
|
|
95
|
+
console.log(`📅 One-time Job erstellt: ${jobId} (${targetDate})`);
|
|
96
|
+
return jobId;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ===== CONVENIENCE METHODS =====
|
|
100
|
+
|
|
101
|
+
daily(time, chatId, message, options = {}) {
|
|
102
|
+
const [hour, minute] = time.split(':');
|
|
103
|
+
const cronExpression = `${minute || 0} ${hour} * * *`;
|
|
104
|
+
return this.schedule(cronExpression, chatId, message, { ...options, type: 'daily' });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
weekly(day, time, chatId, message, options = {}) {
|
|
108
|
+
const [hour, minute] = time.split(':');
|
|
109
|
+
const dayMap = {
|
|
110
|
+
'monday': 1, 'tuesday': 2, 'wednesday': 3, 'thursday': 4,
|
|
111
|
+
'friday': 5, 'saturday': 6, 'sunday': 0
|
|
112
|
+
};
|
|
113
|
+
const dayNum = dayMap[day.toLowerCase()] ?? day;
|
|
114
|
+
const cronExpression = `${minute || 0} ${hour} * * ${dayNum}`;
|
|
115
|
+
return this.schedule(cronExpression, chatId, message, { ...options, type: 'weekly' });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
monthly(day, time, chatId, message, options = {}) {
|
|
119
|
+
const [hour, minute] = time.split(':');
|
|
120
|
+
const cronExpression = `${minute || 0} ${hour} ${day} * *`;
|
|
121
|
+
return this.schedule(cronExpression, chatId, message, { ...options, type: 'monthly' });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ===== WAITING SYSTEM =====
|
|
125
|
+
|
|
126
|
+
createWaiting() {
|
|
127
|
+
return {
|
|
128
|
+
after: {
|
|
129
|
+
message: (ms) => {
|
|
130
|
+
return new Promise(resolve => {
|
|
131
|
+
setTimeout(resolve, ms);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ===== JOB EXECUTION =====
|
|
139
|
+
|
|
140
|
+
async executeJob(chatId, message, options = {}) {
|
|
141
|
+
try {
|
|
142
|
+
// Message kann String oder Function sein
|
|
143
|
+
let finalMessage = message;
|
|
144
|
+
|
|
145
|
+
if (typeof message === 'function') {
|
|
146
|
+
finalMessage = await message();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Template-Variablen ersetzen
|
|
150
|
+
if (typeof finalMessage === 'string') {
|
|
151
|
+
finalMessage = this.processTemplate(finalMessage);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Nachricht senden
|
|
155
|
+
await this.client.socket.sendMessage(chatId, { text: finalMessage });
|
|
156
|
+
|
|
157
|
+
console.log(`📅 Scheduled message sent to ${chatId}: ${finalMessage.substring(0, 50)}...`);
|
|
158
|
+
|
|
159
|
+
// Statistik speichern
|
|
160
|
+
this.storage.write.in("scheduler-stats").increment("totalExecuted", 1);
|
|
161
|
+
|
|
162
|
+
} catch (error) {
|
|
163
|
+
console.error('❌ Job Execution Fehler:', error);
|
|
164
|
+
throw error;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ===== TEMPLATE PROCESSING =====
|
|
169
|
+
|
|
170
|
+
processTemplate(text) {
|
|
171
|
+
const now = new Date();
|
|
172
|
+
|
|
173
|
+
return text
|
|
174
|
+
.replace('{time}', now.toLocaleTimeString('de-DE'))
|
|
175
|
+
.replace('{date}', now.toLocaleDateString('de-DE'))
|
|
176
|
+
.replace('{datetime}', now.toLocaleString('de-DE'))
|
|
177
|
+
.replace('{day}', now.toLocaleDateString('de-DE', { weekday: 'long' }))
|
|
178
|
+
.replace('{timestamp}', now.getTime());
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// ===== JOB MANAGEMENT =====
|
|
182
|
+
|
|
183
|
+
removeJob(jobId) {
|
|
184
|
+
const jobEntry = this.jobs.get(jobId);
|
|
185
|
+
|
|
186
|
+
if (!jobEntry) {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Job stoppen
|
|
191
|
+
if (jobEntry.job) {
|
|
192
|
+
jobEntry.job.stop();
|
|
193
|
+
} else if (jobEntry.timeout) {
|
|
194
|
+
clearTimeout(jobEntry.timeout);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Aus Memory und Storage entfernen
|
|
198
|
+
this.jobs.delete(jobId);
|
|
199
|
+
this.deleteJob(jobId);
|
|
200
|
+
|
|
201
|
+
console.log(`📅 Job entfernt: ${jobId}`);
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
pauseJob(jobId) {
|
|
206
|
+
const jobEntry = this.jobs.get(jobId);
|
|
207
|
+
|
|
208
|
+
if (jobEntry?.job) {
|
|
209
|
+
jobEntry.job.stop();
|
|
210
|
+
jobEntry.data.active = false;
|
|
211
|
+
this.saveJob(jobEntry.data);
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
resumeJob(jobId) {
|
|
219
|
+
const jobEntry = this.jobs.get(jobId);
|
|
220
|
+
|
|
221
|
+
if (jobEntry?.job) {
|
|
222
|
+
jobEntry.job.start();
|
|
223
|
+
jobEntry.data.active = true;
|
|
224
|
+
this.saveJob(jobEntry.data);
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// ===== STORAGE METHODS =====
|
|
232
|
+
|
|
233
|
+
saveJob(jobData) {
|
|
234
|
+
const jobs = this.storage.read.from("scheduled-jobs").all() || [];
|
|
235
|
+
const existingIndex = jobs.findIndex(job => job.id === jobData.id);
|
|
236
|
+
|
|
237
|
+
if (existingIndex >= 0) {
|
|
238
|
+
jobs[existingIndex] = jobData;
|
|
239
|
+
} else {
|
|
240
|
+
jobs.push(jobData);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
this.storage.write.in("scheduled-jobs").data(jobs);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
deleteJob(jobId) {
|
|
247
|
+
const jobs = this.storage.read.from("scheduled-jobs").all() || [];
|
|
248
|
+
const updatedJobs = jobs.filter(job => job.id !== jobId);
|
|
249
|
+
this.storage.write.in("scheduled-jobs").data(updatedJobs);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
loadScheduledJobs() {
|
|
253
|
+
const jobs = this.storage.read.from("scheduled-jobs").all() || [];
|
|
254
|
+
|
|
255
|
+
for (const jobData of jobs) {
|
|
256
|
+
try {
|
|
257
|
+
if (jobData.type === 'cron' && jobData.active) {
|
|
258
|
+
// Cron Jobs wieder starten
|
|
259
|
+
const job = cron.schedule(jobData.cronExpression, async () => {
|
|
260
|
+
await this.executeJob(jobData.chatId, jobData.message, jobData.options);
|
|
261
|
+
}, {
|
|
262
|
+
scheduled: true,
|
|
263
|
+
timezone: jobData.options.timezone || 'Europe/Berlin'
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
this.jobs.set(jobData.id, { job, data: jobData });
|
|
267
|
+
console.log(`📅 Cron Job wiederhergestellt: ${jobData.id}`);
|
|
268
|
+
|
|
269
|
+
} else if (jobData.type === 'once') {
|
|
270
|
+
// One-time Jobs prüfen ob noch gültig
|
|
271
|
+
const targetDate = new Date(jobData.scheduledFor);
|
|
272
|
+
const now = new Date();
|
|
273
|
+
|
|
274
|
+
if (targetDate > now) {
|
|
275
|
+
const delay = targetDate - now;
|
|
276
|
+
const timeout = setTimeout(async () => {
|
|
277
|
+
await this.executeJob(jobData.chatId, jobData.message, jobData.options);
|
|
278
|
+
this.removeJob(jobData.id);
|
|
279
|
+
}, delay);
|
|
280
|
+
|
|
281
|
+
this.jobs.set(jobData.id, { timeout, data: jobData });
|
|
282
|
+
console.log(`📅 One-time Job wiederhergestellt: ${jobData.id}`);
|
|
283
|
+
} else {
|
|
284
|
+
// Abgelaufene Jobs entfernen
|
|
285
|
+
this.deleteJob(jobData.id);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
} catch (error) {
|
|
289
|
+
console.error(`❌ Fehler beim Laden von Job ${jobData.id}:`, error);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// ===== STATISTICS =====
|
|
295
|
+
|
|
296
|
+
getStats() {
|
|
297
|
+
const jobs = Array.from(this.jobs.values());
|
|
298
|
+
const scheduledJobs = this.storage.read.from("scheduled-jobs").all() || [];
|
|
299
|
+
const stats = this.storage.read.from("scheduler-stats").all() || {};
|
|
300
|
+
|
|
301
|
+
return {
|
|
302
|
+
activeJobs: jobs.length,
|
|
303
|
+
totalJobs: scheduledJobs.length,
|
|
304
|
+
cronJobs: jobs.filter(j => j.data.type === 'cron').length,
|
|
305
|
+
onceJobs: jobs.filter(j => j.data.type === 'once').length,
|
|
306
|
+
totalExecuted: stats.totalExecuted || 0,
|
|
307
|
+
jobs: jobs.map(j => ({
|
|
308
|
+
id: j.data.id,
|
|
309
|
+
type: j.data.type,
|
|
310
|
+
chatId: j.data.chatId,
|
|
311
|
+
active: j.data.active,
|
|
312
|
+
createdAt: j.data.createdAt
|
|
313
|
+
}))
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// ===== JOB LISTING =====
|
|
318
|
+
|
|
319
|
+
listJobs() {
|
|
320
|
+
return Array.from(this.jobs.values()).map(jobEntry => jobEntry.data);
|
|
321
|
+
}
|
|
322
|
+
}
|