aboutsummaryrefslogtreecommitdiff
path: root/modules/ext/cron.js
blob: 5ed5ff6e84119c4249fb8d6b296586c0dd705a8e (plain)
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
class CronModule {
    constructor() {
        this.commands = {};
        this.terminal = null;
        this.jobs = {};
        this.counter = 0;
        this.MIN_INTERVAL = 5;
        this.STORAGE_KEY = 'webx11_cron_jobs';
        this._restoreJobs();
    }
    requirements() {
        return { met: true, missing: [] };
    }
    getHelpInfo() {
        return {
            'cron-every': 'cron-every <seconds> <command> — Schedule a command to run every N seconds',
            'cron-list': 'cron-list — List all active cron jobs',
            'cron-stop': 'cron-stop <id> — Stop a specific cron job',
            'cron-clear': 'cron-clear — Stop all cron jobs'
        };
    }
    registerCommands() {
        this.commands['cron-every'] = (args) => this.every(args);
        this.commands['cron-list'] = () => this.list();
        this.commands['cron-stop'] = (args) => this.stop(args);
        this.commands['cron-clear'] = () => this.clear();
    }
    _restoreJobs() {
        try {
            const saved = localStorage.getItem(this.STORAGE_KEY);
            if (!saved) return;
            const data = JSON.parse(saved);
            if (!Array.isArray(data) || data.length === 0) return;
            let maxId = 0;
            data.forEach(j => {
                if (j.id > maxId) maxId = j.id;
                if (this.counter < j.id) this.counter = j.id;
                this.jobs[j.id] = {
                    cmd: j.cmd,
                    interval: j.interval,
                    runs: j.runs || 0,
                    timer: setInterval(() => {
                        if (!this.jobs[j.id]) return;
                        this.jobs[j.id].runs++;
                        this.terminal.print(`[cron #${j.id}] Running: ${j.cmd}`, 'info');
                        this.terminal.executeCommand(j.cmd);
                    }, j.interval)
                };
            });
            this.counter = maxId;
            if (data.length > 0) this.terminal.print(`↻ Restored ${data.length} cron job(s) from storage`, 'info');
        } catch (e) { /* silently ignore corrupt data */ }
    }
    _saveJobs() {
        try {
            const data = Object.entries(this.jobs).map(([id, j]) => ({
                id: parseInt(id),
                cmd: j.cmd,
                interval: j.interval,
                runs: j.runs
            }));
            localStorage.setItem(this.STORAGE_KEY, JSON.stringify(data));
        } catch (e) { /* quota exceeded */ }
    }
    every(args) {
        if (args.length < 2) return this.terminal.print('Usage: cron-every <seconds> <command>', 'warning');
        const secs = parseInt(args[0]);
        if (isNaN(secs) || secs < this.MIN_INTERVAL) return this.terminal.print(`Interval must be >= ${this.MIN_INTERVAL} seconds`, 'warning');
        const cmd = args.slice(1).join(' ');
        this.counter++;
        const id = this.counter;
        this.jobs[id] = {
            cmd, interval: secs * 1000, runs: 0,
            timer: setInterval(() => {
                this.jobs[id].runs++;
                this.terminal.print(`[cron #${id}] Running: ${cmd}`, 'info');
                this.terminal.executeCommand(cmd);
            }, secs * 1000)
        };
        this._saveJobs();
        this.terminal.print(`Cron job #${id} started: "${cmd}" every ${secs}s`, 'success');
    }
    list() {
        const ids = Object.keys(this.jobs);
        if (ids.length === 0) return this.terminal.print('No active cron jobs', 'info');
        this.terminal.print('=== Cron Jobs ===', 'info');
        ids.forEach(id => {
            const j = this.jobs[id];
            this.terminal.print(`  #${id}: "${j.cmd}" every ${j.interval / 1000}s (${j.runs} runs)`);
        });
    }
    stop(args) {
        if (!args[0]) return this.terminal.print('Usage: cron-stop <id>', 'warning');
        const id = parseInt(args[0]);
        if (!this.jobs[id]) return this.terminal.print(`Cron job #${id} not found`, 'error');
        clearInterval(this.jobs[id].timer);
        delete this.jobs[id];
        this._saveJobs();
        this.terminal.print(`Cron job #${id} stopped`, 'success');
    }
    clear() {
        Object.keys(this.jobs).forEach(id => { clearInterval(this.jobs[id].timer); });
        this.jobs = {};
        localStorage.removeItem(this.STORAGE_KEY);
        this.terminal.print('All cron jobs stopped', 'success');
    }
}
if (typeof window.webx11 !== 'undefined' && window.webx11) {
    webx11.moduleManager.registerModule(new CronModule(), 'https://webx11.duckdns.org/spaces/newos4/modules/ext/cron.js');
}