chat-cron.lisp 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  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 t :now (or last-run now))
  32. when (and next-time (<= next-time now))
  33. do (unwind-protect
  34. (apply #'run-hooks :chat-cron (keyify type) chat-id schedule (read-from-string args))
  35. (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)))))
  36. (defmacro def-chat-cron-handler (name (type &rest args) &body body)
  37. (let ((var-type (gensym "TYPE")))
  38. `(progn
  39. (defun ,name (,var-type ,@args)
  40. (declare (ignorable ,@args))
  41. (when (eql ,type ,var-type)
  42. ,@body))
  43. (add-hook :chat-cron ',name))))