1: <?php
2:
3: namespace Budabot\User\Modules;
4:
5: use stdClass;
6: use Exception;
7: use Budabot\Core\Registry;
8:
9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29:
30: class TimerController {
31:
32: 33: 34: 35:
36: public $moduleName;
37:
38:
39: public $db;
40:
41:
42: public $chatBot;
43:
44:
45: public $accessManager;
46:
47:
48: public $text;
49:
50:
51: public $util;
52:
53:
54: public $settingManager;
55:
56:
57: public $setting;
58:
59:
60: public $logger;
61:
62: private $timers = array();
63:
64: 65: 66:
67: public function setup() {
68: $this->db->loadSQLFile($this->moduleName, 'timers');
69:
70: $this->timers = array();
71: $data = $this->db->query("SELECT * FROM timers_<myname>");
72: forEach ($data as $row) {
73: $row->alerts = json_decode($row->alerts);
74:
75:
76:
77: while (count($row->alerts) > 1 && $row->alerts[0]->time <= time()) {
78: array_shift($row->alerts);
79: }
80:
81: $this->timers[strtolower($row->name)] = $row;
82: }
83:
84: $this->settingManager->add($this->moduleName, 'timer_alert_times', 'Times to display timer alerts', 'edit', 'text', '1h 15m 1m', '1h 15m 1m', '', 'mod', 'timer_alert_times.txt');
85: $this->settingManager->registerChangeListener('timer_alert_times', array($this, 'changeTimerAlertTimes'));
86: }
87:
88: public function changeTimerAlertTimes($settingName, $oldValue, $newValue, $data) {
89: $alertTimes = array_reverse(explode(' ', $newValue));
90: $oldTime = 0;
91: forEach ($alertTimes as $alertTime) {
92: $time = $this->util->parseTime($alertTime);
93: if ($time == 0) {
94:
95: throw new Exception("Error saving setting: invalid alert time('$alertTime'). For more info type !help timer_alert_times.");
96: } else if ($time <= $oldTime) {
97:
98: throw new Exception("Error saving setting: invalid alert order('$alertTime'). For more info type !help timer_alert_times.");
99: }
100: $oldTime = $time;
101: }
102: }
103:
104: 105: 106: 107:
108: public function checkTimers() {
109:
110: if (count($this->timers) == 0) {
111: return;
112: }
113:
114: $time = time();
115:
116: forEach ($this->timers as $timer) {
117: if (count($timer->alerts) == 0) {
118: $this->remove($timer->name);
119: continue;
120: }
121:
122: forEach($timer->alerts as $alert) {
123: if ($alert->time > $time) {
124: break;
125: }
126:
127: array_shift($timer->alerts);
128:
129: list($name, $method) = explode(".", $timer->callback);
130: $instance = Registry::getInstance($name);
131: if ($instance === null) {
132: $this->logger->log('ERROR', "Error calling callback method '$timer->callback' for timer '$timer->name': Could not find instance '$name'.");
133: } else {
134: try {
135: $instance->$method($timer, $alert);
136: } catch (Exception $e) {
137: $this->logger->log("ERROR", "Error calling callback method '$timer->callback' for timer '$timer->name': " . $e->getMessage(), $e);
138: }
139: }
140: }
141: }
142: }
143:
144: public function timerCallback($timer, $alert) {
145: $this->sendAlertMessage($timer, $alert);
146: }
147:
148: public function repeatingTimerCallback($timer, $alert) {
149: $this->sendAlertMessage($timer, $alert);
150:
151: if (count($timer->alerts) == 0) {
152: $endTime = $timer->data + $alert->time;
153: $alerts = $this->generateAlerts($timer->owner, $timer->name, $endTime, explode(' ', $this->setting->timer_alert_times));
154: $this->add($timer->name, $timer->owner, $timer->mode, $alerts, $timer->callback, $timer->data);
155: }
156: }
157:
158: public function sendAlertMessage($timer, $alert) {
159: $msg = $alert->message;
160: $mode = $timer->mode;
161: if ('priv' == $mode) {
162: $this->chatBot->sendPrivate($msg);
163: } else if ('guild' == $mode) {
164: $this->chatBot->sendGuild($msg);
165: } else {
166: $this->chatBot->sendTell($msg, $timer->owner);
167: }
168: }
169:
170: 171: 172: 173: 174: 175:
176: public function rtimerCommand($message, $channel, $sender, $sendto, $args) {
177: $initialTimeString = $args[2];
178: $timeString = $args[3];
179: $timerName = $args[4];
180:
181: $timer = $this->get($timerName);
182: if ($timer != null) {
183: $msg = "A timer with the name <highlight>$timerName<end> is already running.";
184: $sendto->reply($msg);
185: return;
186: }
187:
188: $initialRunTime = $this->util->parseTime($initialTimeString);
189: $runTime = $this->util->parseTime($timeString);
190:
191: if ($runTime < 1) {
192: $msg = "You must enter a valid time parameter for the run time.";
193: $sendto->reply($msg);
194: return;
195: }
196:
197: if ($initialRunTime < 1) {
198: $msg = "You must enter a valid time parameter for the initial run time.";
199: $sendto->reply($msg);
200: return;
201: }
202:
203: $endTime = time() + $initialRunTime;
204:
205: $alerts = $this->generateAlerts($sender, $timerName, $endTime, explode(' ', $this->setting->timer_alert_times));
206:
207: $this->add($timerName, $sender, $channel, $alerts, "timercontroller.repeatingTimerCallback", $runTime);
208:
209: $initialTimerSet = $this->util->unixtimeToReadable($initialRunTime);
210: $timerSet = $this->util->unixtimeToReadable($runTime);
211: $msg = "Repeating timer <highlight>$timerName<end> will go off in $initialTimerSet and repeat every $timerSet.";
212:
213: $sendto->reply($msg);
214: }
215:
216: 217: 218: 219:
220: public function timersViewCommand($message, $channel, $sender, $sendto, $args) {
221: $name = strtolower($args[1]);
222: $timer = $this->get($name);
223: if ($timer == null) {
224: $msg = "Could not find timer named <highlight>$name<end>.";
225: } else {
226: $time_left = $this->util->unixtimeToReadable($timer->endtime - time());
227: $name = $timer->name;
228:
229: $msg = "Timer <highlight>$name<end> has <highlight>$time_left<end> left.";
230: }
231: $sendto->reply($msg);
232: }
233:
234: 235: 236: 237:
238: public function timersRemoveCommand($message, $channel, $sender, $sendto, $args) {
239: $name = strtolower($args[2]);
240: $timer = $this->get($name);
241: if ($timer == null) {
242: $msg = "Could not find a timer named <highlight>$name<end>.";
243: } else if ($timer->owner != $sender && !$this->accessManager->checkAccess($sender, "mod")) {
244: $msg = "You must own this timer or have moderator access in order to remove it.";
245: } else {
246: $this->remove($name);
247: $msg = "Removed timer <highlight>$timer->name<end>.";
248: }
249: $sendto->reply($msg);
250: }
251:
252: 253: 254: 255: 256:
257: public function timersAddCommand($message, $channel, $sender, $sendto, $args) {
258: if (count($args) == 3) {
259: $timeString = $args[2];
260: $name = $sender;
261: } else {
262: $timeString = $args[2];
263: $name = $args[3];
264: }
265:
266: if (preg_match("/^\\d+$/", $timeString)) {
267: $runTime = $args[2] * 60;
268: } else {
269: $runTime = $this->util->parseTime($timeString);
270: }
271:
272: $msg = $this->addTimer($sender, $name, $runTime, $channel);
273: $sendto->reply($msg);
274: }
275:
276: 277: 278: 279:
280: public function timersListCommand($message, $channel, $sender, $sendto, $args) {
281: $timers = $this->getAllTimers();
282: $count = count($timers);
283: if ($count == 0) {
284: $msg = "No timers currently running.";
285: } else {
286: $blob = '';
287: forEach ($timers as $timer) {
288: $time_left = $this->util->unixtimeToReadable($timer->endtime - time());
289: $name = $timer->name;
290: $owner = $timer->owner;
291:
292: $remove_link = $this->text->makeChatcmd("Remove", "/tell <myname> timers rem $name");
293:
294: $repeatingInfo = '';
295: if ($timer->callback == 'timercontroller.repeatingTimerCallback') {
296: $repeatingTimeString = $this->util->unixtimeToReadable($timer->data);
297: $repeatingInfo = " (Repeats every $repeatingTimeString)";
298: }
299:
300: $blob .= "Name: <highlight>$name<end> {$remove_link}\n";
301: $blob .= "Time left: <highlight>$time_left<end> $repeatingInfo\n";
302: $blob .= "Set by: <highlight>$owner<end>\n\n";
303: }
304: $msg = $this->text->makeBlob("Timers ($count)", $blob);
305: }
306: $sendto->reply($msg);
307: }
308:
309: public function generateAlerts($sender, $name, $endTime, $alertTimes) {
310: $alerts = array();
311:
312: forEach ($alertTimes as $alertTime) {
313: $time = $this->util->parseTime($alertTime);
314: $timeString = $this->util->unixtimeToReadable($time);
315: if ($endTime - $time > time()) {
316: $alert = new stdClass;
317: $alert->message = "Reminder: Timer <highlight>$name<end> has <highlight>$timeString<end> left. [set by <highlight>$sender<end>]";
318: $alert->time = $endTime - $time;
319: $alerts []= $alert;
320: }
321: }
322:
323: if ($endTime > time()) {
324: $alert = new stdClass;
325: if ($name == $sender) {
326: $alert->message = "<highlight>$sender<end> your timer has gone off.";
327: } else {
328: $alert->message = "<highlight>$sender<end> your timer named <highlight>$name<end> has gone off.";
329: }
330: $alert->time = $endTime;
331: $alerts []= $alert;
332: }
333:
334: return $alerts;
335: }
336:
337: public function addTimer($sender, $name, $runTime, $channel, $alerts = null) {
338: if ($name == '') {
339: return;
340: }
341:
342: if ($this->get($name) != null) {
343: return "A timer named <highlight>$name<end> is already running.";
344: }
345:
346: if ($runTime < 1) {
347: return "You must enter a valid time parameter.";
348: }
349:
350: if (strlen($name) > 255) {
351: return "You cannot use timer names longer than 255 characters.";
352: }
353:
354: $endTime = time() + $runTime;
355:
356: if ($alerts === null) {
357: $alerts = $this->generateAlerts($sender, $name, $endTime, explode(' ', $this->setting->timer_alert_times));
358: }
359:
360: $this->add($name, $sender, $channel, $alerts, 'timercontroller.timerCallback');
361:
362: $timerset = $this->util->unixtimeToReadable($runTime);
363: return "Timer <highlight>$name<end> has been set for $timerset.";
364: }
365:
366: public function add($name, $owner, $mode, $alerts, $callback, $data = null) {
367: usort($alerts, function($a, $b) {
368: return $a->time - $b->time;
369: });
370:
371: $timer = new stdClass;
372: $timer->name = $name;
373: $timer->owner = $owner;
374: $timer->mode = $mode;
375: $timer->endtime = end($alerts)->time;
376: $timer->settime = time();
377: $timer->callback = $callback;
378: $timer->data = $data;
379: $timer->alerts = $alerts;
380:
381: $this->timers[strtolower($name)] = $timer;
382:
383: $sql = "INSERT INTO timers_<myname> (`name`, `owner`, `mode`, `endtime`, `settime`, `callback`, `data`, alerts) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
384: $this->db->exec($sql, $name, $owner, $mode, $timer->endtime, $timer->settime, $callback, $data, json_encode($alerts));
385: }
386:
387: public function remove($name) {
388: $this->db->exec("DELETE FROM timers_<myname> WHERE `name` LIKE ?", $name);
389: unset($this->timers[strtolower($name)]);
390: }
391:
392: public function get($name) {
393: return $this->timers[strtolower($name)];
394: }
395:
396: public function getAllTimers() {
397: return $this->timers;
398: }
399: }
400: