|
|
@@ -0,0 +1,147 @@
|
|
|
+
|
|
|
+/**
|
|
|
+ * Cron Manager Plugin v1.1.0
|
|
|
+ * Schedules delayed tasks and sends results back to the original conversation.
|
|
|
+ */
|
|
|
+
|
|
|
+var JOBS_KEY = 'cron_jobs';
|
|
|
+
|
|
|
+// Initialize state with jobs from storage (if any)
|
|
|
+var storedJobs = shadowman.storage.get(JOBS_KEY);
|
|
|
+if (!storedJobs) storedJobs = [];
|
|
|
+shadowman.state.set(JOBS_KEY, storedJobs);
|
|
|
+
|
|
|
+// --- Tools ---
|
|
|
+
|
|
|
+shadowman.tools.register('schedule_job', function(args) {
|
|
|
+ var schedule = args.schedule;
|
|
|
+ var instructions = args.instructions;
|
|
|
+ var conversationId = args.conversationId;
|
|
|
+
|
|
|
+ var jobs = shadowman.state.get(JOBS_KEY) || [];
|
|
|
+ var jobId = 'job_' + Math.random().toString(36).substr(2, 9);
|
|
|
+
|
|
|
+ var triggerTime = null;
|
|
|
+ var intervalMs = null;
|
|
|
+
|
|
|
+ // Parser: number = minutes interval, string = ISO timestamp
|
|
|
+ if (!isNaN(schedule)) {
|
|
|
+ intervalMs = parseInt(schedule) * 60 * 1000;
|
|
|
+ } else {
|
|
|
+ var date = new Date(schedule);
|
|
|
+ if (!isNaN(date.getTime())) {
|
|
|
+ triggerTime = date.getTime();
|
|
|
+ } else {
|
|
|
+ return { error: "Invalid schedule format. Use an ISO timestamp or a number of minutes for intervals." };
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var job = {
|
|
|
+ id: jobId,
|
|
|
+ schedule: schedule,
|
|
|
+ instructions: instructions,
|
|
|
+ conversationId: conversationId,
|
|
|
+ triggerTime: triggerTime,
|
|
|
+ intervalMs: intervalMs,
|
|
|
+ lastRun: 0,
|
|
|
+ createdAt: Date.now()
|
|
|
+ };
|
|
|
+
|
|
|
+ jobs.push(job);
|
|
|
+ shadowman.storage.set(JOBS_KEY, jobs);
|
|
|
+ shadowman.state.set(JOBS_KEY, jobs);
|
|
|
+
|
|
|
+ return {
|
|
|
+ status: "success",
|
|
|
+ jobId: jobId,
|
|
|
+ message: "Job scheduled. It will trigger at " + schedule + " and notify conversation " + conversationId + "."
|
|
|
+ };
|
|
|
+});
|
|
|
+
|
|
|
+shadowman.tools.register('list_jobs', function() {
|
|
|
+ var jobs = shadowman.state.get(JOBS_KEY) || [];
|
|
|
+ return { jobs: jobs };
|
|
|
+});
|
|
|
+
|
|
|
+shadowman.tools.register('cancel_job', function(args) {
|
|
|
+ var jobId = args.jobId;
|
|
|
+ var jobs = shadowman.state.get(JOBS_KEY) || [];
|
|
|
+ var filtered = [];
|
|
|
+
|
|
|
+ for (var i = 0; i < jobs.length; i++) {
|
|
|
+ if (jobs[i].id !== jobId) {
|
|
|
+ filtered.push(jobs[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (jobs.length === filtered.length) {
|
|
|
+ return { error: "Job not found." };
|
|
|
+ }
|
|
|
+
|
|
|
+ shadowman.storage.set(JOBS_KEY, filtered);
|
|
|
+ shadowman.state.set(JOBS_KEY, filtered);
|
|
|
+ return { status: "success", message: "Job " + jobId + " cancelled." };
|
|
|
+});
|
|
|
+
|
|
|
+// --- Background Worker ---
|
|
|
+
|
|
|
+shadowman.background.run(function() {
|
|
|
+ var JOBS_KEY = 'cron_jobs';
|
|
|
+
|
|
|
+ shadowman.log.info("Cron Manager worker started");
|
|
|
+
|
|
|
+ while (true) {
|
|
|
+ try {
|
|
|
+ var jobs = shadowman.state.get(JOBS_KEY);
|
|
|
+
|
|
|
+ if (jobs && jobs.length > 0) {
|
|
|
+ var currentTime = Date.now();
|
|
|
+ var jobsToTrigger = [];
|
|
|
+ var jobsToRemove = [];
|
|
|
+
|
|
|
+ for (var i = 0; i < jobs.length; i++) {
|
|
|
+ var job = jobs[i];
|
|
|
+ if (job.triggerTime && currentTime >= job.triggerTime) {
|
|
|
+ jobsToTrigger.push(job);
|
|
|
+ jobsToRemove.push(job.id);
|
|
|
+ } else if (job.intervalMs && (currentTime - job.lastRun) >= job.intervalMs) {
|
|
|
+ jobsToTrigger.push(job);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (var i = 0; i < jobsToTrigger.length; i++) {
|
|
|
+ var job = jobsToTrigger[i];
|
|
|
+ shadowman.log.info("Triggering cron job " + job.id);
|
|
|
+
|
|
|
+ shadowman.events.emit('message', {
|
|
|
+ text: "⏰ **Cron Job Triggered**\n\n**Instructions:** " + job.instructions + "\n\n*This is an automated notification from Cron Manager.*",
|
|
|
+ conversationId: job.conversationId,
|
|
|
+ platform: 'CronManager',
|
|
|
+ sender: 'Cron Manager'
|
|
|
+ });
|
|
|
+
|
|
|
+ if (job.intervalMs) {
|
|
|
+ job.lastRun = currentTime;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (jobsToRemove.length > 0) {
|
|
|
+ var remainingJobs = [];
|
|
|
+ for (var i = 0; i < jobs.length; i++) {
|
|
|
+ if (jobsToRemove.indexOf(jobs[i].id) === -1) {
|
|
|
+ remainingJobs.push(jobs[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ shadowman.state.set(JOBS_KEY, remainingJobs);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ shadowman.utils.sleep(10000);
|
|
|
+ } catch (e) {
|
|
|
+ shadowman.log.error("Cron worker error: " + e.toString());
|
|
|
+ shadowman.utils.sleep(5000);
|
|
|
+ }
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+shadowman.log.info("Cron Manager plugin v1.1.0 ready");
|