posts: 08b, almost ready
authorLucian Mogosanu <lucian.mogosanu@gmail.com>
Sun, 7 Apr 2019 09:56:07 +0000 (12:56 +0300)
committerLucian Mogosanu <lucian.mogosanu@gmail.com>
Sun, 7 Apr 2019 09:56:07 +0000 (12:56 +0300)
posts/y05/08b-feedbot-ii.markdown [new file with mode: 0644]

diff --git a/posts/y05/08b-feedbot-ii.markdown b/posts/y05/08b-feedbot-ii.markdown
new file mode 100644 (file)
index 0000000..f2a33ac
--- /dev/null
@@ -0,0 +1,118 @@
+---
+postid: 08b
+title: Feedbot [ii]: the announcer
+date: April 7, 2019
+author: Lucian MogoČ™anu
+tags: tech, tmsr
+---
+
+This post builds upon [the previous][feedbot-i], introducing the second
+component of [Feedbot][feedbot]: the so-called feed entry
+announcer. Similarly to the [previous episode][feedbot-i], we introduce
+the V patch, then we discuss implementation details.
+
+* The [V patch][feedbot-announcer.vpatch]; and
+* my [seal][feedbot-annonuncer.vpatch.spyked.sig].
+
+Below is reproduced verbatim the documentation of the entry announcer,
+more exactly: the message queue; its manipulation; and the announcer
+loop and thread.
+
+**IV. The message queue**
+
+Once new feed entries are found by the feed checker, they are to be
+distributed to the recipient(s) via e.g. IRC messages. We decouple feed
+checking and announcements by introducing a specialized
+producer-consumer data structure, the message queue.
+
+A message queue is a list of messages.
+
+A message is a list of the form:
+
+~~~~ {.commonlisp}
+  (msg :to rcpt :sent sent
+       :feed-id feed-id :feed-title feed-title :entry entry)
+~~~~
+
+where: `msg` is the symbol MSG; `rcpt` is a string denoting a recipient;
+`sent` is a boolean that, when set to true, marks the message as sent;
+`feed-id` is a string denoting the feed id of the entry's associated
+feed; `feed-title` is the title of the feed; and `entry` is a new entry.
+
+*Note*: `feed-title` is an optimization which saves the announcer an
+extra feed db lookup when the message is sent. See below for more
+details.
+
+**V. Message queue manipulation**
+
+There are three fundamental operations on message queues: pushing new
+messages, retrieving messages and deleting sent messages.
+
+As in the case of the feed db: a. low-level operations; b. used in
+conjunction with `with-msg-queue`; c. are used to implement the
+functionality described above. The implementation of `with-msg-queue` is
+reproduced below, along with the message queue methods:
+
+~~~~ {.commonlisp}
+(defmacro with-msg-queue ((queue) bot &body body)
+  "Execute code within the thread-safe `msg-queue' scope of `bot'."
+  (with-gensyms (queue-mutex)
+    `(with-slots ((,queue msg-queue) (,queue-mutex queue-mutex))
+         ,bot
+       (with-mutex (,queue-mutex)
+         ,@body))))
+
+(defmethod feedbot-process-msg-queue ((bot feedbot) func)
+  "Process messages in the msg queue `bot' accoding to `func'.
+
+Returns the updated message queue."
+  (with-msg-queue (msg-queue) bot
+    (loop for msg in msg-queue do
+         (funcall func msg))
+    msg-queue))
+
+(defmethod feedbot-pushnew-to-msg-queue ((bot feedbot) &rest msgs)
+  "Push new messages to the msg queue of `bot'.
+
+Returns the updated message queue."
+  (with-msg-queue (msg-queue) bot
+    (loop for msg in msgs do
+         (push-msg-to-queue! msg-queue msg))
+    msg-queue))
+
+(defmethod feedbot-delete-sent-msgs ((bot feedbot))
+  "Delete sent messages from the msg queue of `bot'.
+
+Returns the updated message queue."
+  (with-msg-queue (msg-queue) bot
+    (setf msg-queue (delete-msgs-from-queue-if! msg-queue
+                                                #'get-msg-sent!))
+    msg-queue))
+~~~~
+
+**VI. The entry announcer**
+
+The entry announcer periodically scans the message queue for new
+(unsent) messages from the feed checker and announces the associated
+entries, i.e. sends them to the recipient.
+
+Additionally, if the number of sent messages is over a certain threshold
+(see `*max-sent-msgs*`), then they are garbage collected. To eliminate
+this check, set `*max-sent-msgs*` to NIL.
+
+To test feedbot feed checker and announcer functionality, run e.g.:
+
+~~~~ {.commonlisp}
+> (defvar *feedbot*
+     (make-instance 'feedbot:feedbot))
+> (defvar *ttp* "http://thetarpit.org/rss.xml")
+> (feedbot:feedbot-get-or-create-feed *feedbot* *ttp*)
+> (feedbot:feedbot-add-rcpts *feedbot* *ttp* "spyked")
+> (feedbot:feedbot-start-checker-thread *feedbot*)
+> (feedbot:feedbot-start-announcer-thread *feedbot*)
+~~~~
+
+[feedbot-i]: /posts/y05/08a-feedbot-i.html
+[feedbot]: http://btcbase.org/log-search?q=feedbot
+[feedbot-announcer.vpatch]: TODO
+[feedbot-annonuncer.vpatch.spyked.sig]: TODO