Bläddra i källkod

[zsd] Poller framework

Innocenty Enikeew 6 år sedan
förälder
incheckning
857382a093
2 ändrade filer med 72 tillägg och 83 borttagningar
  1. 59 72
      plugins/zsd.lisp
  2. 13 11
      poller.lisp

+ 59 - 72
plugins/zsd.lisp

@@ -3,43 +3,39 @@
   (:use :cl :chatikbot.common))
 (in-package :chatikbot.plugins.zsd)
 
-(defparameter +zsd-api-url+ "https://mcabinet.nch-spb.com/onyma/system/api/json")
-(defparameter +zsd-auth-url+ "https://mcabinet.nch-spb.com/onyma/system/api/jsonex?function=open_session")
+(defparameter +api-uri+ "https://mcabinet.nch-spb.com/onyma/system/api/json")
+(defparameter +auth-uri+ "https://mcabinet.nch-spb.com/onyma/system/api/jsonex?function=open_session")
+(defparameter +method-prefix+ "onm_api_toll_api_")
 
-(defun %zsd/api (token method &optional args)
-  (let* ((f (concatenate 'string "onm_api_toll_api_" method))
-         (params (loop for (k . v) in args when v
-                    collect (cons (princ-to-string k) (princ-to-string v))))
-         (response
-          (json-request
-           +zsd-api-url+
-           :parameters (append params `(("function" . ,f)
-                                        ("auth_token" . ,token))))))
-    (values (aget "return" response) (aget "more_rows" response))))
+;; poller methods
+(defmethod poller-request ((module (eql :zsd)) method &rest params)
+  (agets (json-request +api-uri+
+                       :parameters (append
+                                    `(("function" . ,(concatenate 'string +method-prefix+ method))
+                                      ("auth_token" . ,*poller-token*))
+                                    (rest-parameters params)))
+         "return"))
+(defmethod poller-validate ((module (eql :zsd)) response)
+  response)
+(defmethod poller-authenticate ((module (eql :zsd)) secret)
+  (destructuring-bind (username . password) secret
+    (agets (json-request +auth-uri+ :method :post
+                         :content (plist-json (list :realm "WHSD"
+                                                    :user username
+                                                    :pass password)))
+           "return")))
 
-(defun zsd/auth (login password)
-  (aget "return"
-        (json-request +zsd-auth-url+ :method :post
-                      :content (plist-json (list :realm "WHSD"
-                                                 :user login
-                                                 :pass password)))))
+;; API
+(defun pan ()
+  (poller-call :zsd "mobile_pan"))
 
-(defun zsd/pan (token)
-  (%zsd/api token "mobile_pan"))
+(defun contract ()
+  (poller-call :zsd "contract_info"))
 
-(defun zsd/contract (token)
-  (%zsd/api token "contract_info"))
+(defun wall (&optional (offset 0) (limit 5))
+  (poller-call :zsd "mobile_wall" :rows-skip offset :rows-limit limit))
 
-(defun zsd/wall (token &optional (offset 0) (limit 5))
-  (%zsd/api token "mobile_wall"
-            `(("rows_skip" . ,offset) ("rows_limit" . ,limit))))
-
-(defun zsd/load-data (token &optional (limit 5))
-  `(("contract" . ,(zsd/contract token))
-    ("pan" . ,(zsd/pan token))
-    ("wall" . ,(zsd/wall token 0 limit))))
-
-(defun %zsd/format-wall (item pans)
+(defun format-wall (item pans)
   (let* ((pan (aget "pan" item))
          (alias (aget "alias" (find pan pans :test #'equal :key (lambda (el) (aget "pan" el)))))
          (event (parse-integer (aget "event_type" item)))
@@ -51,56 +47,47 @@
       (1 (format nil "~A *~aр.*: 🚗 ~a, _~a → ~a_" cdt amount (or alias pan) entry place))
       (101 (format nil "~A *~aр.*: 💶 _~a_" cdt amount place)))))
 
-(defun zsd/format-changes (old new)
-  (let ((wall-diff (set-difference (aget "wall" new) (aget "wall" old) :test #'equal)))
-    (when wall-diff
-      (format nil "ЗСД остаток: *~$р.*~%~%~{~A~^~%~}"
-              (parse-float (aget "remainder" (car (aget "contract" new))))
-              (loop for item in wall-diff
-                 collect (%zsd/format-wall item (aget "pan" new)))))))
+(defun format-changes (wall-diff contract pans)
+  (format nil "ЗСД остаток: *~$р.*~%~%~{~A~^~%~}"
+          (parse-float (aget "remainder" (car contract)))
+          (loop for item in wall-diff
+             collect (format-wall item pans))))
 
-(defun zsd/handle-set-cron (enable)
+(defcron process-zsd (:minute '(member 0 5 10 15 20 25 30 35 40 45 50 55))
+  (poller-poll-lists :zsd
+                     #'wall
+                     #'(lambda (diff)
+                         (bot-send-message (format-changes diff (contract) (pan))
+                                           :parse-mode "markdown"))
+                     :key #'(lambda (w) (local-time:timestamp-to-universal
+                                         (local-time:parse-timestring (aget "dt" w))))))
+
+(defun handle-set-cron (enable)
   (lists-set-entry :zsd *chat-id* enable)
   (bot-send-message (if enable
                         "Включил рассылку. '/zsd off' чтобы выключить, /zsd - показать последние."
                         "Без рассылки. '/zsd on' - включить, /zsd - последние.")))
 
-(defun zsd/handle-auth (login pass)
-  (let ((token (zsd/auth login pass)))
-    (if token
+(defun handle-auth (login pass)
+  (let ((secret (cons login pass)))
+    (if (poller-authenticate :zsd secret)
         (progn
-          (secret-set `(:zsd ,*chat-id*) token)
-          (zsd/handle-set-cron t))
+          (log:info secret *chat-id*)
+          (secret-set `(:zsd ,*chat-id*) secret)
+          (handle-set-cron t))
         (bot-send-message "Чот не смог, пропробуй другие."))))
 
-(defun zsd/handle-recent ()
-  (with-secret (token (list :zsd *chat-id*))
-    (bot-send-message (if token
-                          (let ((data (zsd/load-data token)))
-                            (if data
-                                (zsd/format-changes nil data)
-                                "Не смог получить данные. Попробуй перелогинься. /zsd <login> <pass>"))
-                          "Нужен логин-пароль. /zsd <login> <pass>")
-                      :parse-mode "markdown")))
+(defun handle-recent ()
+  (bot-send-message
+   (handler-case
+       (format-changes (wall) (contract) (pan))
+     (poller-error ()
+       "Нужен логин-пароль. /zsd <login> <pass>"))
+   :parse-mode "markdown"))
 
 (def-message-cmd-handler handle-cmd-zsd (:zsd)
   (cond
     ((= 1 (length *args*))
-     (zsd/handle-set-cron (equal "on" (car *args*))))
-    ((= 2 (length *args*)) (apply 'zsd/handle-auth *args*))
-    (:otherwise (zsd/handle-recent))))
-
-(defvar *zsd/last-results* (make-hash-table) "Last check results")
-(defcron process-zsd (:minute '(member 0 10 20 30 40 50))
-  (dolist (*chat-id* (lists-get :zsd))
-    (with-secret (token (list :zsd *chat-id*))
-      (if token
-          (let ((old (gethash *chat-id* *zsd/last-results*))
-                (new (zsd/load-data token)))
-            (when new
-              (when old
-                (alexandria:when-let ((changes (zsd/format-changes old new)))
-                  (bot-send-message changes :parse-mode "markdown")))
-              (setf (gethash *chat-id* *zsd/last-results*) new)))
-          (progn
-            (log:warn "zsd no token for" *chat-id*))))))
+     (handle-set-cron (equal "on" (car *args*))))
+    ((= 2 (length *args*)) (apply 'handle-auth *args*))
+    (:otherwise (handle-recent))))

+ 13 - 11
poller.lisp

@@ -62,14 +62,16 @@
 
 (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))))))
+    (handler-case
+        (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))))
+      (error (e) (log:error e)))))