(in-package #:logbot) (defun get-and-purge-outbox-messages (db) (postmodern:with-connection db (postmodern:query "with deleted as ( delete from outbox returning target, message, queued_at ) select target, message from deleted order by queued_at" :rows))) (defun make-log-entry (db target message host source user) (postmodern:with-connection db (postmodern:execute "insert into log (target, message, host, source, \"user\") values ($1, $2, $3, $4, $5)" target message (if (string= "" host) :null host) source (if (null user) :null user)))) (defclass logbot (ircbot) ((pg-thread :accessor logbot-pg-thread :initform nil) (db :reader logbot-db :initarg :db))) (defmethod ircbot-connect :after ((bot logbot)) (let ((conn (ircbot-connection bot))) (add-hook conn 'irc-mode-message (lambda (message) (logbot-check-mode bot message))) (add-hook conn 'irc-privmsg-message (lambda (message) (destructuring-bind (target message-text) (arguments message) (make-log-entry (logbot-db bot) target message-text (host message) (source message) (user message))))))) (defmethod ircbot-send-message :after ((bot logbot) target message-text) (let* ((b-connection (ircbot-connection bot)) (b-user (user b-connection))) (make-log-entry (logbot-db bot) target message-text (hostname b-user) (nickname b-user) (username b-user)))) (defmethod logbot-check-mode ((bot logbot) message) (if (= 3 (length (arguments message))) (destructuring-bind (channel mode nick) (arguments message) (when (and (string= (host message) "services.") (string= channel (ircbot-channel bot)) (or (string= mode "+o") (string= mode "+v")) (string= nick (ircbot-nick bot))) (when (null (logbot-pg-thread bot)) (logbot-start-pg-thread bot) (logbot-send-outbox bot)))))) (defmethod logbot-send-outbox ((bot logbot)) (loop for (target message) in (get-and-purge-outbox-messages (logbot-db bot)) do (ircbot-send-message bot target message))) (defmethod logbot-start-pg-thread ((bot logbot)) (setf (logbot-pg-thread bot) (sb-thread:make-thread (lambda () (postmodern:with-connection (logbot-db bot) (postmodern:execute "listen outbox_new_message") (loop (if (string= (cl-postgres:wait-for-notification postmodern:*database*) "outbox_new_message") (logbot-send-outbox bot))))) :name "logbot-pg"))) (defun make-logbot (server port nick password channel db) (make-instance 'logbot :server server :port port :nick nick :password password :channel channel :db db))