From 2537df9d1fed2a05085c0180fae6ea59385c8ee8 Mon Sep 17 00:00:00 2001 From: Eric Richter Date: Tue, 29 Aug 2017 18:34:04 -0500 Subject: [PATCH] doc: add initial documentation for the message type standard Message types can be used to control how modules interpret messages. This file serves as the standard for what are valid types, and how modules or agents should expect to handle them. --- doc/MessageFormat.md | 8 ++--- doc/MessageTypes.md | 84 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 doc/MessageTypes.md diff --git a/doc/MessageFormat.md b/doc/MessageFormat.md index 1da0d75..4e5f4d0 100644 --- a/doc/MessageFormat.md +++ b/doc/MessageFormat.md @@ -11,7 +11,7 @@ Messages are received as an object that works like a javascript-like dictionary, The following are top-level attributes: - `body`: The data being sent. In most cases, this is the text of the message. - - `type`: Type of message, determines what may be in `body`. + - `type`: Type of message, determines what may be in `body`. See `MessageFormat.md` for more info. - `author`: A short name for who sent the message. - `identity`: A string that uniquely identifies a user. - `origin`: Where this message originated from. @@ -27,11 +27,9 @@ This will always be a `str` object, and can be empty (`""`). ## Type (*string*) The type of message should be set to reflect the kind of message being passed along. -The valid types of messages are: +The valid types of messages are defined more in depth in `MessageFormat.md`. -| Type String | Description | What is in `body` | -| ----------- | ----------------------------------- | ----------------- | -| `simple` | Plain text message sent from a user | Plain text | +Most messages are use the type `simple`, which are for general chatter (e.g. plaintext messages sent to/from a channel or user). ## Author (*string*) diff --git a/doc/MessageTypes.md b/doc/MessageTypes.md new file mode 100644 index 0000000..c4cbc2b --- /dev/null +++ b/doc/MessageTypes.md @@ -0,0 +1,84 @@ +# Halibot Message Types + +While most Halibot activity is generally simple chatter between agents and modules, there are other message types reserved for other functions. +The most common type is the obviously named `simple`, which indicates the body field contains plain text that an agent or module should react to. +An example of another type of message is a `status` message, which could be used for say, indicating a user has joined a channel. +Message types can also be further refined with a subtype. +Using the previous example, the status subtype would be `status:join`. + +## How are types used? + +This is actually a bit of trick question. +Types for the most part are actually *ignored* by Halibot core. +So why bother defining them? +Types exist so that agents and modules can have a platform to hint at how the message should be interpreted. +As mentioned before, in most cases, messages are used to send a protocol's chat messages over to modules for them to handle. +However, this does not provide a platform for an agent to relay *other* useful metadata, like a user joining a channel. +Types thus provide a standardized way to further translate protocol-specific information into a generic platform for modules to react to. + +Types can also be used as a grouping of subtypes. +Not all protocols are designed the same, some provide more fine detail. +Therefore, types are also flexible via use of subtypes, to also provide more detail. +In slightly more simple terms, consider the type to be a top-level category, and a subtype to be more specific. +See the table below for more examples. + +## HalObject API + +A Message type (`msg.type`) is defined by a string of the form `` or `:`. +Subtypes are optional and not required, however it must be noted that inclusion or omission of a subtype may cause the message to be handled differently than expected. +Refer to the table below to ensure that the correct message type and/or subtype is used. + +While Halibot core does not handle messages any different by type, HalObject instead uses a "top-level" filter based on type. +That is, messages of a different supertype can be sent to different receive handlers. +By default, if no specialized receivers are defined, all messages regardless of type are send to `.receive()`. +A notable exception is the `HalModule` class, which by default defines all the type receivers (except `simple`) as no-ops, to passively ignore unhandled types. + +To clear things up, here is a quick diagram and example: +```python +''' +msg.type = simple + Agent -> dispatch() -> Module -> .receive_simple() -> .receive() +msg.type = status:join + Agent -> dispatch() -> Module -> .receive_status() +''' + +class Example(HalModule): + + # Receiver of msg.type = status messages ONLY + def receive_status(self, msg): + # Respond to a user entering the channel + if msg.type.subtype == "join": + self.reply(msg, body="Hello, " + msg.author, type="simple") + # Respond to a user leaving the channel + elif msg.type.subtype in ("part","quit"): + self.reply(msg, body="Goodbye, " + msg.author, type="simple") + # Agent or protocol doesn't specify what type of status, so have a default catch-all + else: + self.reply(msg, body="{} did something.", type="simple") + + # Default receiver of all messages + def receive(self, msg): + if msg.body.lower() in ("hi", "hello") + self.reply(msg, body="Hello, " + msg.author) + +``` + +**NOTE:** `msg.type` will always contain the full string `":subtype"`. +The attribute `msg.type.subtype` exists for convenience to either return the string of the subtype, or the empty string if no subtype is set. + +## TL;DR + +As a rule: `msg.status` defines how to interpret what is in the `msg.body`. +Furthermore, `msg.status` also defines what handlers are called when this message is received in the HalObject API. +It is up to the modules and agents to correctly communicate the data within `msg.body` -- there is no validation done via Halibot core. +Thus, if `msg.status`'s type indicates that `msg.body` should be an integer, both sides must do their own enforcement. + +## Table of Types + +Type String | Description | What is in `msg.body` +----------------------------------------------------------------------------- +`simple` | Plain text message sent to/from a user | Plain text +`status` | A user changed connection status | undefined +`status:join` | A user joined the channel | undefined +`status:part` | A user left the channel | undefined +`status:quit` | A user disconnected | undefined