diff options
author | thegoofist <49315797+thegoofist@users.noreply.github.com> | 2019-10-04 13:35:43 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-10-04 13:35:43 -0500 |
commit | 1fa9a1fc8cef784680bea4336f4ba4bed6185235 (patch) | |
tree | 8dc4ca0b56266672cc2e826a3c218c2911849e2e | |
parent | e5b24b5eac031b68712c75b463a0e138b617b02d (diff) | |
parent | 58f698906747f5285ce6f6344eea96e05a6931a6 (diff) |
Merge pull request #10 from thegoofist/room-event-id
Clean: *room-id* special var refactoring handle-event generic
-rw-r--r-- | README.org | 18 | ||||
-rw-r--r-- | examples/roshambot.lisp | 35 | ||||
-rw-r--r-- | granolin.lisp | 46 | ||||
-rw-r--r-- | package.lisp | 2 | ||||
-rw-r--r-- | utility-apps.lisp | 40 |
5 files changed, 72 insertions, 69 deletions
diff --git a/README.org b/README.org new file mode 100644 index 0000000..0c5c20d --- /dev/null +++ b/README.org @@ -0,0 +1,18 @@ +* Granolin + +Build better bots, for matrix! + +* Event Handlers +** Special Variables +*** *room-id* + +The special variable =*room-id*= is available in your =handle-event= methods. +It will have the value of the Matrix room id in which the event occured. It +will be =nil= if the event is not a room state nor timeline/message event. + +For example: + +#+begin_src common-lisp +(defmethod handle-event :after ((cli echo-bot) (ev text-message-event)) + (send-text-message cli *room-id* (msg-body ev))) +#+end_src diff --git a/examples/roshambot.lisp b/examples/roshambot.lisp index 1062302..48ed49d 100644 --- a/examples/roshambot.lisp +++ b/examples/roshambot.lisp @@ -4,12 +4,6 @@ (defpackage #:roshambot (:use :cl :granolin)) - ;; (:import-from :granolin - ;; :handle-event - ;; :find-contact - ;; :text-message-event - ;; :send-text-message - ;; :let-cond)) (in-package :roshambot) @@ -58,14 +52,14 @@ (defun roshambo-move!? (str) (nth-value 0 (ppcre:scan-to-strings +roshambo-move-regex+ str))) -(defmethod handle-event :after ((bot roshambot) (event text-message-event) &optional room-id) +(defmethod handle-event :after ((bot roshambot) (event text-message-event)) (let ((text (granolin:msg-body event))) (let-cond (challenged (you-wanna-piece-of-this!? text) - (handle-new-challenge bot room-id (granolin:sender event) challenged)) - (roshambo-match (challenger-made-move!? bot room-id (granolin::sender event) text) + (handle-new-challenge bot *room-id* (granolin:sender event) challenged)) + (roshambo-match (challenger-made-move!? bot *room-id* (granolin::sender event) text) (handle-match-state-change bot roshambo-match)) - (roshambo-match (challenged-made-move!? bot room-id (granolin::sender event) text) + (roshambo-match (challenged-made-move!? bot *room-id* (granolin::sender event) text) (handle-match-state-change bot roshambo-match))))) (defun challenger-made-move!? (bot room-id sender text) @@ -207,19 +201,14 @@ (defclass roshambo-bot (granolin:client granolin:server-directory roshambot auto-joiner) ()) -;; (defmethod handle-event :after ((bot roshambot-bot) (ev timeline-event) &optional room-id) -;; (format t "~a - ~a:~% ~a~%" room-id (granolin::sender ev) (granolin:msg-body ev))) +(defmethod handle-event :after ((bot roshambo-bot) (ev text-message-event)) + (format t "~a - ~a:~% ~a~%" *room-id* (granolin::sender ev) (granolin:msg-body ev))) -(defmethod handle-event :after ((bot roshambo-bot) (ev text-message-event) &optional room-id) - (format t "~a - ~a:~% ~a~%" room-id (granolin::sender ev) (granolin:msg-body ev))) - -(defmethod handle-event :after ((bot roshambo-bot) - (ev granolin::account-data-event) - &optional room-id) +(defmethod handle-event :after ((bot roshambo-bot) (ev granolin::account-data-event)) (format t "~a ~a" (event-type ev) (event-content ev))) - -(defvar *roshambot* (make-instance 'roshambo-bot - :homeserver "https://matrix.hrlo.world")) - - +;; creates and authenticates the bot, returns the bot instance +(defun roshambot (homeserver user password) + (let ((bot (make-instance 'roshambo-bot :homeserver homeserver))) + (login bot user password) + bot)) diff --git a/granolin.lisp b/granolin.lisp index 76e7441..0460ac2 100644 --- a/granolin.lisp +++ b/granolin.lisp @@ -16,7 +16,6 @@ (incf id-source) (format nil "~a" id-source))) - ;;; The main matrix client class (defclass client (id-source) @@ -24,7 +23,8 @@ :reader homeserver :initarg :homeserver :initform (error "HOMESERVER is required.") - :type string) + :type string + :documentation "The hostname this client connects to.") (user-id :accessor user-id :initarg :user-id @@ -53,7 +53,11 @@ :accessor next-batch :initform nil :type string - :documentation "Used on sync requests as the value of the SINCE parameter")) + :documentation "Used on sync requests as the value of the SINCE parameter") + (ssl + :reader ssl + :initform T + :documentation "Set to nil to use http protocol.")) (:documentation "An instance of CLIENT holds the necessary state for interacting with a Matrix server. If HARDCOPY is supplied, the INITIALIZE-INSTANCE :after auxilliary method will attempt to populate the @@ -101,9 +105,9 @@ (when (and (hardcopy client) (probe-file (hardcopy client))) (load-client-state client))) -(defgeneric handle-event (client event &optional room-id) +(defgeneric handle-event (client event) (:documentation "Implemented on handlers that need to respond to events.") - (:method ((client client) event &optional room-id) t)) + (:method ((client client) event) t)) (defgeneric clean-up (client) (:documentation "To be run before the client crashes or is killed.") @@ -122,6 +126,8 @@ "Dynamic variable holding response status headers.") (defvar *response-object* nil "Dynamic variable holding a RESPONSE-OBJECT struct.") +(defvar *room-id* nil + "Dynamic variable holding id of the room whose event is being processed.") ;;; Utilities for working with parsed JSON data @@ -192,7 +198,6 @@ ;; the basic-json struct is used as a kind of default in some places (def-json-wrap basic-json) - ;;; URI constants (format) strings for interacting with the Matrix API (defparameter +login-path+ "/_matrix/client/r0/login") @@ -272,8 +277,11 @@ ,on-ok) ,otherwise))) -(defun make-matrix-path (client path) - (concatenate 'string (homeserver client) path)) +(defun make-matrix-path (client path ) + (concatenate 'string + (if (ssl client) "https://" "http://") + (homeserver client) + path)) ;;; API Calls @@ -332,7 +340,6 @@ (process-invited-room-events client) (process-account-data-events client)) - ;; The following globals are private and are recycled per call to sync (defvar *timeline-event* (make-timeline-event :data nil)) (defvar *text-message-event* (make-text-message-event :data nil)) @@ -376,38 +383,35 @@ (setf (timeline-event-data *timeline-event*) ob) *timeline-event*))) - (defun process-joined-events (client) (loop :for (room-id room . ignore) :on (joined-rooms *response-object*) :by #'cddr :do - ;; room-id should be a string - (setf room-id (symbol-name room-id)) + (let ((*room-id* (symbol-name room-id))) ;; room-id should be a string ;; handle the timeline events (aka room events) (dolist (ob (getob room :|timeline| :|events|)) (handle-event client - (categorize-and-set-timeline-event ob) - room-id)) + (categorize-and-set-timeline-event ob))) ;; handle state chnage events (aka state events) (dolist (ob (getob room :|state| :|events|)) (setf (room-state-event-data *state-event*) ob) - (handle-event client *state-event* room-id)))) + (handle-event client *state-event*))))) ;; TODO add global cache variable for invite event (defun process-invited-room-events (client) (let ((invite-event (make-invitation-event :data nil))) (loop :for (room-id room . ignore) :on (invited-rooms *response-object*) :by #'cddr :do - (setf room-id (symbol-name room-id)) - (dolist (ob (getob room :|invite_state| :|events|)) - (setf (invitation-event-data invite-event) ob) - (handle-event client invite-event room-id))))) + (let ((*room-id* (symbol-name room-id))) + + (dolist (ob (getob room :|invite_state| :|events|)) + (setf (invitation-event-data invite-event) ob) + (handle-event client invite-event)))))) (defun process-account-data-events (client) (dolist (ob (account-data-events *response-object*)) (setf (account-data-event-data *account-data-event*) ob) (handle-event client *account-data-event*))) - (defun send-text-message (client room-id message &rest args) "Sends the MESSAGE (a string) to the room with id ROOM-ID. MESSAGE can also be a format string, and ARGS is " @@ -416,7 +420,6 @@ :|body| (apply #'format (list* nil message args))))) (send (client url body :wrap make-basic-json) t))) - (defun join-room (client room-id) "Attempts to join the client to the room with ROOM-ID." (let ((body (list :|roomId| room-id)) @@ -428,7 +431,6 @@ *response-status* (flexi-streams:octets-to-string *response-body*))))) - (defun update-account-data (client m-type data) "Serializes the PLIST DATA as JSON and PUTs it in account_data at the given M-TYPE. diff --git a/package.lisp b/package.lisp index c88d8f6..0368c9c 100644 --- a/package.lisp +++ b/package.lisp @@ -88,4 +88,6 @@ #:start #:stop + ;; special variables + #:*room-id* )) diff --git a/utility-apps.lisp b/utility-apps.lisp index 8395805..d9834ad 100644 --- a/utility-apps.lisp +++ b/utility-apps.lisp @@ -19,11 +19,11 @@ (loop :for (k . v) :in alist :do (format stream "~a: ~a~%" k v))) -(defmethod handle-event :after ((log message-log) (event timeline-event) &optional room) +(defmethod handle-event :after ((log message-log) (event timeline-event)) (when (logging-p log) (print "Joined Room Message/Timeline Event" (output log)) (terpri (output log)) - (let ((fields `(("room" . ,room) + (let ((fields `(("room" . ,*room-id*) ("sender" . ,(sender event)) ("event type" . ,(event-type event)) ("message type" . ,(msg-type event)) @@ -33,11 +33,11 @@ (terpri (output log))))) -(defmethod handle-event :after ((log message-log) (event room-state-event) &optional room) +(defmethod handle-event :after ((log message-log) (event room-state-event)) (when (logging-p log) (print "Joined Room State Event" (output log)) (terpri (output log)) - (let ((fields `(("room" . ,room) + (let ((fields `(("room" . ,*room-id*) ("sender" . ,(sender event)) ("event type" . ,(event-type event)) ("state key" . ,(state-key event)) @@ -45,8 +45,7 @@ (print-assoc fields (output log)) (terpri (output log))))) -(defmethod handle-event :after ((log message-log) (event account-data-event) &optional room) - (declare (ignore room)) +(defmethod handle-event :after ((log message-log) (event account-data-event)) (when (logging-p log) (print "Account Data Event" (output log)) (terpri (output log)) @@ -56,11 +55,11 @@ (terpri (output log)))) -(defmethod handle-event :after ((log message-log) (event invitation-event) &optional room) +(defmethod handle-event :after ((log message-log) (event invitation-event)) (when (logging-p log) (print "Invitation Event" (output log)) (terpri (output log)) - (let ((fields `(("room" . ,room) + (let ((fields `(("room" . ,*room-id*) ("sender" . ,(sender event)) ("event type" . ,(event-type event)) ("state key" . ,(state-key event)) @@ -110,29 +109,22 @@ (defun update-room-aliases (client room-id member) (declare (ignore client room-id member))) -(defmethod handle-event :after ((client server-directory) - (event room-state-event) - &optional room-id) +(defmethod handle-event :after ((client server-directory) (event room-state-event)) (cond ((string= "m.room.name" (event-type event)) - (update-room-name client room-id (room-name event))) + (update-room-name client *room-id* (room-name event))) ((string= "m.room.member" (event-type event)) - (update-room-member client room-id (sender event))) + (update-room-member client *room-id* (sender event))) ((string= "m.room.aliases" (event-type event)) - (update-room-aliases client room-id (room-aliases event))))) + (update-room-aliases client *room-id* (room-aliases event))))) -(defmethod handle-event :after ((client server-directory) - (event timeline-event) - &optional room-id) - (update-room-member client room-id (sender event))) +(defmethod handle-event :after ((client server-directory) (event timeline-event)) + (update-room-member client *room-id* (sender event))) -(defmethod handle-event :after ((client server-directory) - (event account-data-event) - &optional room-id) - (declare (ignore room-id)) +(defmethod handle-event :after ((client server-directory) (event account-data-event)) (when (equal "m.direct" (event-type event)) (setf (m-direct-event-content client) (event-content event)) (loop :for (user room-ids . more) :on (event-content event) :by #'cddr :do @@ -248,8 +240,8 @@ (defclass auto-joiner () ()) -(defmethod handle-event :after ((client auto-joiner) (event invitation-event) &optional room-id) +(defmethod handle-event :after ((client auto-joiner) (event invitation-event)) (when (equal "invite" (getf (event-content event) :|join_rule|)) - (join-room client room-id))) + (join-room client *room-id*))) |