diff --git a/docs/aliases.rst b/docs/cogs/aliases.rst similarity index 100% rename from docs/aliases.rst rename to docs/cogs/aliases.rst diff --git a/docs/anotherpingcog.rst b/docs/cogs/anotherpingcog.rst similarity index 100% rename from docs/anotherpingcog.rst rename to docs/cogs/anotherpingcog.rst diff --git a/docs/status.rst b/docs/cogs/status.rst similarity index 100% rename from docs/status.rst rename to docs/cogs/status.rst diff --git a/docs/system.rst b/docs/cogs/system.rst similarity index 100% rename from docs/system.rst rename to docs/cogs/system.rst diff --git a/docs/index.rst b/docs/index.rst index 7750a0f7..97bdbf9f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -16,10 +16,13 @@ Welcome to Vex-Cogs's documentation! :maxdepth: 2 :caption: Cogs: - anotherpingcog - aliases - status - system + cogs/anotherpingcog + cogs/aliases + cogs/status + cogs/system + +If you're a developer, there are custom events you can listen to for :ref:`status_dev`. + diff --git a/docs/status_dev.rst b/docs/status_dev.rst new file mode 100644 index 00000000..002878ff --- /dev/null +++ b/docs/status_dev.rst @@ -0,0 +1,97 @@ +.. _status_dev: + +====== +Status +====== + +The status cog has two events you can listen to, ``on_vexed_status_update`` and +``on_vexed_status_channel_send``. + +``status_channel_send`` is fired in quick succession, espscially on larger bots with +lots of channels added, so you shouldn't do anything expensive. ``status_channel_send`` +is dispatched after a successful channel send. + +``status_update`` is dispatched with the channels the cog intends to send updates to when +an update has been confirmed as a non-ghost update. + +There is a guaranteed delay of 1 second between ``status_update`` and the first +``status_channel_send`` to allow you to perform an expensive process (eg get data +from config) and then cache the result for the when ``status_channel_send`` despatches +for each channel so you get the timing correct and you can guarantee it was sent. + +Though this is incredibly unlikely, the cog will cancel sending updates (and the subsequent +``status_channel_send`` if it lasts longer than 1 minute and 50 seconds after +``status_update`` the update was detected. + +Note that ``status_update`` will not trigger if no channels are subscribed to service - +the cog only checks feeds that have channels subscribed to it. + +In terms of testing, the ``devforcestatus`` (alias ``dfs`` command can be used for this. +It simulates an actual/organic update as closely as possible so sends to all registered +channels. The ``force`` parameter will be ``True`` in such cases. + + +.. function:: on_vexed_status_update(feed, fp_data, service, channels, force) + + This event triggers before updates are sent to channels. See above for details. + + :type feed: :class:`dict` + :param feed: A fully parsed dictionary with individual updates in the incident + split up. + + .. note:: + The time the ``time`` key should be a datetime object but it could + be something else. Make sure you handle this. + .. note:: + Some feeds only supply the latest update. See the file-level const + ``AVALIBLE_MODES`` in ``status.py``. + .. note:: + The majority of updates are in the incorrect order in the ``field`` key. + They will need reversing if you are using this key. See file-level const + ``DONT_REVERSE`` in ``status.py`` for ones that don't need it. + :type fp_data: :class:`FeedParserDict` + :param fp_data: The raw data from feedparser. The above ``feed`` is reccomended + where possible. + :type service: :class:`str` + :param service: The name of the service, in lower case. Guaranteed to be on of + the keys in the file-level consts of ``status.py``, though new services are + being added over time so don't copy-paste and expect it to be one of them. + :type channels: :class:`dict` + :param channels: A dict with the keys as channel IDs and the values as a nested + dict contaning the settings for that channel. + :type force: :class`bool` + :param force: Whether or not the update was forced to update with + ``devforcestatus``/``dfs`` + +.. function:: on_vexed_status_channel_send(feed, service, channel, webhook, embed) + + This is has similarties and differnces to the above feed, mainly that it has less + data and dispatches after an update was successfully sent to a specific channel. + See above info at the top of this page for details. + + :type feed: :class:`dict` + :param feed: A fully parsed dictionary with individual updates in the incident + split up. + + .. note:: + The time the ``time`` key should be a datetime object but it could + be something else. Make sure you handle this. + .. note:: + Some feeds only supply the latest update. See the file-level const + ``AVALIBLE_MODES`` in ``status.py``. + .. note:: + The majority of updates are in the incorrect order in the ``field`` key. + They will need reversing if you are using this key. See file-level const + ``DONT_REVERSE`` in ``status.py`` for ones that don't need it. + :type service: :class:`str` + :param service: The name of the service, in lower case. Guaranteed to be on of + the keys in the file-level consts of ``status.py``, though new services are + being added over time so don't copy-paste and expect it to be one of them. + :type channel: :class:`discord.TextChannel` + :param channel: The discord.TextChannel object the update was successfully sent to. + :type webhook: :class:`bool` + :param webhook: Whether or not the update was sent as a webhook. + :type embed: :class:`bool` + :param embed: Whether or not the update was sent as an embed. Will always be ``True`` + if ``webhook`` is ``True``. + diff --git a/status/status.py b/status/status.py index 497c7dff..15f93250 100644 --- a/status/status.py +++ b/status/status.py @@ -1,6 +1,7 @@ # HELLO! # This file is formatted with black, line length 120 -# If you are looking for an event your cog can listen to, take a look around lines 170 and 210 +# If you are looking for an event your cog can listen to, take a look here: +# [link here] import asyncio import datetime @@ -181,7 +182,7 @@ async def _check_for_updates(self): await asyncio.wait_for(self._actually_check_updates(), timeout=110.0) # 1 min 50 secs except TimeoutError: log.error( - "Loop timed out after 2 minutes 20 seconds. Will try again shortly. If this keeps happening " + "Loop timed out after 1 minute 50 seconds. Will try again shortly. If this keeps happening " "when there's an update for a specific service, contact Vexed." ) except Exception as e: @@ -197,38 +198,8 @@ async def before_start(self): async def _update_dispatch(self, feed, feedparser, service, channels, force): """ - This can be used by anyone. If you wish to test it, run the hidden command - `devforcestatus` in discord (alias `dfs`). - - Please note this will NOT trigger if no channels have registered the service - you are looking for. - - This event is triggered BEFORE any updates are sent to channels. - This event can trigger multiple times in short sucession due to how this cog - works. - - Parameters - ---------- - feed : dict - A fully parsed dict with individual updates split up - NOTE: The time the feed was published may be a datetime object OR - something else. Make sure you can handle this - NOTE: Some feeds only supply the latest update. See the file-level - const AVALIBLE_MODES. - NOTE: The majority of feeds are in the incorrect order. They need - reversing. See file-level const DONT_REVERSE. - feedparser : FeedParserDict - The raw dict from feedparser. Unless there's specific data you need, - I highly reccomend using the above `feed` where possible. - service : str - The service name. Guaranteed to be one of the keys in the FEED_URLS - file-level const (unless dev commands are used) - channels : dict - A dict with the keys as channel IDs and the values as another dict contining - the settings for that channel. - force : bool - Whether or not the feed was forced to update with the `devforcestatus`/`dfs` - command. + For more information on this event, take a look at the docs: + [link here] """ self.bot.dispatch( "vexed_status_update", @@ -241,37 +212,8 @@ async def _update_dispatch(self, feed, feedparser, service, channels, force): async def _channel_send_dispatch(self, feed, service, channel, webhook, embed): """ - This can be used by other cogs. For testing, run the hidden comman - `devforcestatus` in discord (alias `dfs`). - - This event is triggered AFTER the update has been sent to channel and will - NOT be triggered if it failed to send. - Due to this, this event will trigger in burts, many times a second. - - If you need the raw feed data from feedparser, take a look at the above event. - Unlike the above event, this does not distinguish between forced and organic - triggers - - Parameters - ---------- - feed : dict - A fully parsed dict with individual updates split up - NOTE: The time the feed was published may be a datetime object OR - something else. Make sure you can handle this - NOTE: Some feeds only supply the latest update. See the file-level - const AVALIBLE_MODES - NOTE: The majority of feeds that support all updates of the incidents - need reversing. See file-level const DONT_REVERSE - service : str - The service name. Guaranteed to be one of the keys in the FEED_URLS - file-level const (unless dev commands are used) - channel : discord.TextChannel - The discord.TextChannel object the update was sent to - webhook : bool - Whether or not the feed was sent as a webhook - embed : bool - Whether or not the feed was sent as a embed. Will always be True if - embed is True + For more information on this event, take a look at the docs: + [link here] """ self.bot.dispatch( "vexed_status_channel_send", @@ -344,8 +286,9 @@ async def _actually_check_updates(self): continue # log.debug(f"Feed dict for {service}: {feeddict}") channels = await self._get_channels(service) - await self._update_dispatch(feeddict, fp_data, service, channels, False) await self._make_send_cache(feeddict, service) + await self._update_dispatch(feeddict, fp_data, service, channels, False) + await asyncio.sleep(1) # guaranteed wait for other CCs log.debug(f"Sending status update for {service} to {len(channels)} channels...") for channel in channels.items(): await self._send_updated_feed(feeddict, channel, service)