chat-cron.lisp 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. (in-package :cl-user)
  2. (defpackage chatikbot.chat-cron
  3. (:use :cl :chatikbot.utils :chatikbot.db
  4. :chatikbot.macros)
  5. (:export :add-chat-cron
  6. :get-chat-crons
  7. :delete-chat-cron
  8. :def-chat-cron-handler))
  9. (in-package :chatikbot.chat-cron)
  10. (def-db-init
  11. (db-execute "create table if not exists chat_crons (type, chat_id, schedule, args, last_run)"))
  12. (defun add-chat-cron (type chat-id schedule &rest args)
  13. (apply #'clon:make-typed-cron-schedule (read-from-string schedule)) ;; Validate schedule
  14. (db-execute "insert into chat_crons (type, chat_id, schedule, args) values (?, ?, ?, ?)"
  15. (symbol-name type) chat-id schedule (write-to-string args)))
  16. (defun get-chat-crons (type chat-id)
  17. (loop for (schedule args) in (db-select "select schedule, args from chat_crons where type = ? and chat_id = ?"
  18. (symbol-name type) chat-id)
  19. collect (append (list schedule) (read-from-string args))))
  20. (defun delete-chat-cron (type chat-id index)
  21. (let ((crons (db-select "select schedule, args from chat_crons where type = ? and chat_id = ?"
  22. (symbol-name type) chat-id)))
  23. (destructuring-bind (schedule args) (nth index crons)
  24. (db-execute "delete from chat_crons where type = ? and chat_id = ? and schedule = ? and args = ?"
  25. (symbol-name type) chat-id schedule args))))
  26. (defcron chat-crons-handler ()
  27. (let ((now (get-universal-time)))
  28. (loop
  29. for (type chat-id schedule-text args last-run) in (db-select "select type, chat_id, schedule, args, last_run from chat_crons")
  30. for schedule = (apply #'clon:make-typed-cron-schedule (read-from-string schedule-text))
  31. for next-time = (clon:next-time schedule :allow-now-p (not last-run) :now (or last-run now))
  32. when (and next-time (<= (same-time-in-chat next-time chat-id) now))
  33. do (unwind-protect
  34. (progn
  35. (log:info :chat-cron type chat-id schedule-text now next-time last-run)
  36. (apply #'run-hooks :chat-cron (keyify type) chat-id schedule (read-from-string args)))
  37. (db-execute "update chat_crons set last_run = ? where type = ? and chat_id = ? and schedule = ? and args = ?" next-time type chat-id schedule-text args)))))
  38. (defmacro def-chat-cron-handler (name (type &rest args) &body body)
  39. (let ((var-type (gensym "TYPE")))
  40. `(progn
  41. (defun ,name (,var-type ,@args)
  42. (declare (ignorable ,@args))
  43. (when (eql ,type ,var-type)
  44. ,@body))
  45. (add-hook :chat-cron ',name))))