Parcourir la source

hunchentoot webserver. webhooks mode

Innocenty Enikeew il y a 9 ans
Parent
commit
f88b28f2ed
5 fichiers modifiés avec 63 ajouts et 6 suppressions
  1. 2 0
      chatikbot.asd
  2. 9 4
      chatikbot.lisp
  3. 17 2
      plugins/vk.lisp
  4. 32 0
      server.lisp
  5. 3 0
      telegram.lisp

+ 2 - 0
chatikbot.asd

@@ -12,6 +12,7 @@
                #:clss
                #:drakma
                #:flexi-streams
+               #:hunchentoot
                #:local-time
                #:log4cl
                #:plump
@@ -24,4 +25,5 @@
                (:file "utils")
                (:file "db")
                (:file "telegram")
+               (:file "server")
                (:file "chatikbot")))

+ 9 - 4
chatikbot.lisp

@@ -83,10 +83,15 @@
   ;; Run 'starting' hooks to set up schedules
   (run-hooks :starting)
 
-  ;; Start getUpdates thread
-  (bordeaux-threads:make-thread
-   (lambda () (loop-with-error-backoff #'process-updates))
-   :name "process-updates")
+  (if *web-path*
+      ;; If *web-path* is set, use webhooks
+      (telegram-set-webhook (format nil "~A/~A" *web-path* *telegram-token*))
+      ;; else start getUpdates thread
+      (progn
+        (telegram-set-webhook "") ;; Disable webhooks if present
+        (bordeaux-threads:make-thread
+         (lambda () (loop-with-error-backoff #'process-updates))
+         :name "process-updates")))
 
   ;; Notify admins
   (dolist (admin *admins*)

+ 17 - 2
plugins/vk.lisp

@@ -1,6 +1,21 @@
 (in-package #:chatikbot)
 
-(defparameter +vk-api-url+ "https://api.vk.com/method/~A?v=5.40" "VK.com API endpoint")
+(defparameter +vk-api-ver+ "5.53" "vk api version to use")
+(defparameter +vk-api-url+ "https://api.vk.com/method/~A?v=~A" "vk.com API endpoint")
+(defparameter +vk-oauth-authorize+ "https://oauth.vk.com/authorize" "vk.com OAuth authrization endpoint")
+(defsetting *vk-app-client-id* nil "vk app to authenticate against")
+(defsetting *vk-app-client-secret* nil "vk app secret")
+
+(defparameter +vk-scope-mapping+
+  '((:notify . 1) (:friends . 2) (:photos . 4) (:audio . 8) (:video . 16) (:docs . 131072) (:notes . 2048)
+    (:pages . 128) (:pages-left . 256) (:status . 1024) (:offers . 32) (:questions . 64) (:wall . 8192)
+    (:groups . 262144) (:messages . 4096) (:email . 4194304) (:notifications . 524288) (:stats . 1048576)
+    (:ads . 32768) (:market . 134217728) (:offline . 65536)))
+
+(defun vk-get-authorization-url (&optional state &rest scopes)
+  (let ((scope (apply #'+ (mapcar #'(lambda (k) (cdr (assoc k +vk-scope-mapping+))) scopes))))
+    (format nil "~A?v=~A&client_id=~A&redirect_uri=~A/oauth~@[&scope=~A~]~@[&state=~A~]"
+            +vk-oauth-authorize+ +vk-api-ver+ *vk-app-client-id* *web-path* (unless (zerop scope) scope) state)))
 
 (defun %vk-api-call (method &optional args)
   (handler-case
@@ -10,7 +25,7 @@
                           collect (cons
                                    (princ-to-string k)
                                    (princ-to-string v))))
-               (response (json-request (format nil +vk-api-url+ method)
+               (response (json-request (format nil +vk-api-url+ method +vk-api-ver+)
                                        :method :post
                                        :parameters params)))
           (when (aget "error" response)

+ 32 - 0
server.lisp

@@ -0,0 +1,32 @@
+(in-package #:chatikbot)
+
+(defvar *web-path* nil "Set to externally accessible url")
+(defvar *web-iface* nil "Interface to listen on")
+(defvar *web-port* 4242 "Port to listen on")
+
+(defvar *web-acceptor* nil "Running hunchentoot acceptor")
+
+(defun web-start ()
+  (when *web-acceptor* (hunchentoot:stop *web-acceptor*))
+  (when *web-path*
+    (setf *web-acceptor*
+          (hunchentoot:start
+           (make-instance 'hunchentoot:easy-acceptor
+                          :address *web-iface* :port *web-port*)))))
+(add-hook :starting #'(lambda () (web-start) (values)))
+
+(defun webhookp (request)
+  (equal (concatenate 'string "/" *telegram-token*)
+         (hunchentoot:script-name* request)))
+
+(hunchentoot:define-easy-handler (webhook-handler :uri #'webhookp :default-request-type :post) ()
+  (handler-case
+      (let ((stream (hunchentoot:raw-post-data :want-stream t)))
+        (setf (flex:flexi-stream-external-format stream) :utf-8)
+        (handle-update (yason:parse stream :object-as :alist)))
+    (error (e) (log:error e))))
+
+(hunchentoot:define-easy-handler (oauth-handler :uri "/oauth")
+    (code state error (error-description :real-name "error_description"))
+  (setf (hunchentoot:content-type*) "text/plain")
+  (format nil "Hey~@[ ~A~]~@[ ~A~]~@[ ~A~]~@[ ~A~]!" code state error error-description))

+ 3 - 0
telegram.lisp

@@ -34,6 +34,9 @@
 (defun telegram-get-me ()
   (%telegram-api-call "getMe"))
 
+(defun telegram-set-webhook (&optional url certificate)
+  (%telegram-api-call "setWebhook" (list (cons "url" url) (cons "certificate" certificate))))
+
 (defun telegram-send-message (chat-id text &key parse-mode disable-web-preview reply-to reply-markup)
   (%telegram-api-call
    "sendMessage"