From 3d9b7e3a01cbfc8883e6f190b961615fba6ba523 Mon Sep 17 00:00:00 2001 From: Lucian Mogosanu Date: Sun, 7 Apr 2019 12:56:07 +0300 Subject: [PATCH] posts: 08b, almost ready --- posts/y05/08b-feedbot-ii.markdown | 118 +++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 posts/y05/08b-feedbot-ii.markdown diff --git a/posts/y05/08b-feedbot-ii.markdown b/posts/y05/08b-feedbot-ii.markdown new file mode 100644 index 0000000..f2a33ac --- /dev/null +++ b/posts/y05/08b-feedbot-ii.markdown @@ -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 -- 1.7.10.4