| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172 |
- (in-package :cl-user)
- (defpackage chatikbot.inline
- (:use :cl :chatikbot.utils :chatikbot.telegram :chatikbot.crypto
- :chatikbot.macros)
- (:export :get-inline-keyboard
- :inline-button))
- (in-package :chatikbot.inline)
- (defstruct button callback created)
- (defparameter +max-id+ 2000000000 "Buttons store key range")
- (defparameter +max-tries+ 100 "Tries to find free store key")
- (defparameter +ttl+ (* 60 60 24 7) "Weekly TTL for buttons in store")
- (defvar *inline-buttons* (make-hash-table) "Hashtable storing button actions")
- (defvar *buttons-lock* (bt:make-recursive-lock "inline buttons lock"))
- (defun add-button (callback)
- (bt:with-recursive-lock-held (*buttons-lock*)
- (let ((id (loop for id = (random +max-id+) then (random +max-id+)
- for try from 1
- unless (gethash id *inline-buttons*)
- do (return id)
- when (> try +max-tries+)
- do (error "Can't get inline button id in ~A tries" try))))
- (setf (gethash id *inline-buttons*)
- (make-button :callback callback
- :created (get-universal-time)))
- id)))
- (defun prune-buttons ()
- (bt:with-recursive-lock-held (*buttons-lock*)
- (let ((now (get-universal-time)))
- (loop for id being the hash-keys in *inline-buttons* using (hash-value button)
- when (> (- now (button-created button))
- +ttl+)
- do (remhash id *inline-buttons*)))))
- (defcron process-prune-buttons ()
- (prune-buttons))
- (defmacro inline-button ((text) &body body)
- `(cons ,text
- (lambda (callback)
- (with-parsed-callback callback
- (handler-case (progn ,@body)
- (error (e)
- (log:error "~A" e)
- (telegram-answer-callback-query
- query-id
- :text (format nil "Ошибочка вышла~@[: ~A~]"
- (when (member source-chat-id *admins*) e)))))))))
- (defun get-inline-keyboard (chat-id buttons)
- (telegram-inline-keyboard-markup
- (loop for row in buttons
- when row
- collect (loop for (text . callback) in row
- when text
- collect (list
- :text text
- :callback-data
- (encode-callback-data
- chat-id :inline (add-button callback) +ttl+))))))
- (def-callback-section-handler cb-handle-inline (:inline)
- (let ((button (gethash (parse-integer data) *inline-buttons*)))
- (if button
- (funcall (button-callback button) callback)
- (progn
- (log:error "Can't find button id ~A" data)
- (telegram-answer-callback-query query-id :text "Ошибка")))))
|