The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

=head1 NAME
App::Wubot::Guide::GettingStarted - monitoring and reacting to a feed
=head1 DESCRIPTION
This recipe downloads worldwide earthquake data from the USGS RSS
feed. The feed contains an item for each earthquake 5.0 and greater.
The recipe below filters out earthquakes that are less than 6.0, and
sends a console and growl notification for each. Earthquakes of 7 or
greater get a colorized growl notification. Earthquakes of 8 or
greater get a sticky growl notification. The filtered feed is then
stored in a SQLite database and fed back out again to your favorite
RSS reader.
=head1 RSS Monitor
Start by defining an RSS monitor config.
The RSS plugin config files live here:
~/wubot/config/plugins/RSS/
Start by creating a file named usgs-m5.yaml in that directory. Here
is an example of a minimalist RSS monitor config:
---
delay: 15m
The 'delay' param tells wubot-monitor how frequently to run the check,
and the 'url' tag is the URL of the RSS/Atom feed. For more info on
the RSS monitor, see L<App::Wubot::Plugin::RSS>.
After creating this config file, run wubot-monitor. It will find the
new config file and will schedule an immediate check of the RSS feed.
For each entry in the feed, it will send a message (a data structure)
containing the RSS feed data that will, by default, get serialized and
stored in the queue to go to the reactor process. The message will
look something like this:
- body: ~
config.delay: 300
key: RSS-usgs-m5
lastupdate: 1311212434
plugin: App::Wubot::Plugin::RSS
subject: 'M 6.0, Solomon Islands'
title: 'M 6.0, Solomon Islands'
Notice that the original config params are available in the message
under config.*. The 'key' is unique for every monitor instance, it
contains the plugin directory and filename joined with a dash. The
full plugin name is available in 'plugin'. The 'lastupdate' field
contains the time the message was generated. These are standard
message fields which will be set in every message by wubot-monitor.
The 'subject' field is an optional field that the notification plugins
make use of. If the message has a subject, that subject will be sent
in a notification.
Other fields in the message are initially set by the message plugins
and vary from plugin to plugin. For the RSS plugin, the custom fields
available in this feed are 'body', 'link', and 'title'. The body has
no content in this example.
After the monitor runs and successfully delivers it's messages to the
reactor queue, it will write a cache file here:
~/wubot/cache/RSS-usgs-m5.yaml
The cache file contains a list of the subjects that have previously
been seen, so that the next time the monitor runs (15 minutes later
per the 'delay' config param), it will only send any new items that
show up in the feed. If you remove the cache file and restart
wubot-monitor, it will schedule another immediate check and will
re-send all the data from the feed.
=head1 Rules
Now that the messages have been delivered to the reactor queue, you
need a reactor config to determine what action to take when the
message arrives.
The reactor is configured with a series of rules. For a list of the
properties of a rule, have a peak at L<App::Wubot::Guide::Rules>. For an
overview of the available reactor plugins, see
L<App::Wubot::Guide::ReactorPlugins>.
Let's start with the individual rules and work up to the full rule
tree.
The first thing we need is a rule that captures the magnitude of the
earthquake. The title of the feed contains the magnitude, e.g.:
M 6.0, Solomon Islands
The following rule will use the CaptureData plugin to capture the
number from the 'title' field of the RSS message and store it in a new
field called 'size':
- name: size
plugin: CaptureData
config:
source_field: title
regexp: '^M ([\d\.]+),'
target_field: size
After this rule runs, the message will have a new field named 'size'.
- body: ~
config.delay: 300
key: RSS-usgs-m5
lastupdate: 1311212434
plugin: App::Wubot::Plugin::RSS
size: 6.0
subject: 'M 6.0, Solomon Islands'
title: 'M 6.0, Solomon Islands'
The next step is to ignore earthquakes in the 5.x range. According to
the USGS, there are an average of 1319 earthquakes in this range every
year. That will add up to a lot of notifications. We're just
watching for the bigger ones here, so we need to select those that are
less than 6, and then set the magical 'last_rule' rule, which prevents
any further rules from running. This is the equivalent of routing the
message out /dev/null.
- name: suppress less than 6.0
condition: size < 6
last_rule: 1
There are only an average of 134 earthquakes in the 6 to 7 range, so
we'll let those through so we'll get notification for earthquakes in
that range. But there are only an average of 16 earthquakes per year
that are over 7.0. We want to make the notifications for these events
to stand out. This is pretty similar to the previous rule, but we'll
set the 'sticky' and 'yellow' properties on the rule.
- name: sticky greater than 7.0
condition: size >= 7
plugin: SetField
config:
set:
sticky: 1
color: yellow
To enable the notifications, see L<App::Wubot::Guide::Notifications>.
After enabling the notifications, go to images.google.com and find a
.png file that you would like to use for this feed (try searching for
usgs). Save the file as:
~/.icons/usgs-m5.png
Note that this matches the filename that was created in ~/wubot/config/plugins/RSS.
=head1 final config
So now let's put it all together. The reactor config lives here:
~/wubot/config/reactor.yaml
Here are the final contents of the reactor config, including some
notifications rules discussed in L<App::Wubot::Guide::Notifications>.
Warning: if you are not familiar with YAML, it is extremely sensitive
to whitespace!
---
rules:
- name: earthquakes
condition: key matches ^RSS-usgs-m5
rules:
- name: size
plugin: CaptureData
config:
source_field: title
regexp: '^M ([\d\.]+),'
target_field: size
- name: suppress less than 6.0
condition: size < 6
last_rule: 1
- name: sticky greater than 7.0
condition: size >= 7
plugin: SetField
config:
set:
sticky: 1
color: yellow
- name: notifications
condition: subject is true
rules:
- name: console
plugin: Console
- name: growl color
plugin: HashLookup
config:
source_field: color
target_field: growl_priority
lookup:
red: 2
yellow: 1
orange: 1
grey: 0
bold black: 0
green: -1
magenta: -2
purple: -2
blue: -2
cyan: -2
- name: growl icon
plugin: Icon
config:
image:dir: /Users/your_id/.icons
- name: growl notify
plugin: Growl
=head1 Starting the Reactor
To start the reactor, simply run: wubot-reactor
=head1 Web UI
For more information on the wubot webui, please see the document
L<App::Wubot::Guide::WebUI>.
The Web UI reads the data out of the rss SQLite database, so before we
can use the Web UI, we need to go back to the reactor and add some
rules to store the message.
- name: rss sqlite
condition: key matches ^RSS AND mailbox is true
plugin: SQLite
config:
file: /home/myuserid/wubot/sqlite/rss.sql
tablename: feeds
The SQLite plugin will look at the schema to determine which message
fields you are interested in, and will then attempt to insert a new
row into the database. If SQLite throws and error that the table does
not exist, the SQLite reactor will catch the error and use the schema
above to create the table and then insert the message again. Also you
can add a new column to the schema at any time (a restart of wubot may
be required to read the new schema from the config). When the SQLite
plugin goes to insert the data, it will catch the error that the
column does not exist, and will then attempt to alter the table and
add the row. Note that it will not change the type on a column that
has already been created in the table, or remove a column that was
previously added. For more information, see L<App::Wubot::SQLite>.
You could easily add a rule in the reactor to select the RSS-usgs-m5
key and then add a 'mailbox' field. But this is a good opportunity to
point out that you can also define a reaction that will run directly
in the wubot-monitor process. When you do this, the monitor will
process the rules before ever storing the message to the reactor
queue. The advantage here is that the rule is defined close to the
monitoring config, so you can edit all the custom config specific to
that feed in one place. Start with the monitor config we used
earlier:
---
delay: 15m
And add a 'react' section to define your rules. We'll use the
'SetField' plugin to manually set the mailbox for this feed:
---
delay: 15m
react:
- name: set mailbox
plugin: SetField
config:
field: mailbox
value: earthquake
If you already ran the wubot-monitor after defining the RSS monitor
but before adding this rule, then the monitor has already pulled all
the items from the RSS feed and cached them. So when you add this
rule to the reactor, your database will not even get created until the
first new entry shows up in the feed. You could remove the monitor
cache file (see above in the monitor section) and restart the monitor,
and it will send all the items back through the feed again. Thus your
database will contain all the items that are currently available in
the feed.
The monitor config is a great place to define simple reactions for a
monitor, e.g. adding or modifying fields on the message. But there
are some limitations to be aware of. First, you can only define
reactions that are specific to a single instance of a monitor. If you
have a rule that you wanted to apply to all RSS feeds, then you would
have to duplicate that rule in every file in the RSS directory. So
reactions that cross across many plugins (e.g. the notifications)
should always be defined in the reactor. Second, not all reactor
plugins work in the wubot-monitor process. For example, the 'State'
and 'Command' plugins will not work properly or fully in the
wubot-monitor process. Third, the reason that the monitor and the
reactor are separate processes is by design. This ensures that the
monitors can continually gather data on schedule and won't get hung up
waiting for a reaction to occur.
See the L<App::Wubot::Guide::WebUI> document for more information on
starting up the web ui. Once the process is started up, point your
RSS reader here, and enjoy your filtered feed: