|
|
@@ -0,0 +1,75 @@
|
|
|
+(in-package :cl-user)
|
|
|
+(defpackage chatikbot.poller
|
|
|
+ (:use :cl :chatikbot.utils)
|
|
|
+ (:export :*poller-token*
|
|
|
+ :*poller-module*
|
|
|
+ :filled
|
|
|
+ :rest-parameters
|
|
|
+
|
|
|
+ :poller-request
|
|
|
+ :poller-validate
|
|
|
+ :poller-authenticate
|
|
|
+
|
|
|
+ :poller-error
|
|
|
+ :poller-no-secret
|
|
|
+ :poller-cant-authenticate
|
|
|
+
|
|
|
+ :poller-call
|
|
|
+ :poller-poll-list))
|
|
|
+
|
|
|
+(defvar *tokens* (make-hash-table) "Module's tokens store")
|
|
|
+(defvar *state* (make-hash-table) "Module's state store")
|
|
|
+(defvar *poller-token* nil "Current user's API token")
|
|
|
+(defvar *poller-module* nil "Current module")
|
|
|
+
|
|
|
+(defun rest-parameters (rest)
|
|
|
+ (loop for (param value) on rest by #'cddr
|
|
|
+ when value collect (cons (dekeyify param) value)))
|
|
|
+
|
|
|
+(defun get-data (store chat-id &optional (module *poller-module*))
|
|
|
+ (let ((module-store (gethash module store)))
|
|
|
+ (when module-store (gethash chat-id module-store))))
|
|
|
+
|
|
|
+(defun set-data (store chat-id data &optional (module *poller-module*))
|
|
|
+ (let ((module-store (or (gethash module store)
|
|
|
+ (setf (gethash module store)
|
|
|
+ (make-hash-table)))))
|
|
|
+ (setf (gethash chat-id module-store) data)))
|
|
|
+
|
|
|
+(defgeneric poller-request (module method &rest params)
|
|
|
+ (:documentation "Performs api request to module"))
|
|
|
+(defgeneric poller-validate (module response)
|
|
|
+ (:documentation "Performs api result validation"))
|
|
|
+(defgeneric poller-authenticate (module secret)
|
|
|
+ (:documentation "Performs api request to module"))
|
|
|
+
|
|
|
+(define-condition poller-error (error) ())
|
|
|
+(define-condition poller-no-secret (poller-error) ())
|
|
|
+(define-condition poller-cant-authenticate (poller-error) ())
|
|
|
+
|
|
|
+(defun poller-call (module method &rest params)
|
|
|
+ (let* ((chat-id *chat-id*)
|
|
|
+ (*poller-module* module)
|
|
|
+ (*poller-token* (get-data *tokens* chat-id module))
|
|
|
+ (response (apply 'poller-request module method params)))
|
|
|
+ (if (poller-validate module response) response
|
|
|
+ (with-secret (secret (list module chat-id))
|
|
|
+ (unless secret (error 'polller-no-secret))
|
|
|
+ (let ((*poller-token* (poller-authenticate module secret)))
|
|
|
+ (unless *poller-token* (error 'poller-cant-authenticate))
|
|
|
+ (set-data *tokens* chat-id *poller-token* module)
|
|
|
+ (values (apply 'poller-request module method params)))))))
|
|
|
+
|
|
|
+(defun poller-poll-lists (module get-state-fn process-diff-fn &key (test #'equalp) (predicate #'<) key (max-store 200))
|
|
|
+ (dolist (*chat-id* (lists-get module))
|
|
|
+ (let* ((old (get-data *state* *chat-id* module))
|
|
|
+ (new (funcall get-state-fn))
|
|
|
+ (diff (sort (set-difference new old :test test)
|
|
|
+ predicate :key key)))
|
|
|
+ (when diff
|
|
|
+ (when old
|
|
|
+ (funcall process-diff-fn diff))
|
|
|
+ (let ((merged (merge 'list old diff predicate :key key)))
|
|
|
+ (set-data *state* *chat-id*
|
|
|
+ (subseq merged (max (- (length merged) max-store) 0))
|
|
|
+ module))))))
|