macros.lisp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. (in-package :cl-user)
  2. (defpackage chatikbot.macros
  3. (:use :cl :chatikbot.utils :chatikbot.telegram :chatikbot.crypto)
  4. (:export :def-db-init
  5. :with-parsed-message
  6. :def-message-handler
  7. :def-message-cmd-handler
  8. :def-message-admin-cmd-handler
  9. :with-parsed-callback
  10. :def-callback-handler
  11. :def-callback-section-handler
  12. :def-oauth-handler
  13. :def-oauth-section-handler
  14. :defcron))
  15. (in-package #:chatikbot.macros)
  16. (defmacro def-db-init (&body body)
  17. `(add-hook :db-init #'(lambda ()
  18. (handler-case (progn ,@body)
  19. (error (e) (log:error e)))
  20. (values))))
  21. (defmacro with-parsed-message (message &body body)
  22. `(let ((message-id (agets ,message "message_id"))
  23. (from-id (agets ,message "from" "id"))
  24. (chat-id (agets ,message "chat" "id"))
  25. (text (agets ,message "text")))
  26. (declare (ignorable message-id from-id chat-id text))
  27. ,@body))
  28. (defmacro def-message-handler (name (message &optional prio) &body body)
  29. `(progn
  30. (defun ,name (,message)
  31. (with-parsed-message ,message
  32. (handler-case (progn ,@body)
  33. (error (e)
  34. (log:error "~A" e)
  35. (bot-send-message chat-id
  36. (format nil "Ошибочка вышла~@[: ~A~]"
  37. (when (member chat-id *admins*) e)))))))
  38. (when ,prio (setf (get ',name :prio) ,prio))
  39. (add-hook :update-message ',name)))
  40. (defmacro def-message-cmd-handler (name (&rest commands) &body body)
  41. `(def-message-handler ,name (message)
  42. (when (and text (equal #\/ (char text 0)))
  43. (multiple-value-bind (cmd args) (parse-cmd text)
  44. (when (member cmd (list ,@commands))
  45. (log:info cmd message-id chat-id from-id args)
  46. ,@body
  47. t)))))
  48. (defmacro def-message-admin-cmd-handler (name (&rest commands) &body body)
  49. `(def-message-handler ,name (message)
  50. (when (and (member chat-id *admins*)
  51. text (equal #\/ (char text 0)))
  52. (multiple-value-bind (cmd args) (parse-cmd text)
  53. (when (member cmd (list ,@commands))
  54. (log:info cmd message-id chat-id from-id args)
  55. ,@body
  56. t)))))
  57. (defmacro with-parsed-callback (callback &body body)
  58. `(let* ((query-id (agets ,callback "id"))
  59. (from (agets ,callback "from"))
  60. (raw-data (agets ,callback "data"))
  61. (source-message (agets ,callback "message"))
  62. (inline-message-id (agets ,callback "inline_message_id"))
  63. (from-id (agets from "id"))
  64. (source-chat-id (agets source-message "chat" "id"))
  65. (source-message-id (agets source-message "message_id")))
  66. (declare (ignorable query-id from raw-data source-message inline-message-id
  67. from-id source-chat-id source-message-id))
  68. ,@body))
  69. (defmacro def-callback-handler (name (callback &optional prio) &body body)
  70. `(progn
  71. (defun ,name (,callback)
  72. (with-parsed-callback ,callback
  73. (handler-case (progn ,@body)
  74. (error (e)
  75. (log:error "~A" e)
  76. (bot-send-message (or source-chat-id from-id)
  77. (format nil "Ошибочка вышла~@[: ~A~]"
  78. (when (member source-chat-id *admins*) e)))))))
  79. (when ,prio (setf (get ',name :prio) ,prio))
  80. (add-hook :update-callback-query ',name)))
  81. (defmacro def-callback-section-handler (name (&rest sections) &body body)
  82. `(def-callback-handler ,name (callback)
  83. (when source-chat-id
  84. (multiple-value-bind (data section) (decode-callback-data source-chat-id raw-data)
  85. (when (member section (list ,@sections))
  86. (log:info query-id from-id source-chat-id source-message-id section data)
  87. ,@body
  88. t)))))
  89. (defmacro def-oauth-handler (name (code error state &optional prio) &body body)
  90. `(progn
  91. (defun ,name (,code ,error ,state)
  92. (declare (ignorable ,code ,error ,state))
  93. (handler-case (progn ,@body)
  94. (error (e)
  95. (log:error "~A" e)
  96. (hunchentoot:redirect "/error"))))
  97. (when ,prio (setf (get ',name :prio) ,prio))
  98. (add-hook :oauth ',name)))
  99. (defmacro def-oauth-section-handler (name (&rest sections) &body body)
  100. `(def-oauth-handler ,name (code error raw-state)
  101. (multiple-value-bind (state section) (decode-oauth-state raw-state)
  102. (when (member section (list ,@sections))
  103. ,@body
  104. t))))
  105. ;; Schedule
  106. (defmacro defcron (name (&rest schedule) &body body)
  107. (let ((schedule (or schedule '(:minute '* :hour '*)))
  108. (scheduler (symbol-append name '-scheduler)))
  109. `(progn
  110. (defun ,name ()
  111. (unwind-protect
  112. (handler-case (progn ,@body)
  113. (error (e) (log:error "~A" e)))
  114. (dex:clear-connection-pool)))
  115. (defun ,scheduler ()
  116. (clon:schedule-function
  117. ',name (clon:make-scheduler
  118. (clon:make-typed-cron-schedule
  119. ,@schedule)
  120. :allow-now-p t)
  121. :name ',name :thread t)
  122. (values))
  123. (add-hook :starting ',scheduler))))