--- /dev/null
+(defsystem "mapi"
+ :version "0.0.1"
+ :author "Andrei Șova"
+ :license "MIT"
+ :depends-on (:com.inuoe.jzon
+ :dexador
+ :bordeaux-threads
+ :cl-hash-util
+ :quri
+ :flexi-streams
+ :split-sequence
+ :verbose)
+ :components ((:module "src"
+ :components
+ ((:file "package")
+ (:file "core" :depends-on ("package"))
+ (:file "commands" :depends-on ("package" "core"))
+ (:file "util" :depends-on ("package" "core")))))
+ :description "Library for interacting with the Matrix Client-Server API"
+ :in-order-to ((test-op (test-op "mapi/tests"))))
+
+(defsystem "mapi/tests"
+ :author "Andrei Șova"
+ :license "MIT"
+ :depends-on (:mapi
+ :rove)
+ :components ((:module "tests"
+ :components
+ ((:file "main"))))
+ :description "Test system for mapi"
+ :perform (test-op (op c) (symbol-call :rove :run c)))
--- /dev/null
+(in-package #:org.rm-r.mapi.commands)
-;; readers beware: this is currently a very barebones (and amateurish) library
-;;
-;; In the future it might be packaged into its own thing
-
-(defpackage nullbot/matrix-api
- (:use #:cl
- #:cl-hash-util)
- (:local-nicknames
- (:jzon :com.inuoe.jzon)
- (:fs :flexi-streams))
- (:export
- #:matrix-user
- #:homeserver
- #:name
- #:listening
- #:token
- #:lock
- #:matrix-bot
- #:sendmsg
- #:on-event
- #:start
- #:stop
- #:whoami
- #:request
- #:join
- #:leave
- #:room-id))
-(in-package #:nullbot/matrix-api)
+(in-package #:org.rm-r.mapi)
(defclass matrix-client ()
((homeserver
(:method ((obj matrix-client) event room-id)
(format t "Event Received: ~a~%" event)))
-(defun randint (start end)
- (+ start (random (+ 1 (- end start)))))
-
-(defun rand-string (len &aux (arr (make-array len)))
- (loop for i from 0 below len do
- (setf (aref arr i) (randint 65 90)))
- (fs:octets-to-string arr))
-
-(defgeneric sendmsg (obj room-id content)
- (:method ((obj matrix-client) room-id content
- &aux
- (msg (make-hash-table :test #'equal))
- (encoded-room-id (quri:url-encode room-id))
- (unique-str (rand-string 20)))
- (setf (gethash "msgtype" msg) "m.text")
- (setf (gethash "body" msg) content)
- (request obj (format nil "/rooms/~a/send/m.room.message/~a"
- encoded-room-id
- unique-str)
- :put
- msg
- '(("Content-Type" . "application/json")))))
-
(defgeneric whoami (obj)
(:method ((obj matrix-client))
(request obj "/account/whoami" :get)))
(defgeneric directory-room (obj room-alias)
(:method ((obj matrix-client) room-alias)
(check-type room-alias room-alias)
- ))
+ (request obj
+ (format nil "/directory/room/~a"
+ (quri:url-encode room-alias))
+ :get)))
(defgeneric join (obj room)
(:method ((obj matrix-client) room)
- (request obj (format nil "/rooms/~a/join"
+ (request obj (format nil "/join/~a"
(quri:url-encode room))
+ :post
+ (make-hash-table)
+ '(("Content-Type" . "application/json")))))
+
+(defgeneric sync (obj &key timeout since)
+ (:method ((obj matrix-client) &key timeout since
+ &aux (params))
+ (check-type timeout integer)
+ (check-type since integer)
+ (when timeout
+ (push '("timeout" . timeout) params))
+ (when since
+ (push '("since" . since) params))
+ (request obj (format nil "/sync?~a"
+ (quri:url-encode-params params))
:get)))
(defgeneric leave (obj room-id)
(setf (listening obj) t)
(bt2:make-thread (lambda (&aux
(since)
- (sync-route "/sync?timeout=30000"))
+ ;; TODO: support a configurable timeout
+ (timeout 30000)
+ (sync-route (format nil "/sync?timeout=~a" timeout)))
(loop while (bt2:with-lock-held ((lock obj)) (listening obj)) do
(when since
- (setf sync-route (format nil "/sync?timeout=30000&since=~a" since)))
+ (setf sync-route (format nil "/sync?timeout=~a&since=~a" timeout since)))
(let* ((response (request obj sync-route :get))
(rooms-join (hash-get response '("rooms" "join"))))
(when rooms-join (loop for room-id being each hash-key of rooms-join
--- /dev/null
+(defpackage org.rm-r.mapi
+ (:use #:cl
+ #:cl-hash-util)
+ (:local-nicknames
+ (#:jzon #:com.inuoe.jzon)
+ (#:v #:org.shirakumo.verbose))
+ (:export
+ #:matrix-user
+ #:homeserver
+ #:name
+ #:listening
+ #:token
+ #:lock
+ #:matrix-client
+ #:matrix-bot
+ #:on-event
+ #:start
+ #:stop
+ #:whoami
+ #:request
+ #:join
+ #:leave
+ #:room-id))
+
+(defpackage org.rm-r.mapi.commands
+ (:use #:cl)
+ (:local-nicknames
+ (#:mapi #:org.rm-r.mapi)))
+
+(defpackage org.rm-r.mapi.util
+ (:use #:cl
+ #:org.rm-r.mapi)
+ (:export
+ #:sendmsg)
+ (:local-nicknames
+ (#:fs #:flexi-streams)))
--- /dev/null
+(in-package #:org.rm-r.mapi.util)
+
+(defun randint (start end)
+ (+ start (random (+ 1 (- end start)))))
+
+(defun rand-string (len &aux (arr (make-array len)))
+ (loop for i from 0 below len do
+ (setf (aref arr i) (randint 65 90)))
+ (fs:octets-to-string arr))
+
+(defgeneric sendmsg (obj room-id content)
+ (:method ((obj matrix-client) room-id content
+ &aux
+ (msg (make-hash-table :test #'equal))
+ (encoded-room-id (quri:url-encode room-id))
+ (unique-str (rand-string 20)))
+ (setf (gethash "msgtype" msg) "m.text")
+ (setf (gethash "body" msg) content)
+ (request obj (format nil "/rooms/~a/send/m.room.message/~a"
+ encoded-room-id
+ unique-str)
+ :put
+ msg
+ '(("Content-Type" . "application/json")))))
:version "0.0.1"
:author "Andrei Șova"
:license "MIT"
- :depends-on (:com.inuoe.jzon
+ :depends-on (:mapi
+ :com.inuoe.jzon
:dexador
:bordeaux-threads
:cl-hash-util
:xmls)
:components ((:module "src"
:components
- ((:file "api")
- (:file "main" :depends-on ("api")))))
+ ((:file "main"))))
:description "A bot for nullring on matrix"
:in-order-to ((test-op (test-op "nullbot/tests"))))
#:cl-hash-util)
(:local-nicknames
(:jzon :com.inuoe.jzon)
- (:mapi :nullbot/matrix-api)
+ (:mapi :org.rm-r.mapi)
(:sseq :split-sequence)
(:dex :dexador))
+ (:import-from #:org.rm-r.mapi.util #:sendmsg)
(:export
#:start))
(in-package #:nullbot)
(defparameter +feed-room-id+ "!ShuXi5ohrPUtKHkrNO:matrix.nullring.xyz")
(defparameter +feed-cache-path+ #P"./nullbot_cache.sexp")
(defparameter +feed-sleep-minutes+ 1)
-(defparameter +weather-vancouver+ )
(defparameter +prefix+ "$")
(when (and (> (length body) 0) (equal (aref (car split-body) 0) #\$))
(cond
((string= command "$help")
- (mapi:sendmsg *bot* room-id "Unlike some other bots, I'm nice :3"))
+ (sendmsg *bot* room-id "Unlike some other bots, I'm nice :3"))
((string= command "$weather")
- (mapi:sendmsg *bot* room-id (format nil "It's ~a degrees in Vancouver~%It's ~a degrees in Victoria" (get-temp "YVR") (get-temp "YYJ")))))))
+ (sendmsg *bot* room-id (format nil "It's ~a degrees in Vancouver~%It's ~a degrees in Victoria" (get-temp "YVR") (get-temp "YYJ")))))))
(defmethod mapi:on-event
((obj nullbot) event room-id
(car (xmls:node-children obj)))
(defun node-attr (obj name)
- (second (assoc name (xmls:node-attrs obj) :test #'string=)))
+ (cdr (assoc name (xmls:node-attrs obj) :test #'string=)))
;; TODO: make this into a generic f-n maybe and also make it not dumb
(defun get-node-by-name (obj name)
return child))
(defun send-entry (entry)
- (mapi:sendmsg
+ (sendmsg
*bot*
+feed-room-id+
(format nil "New message on mailing list!~%Title: ~a~%From: ~a~%Link: ~a~%"