Skip to content

Response Object Design and Implementation

Upendra Reddy edited this page Jun 5, 2019 · 4 revisions

Response Object Design and Implementation

Abstract: The aim of this document is to design a response object for introducing interactivity in rich messages in Rocket.chat and exploring the ways to send the response object to the bot. This document also summarizes on how the slack and telegram send the messages back and forth between bot and room.

Interactive Message Flow:

The present rich messages implementations are static and don’t support any continuous interactions with the bot. But continuous interactivity with the bot is required for better conversations.

  1. Origin: The origin for an interactive message would be the user makes a request for the interactive rich message component and the rich message is sent to the user by the bot.
  2. Interaction: The rich message may be static component i.e doesn’t start a new flow or it is interactive i.e starts a flow of messages by sending a message back to the bot. The interaction happens when the user acts upon on the interactive component like clicking a button or selecting an item from the menu.
  3. Request: When the interaction happens a response payload corresponding to the interacted component is sent to the bot from the Rocket chat API and the response payload contains details about the room, user, original message … etc
  4. Respond Back: After receiving the response payload it’s up to the bot on how to handle the response i.e based upon the response, the bot may start a call to external services and update in the room by sending a new interactive message or stop the conversation just by acknowledging with ok response back to the room.

Response payload:

The Response payload is used to notify the bot about the value of the interacted rich message component so that bot can take necessary action based upon the user interaction with the interactive message. The basic things which the response payload must contain are type, Channel details, user details, time stamp, response URL1. , selected actions.

Example:

{
	"type": "block_actions",
	"channel": {
		"id": "T0CAG",
             "name": "general",
             "type": "public",
	},
	"user": {
		"id": "U0CA5",
		"username": "Amy McGee",
		"name": "Amy McGee",
		"roles": "user"
	},
	"id": "A0CA5",
	"original_message": {json_data of original message},
	"trigger_id": "12466734323.1395872398",
	"response_url": "https://www.postresponsestome.com/T123567/1509734234",
	"actions": [
		{
			"type": "overflow",
			"block_id": "actionblock789",
			"action_id": "overflow",
			"selected_option": {
				"text": {
					"type": "plain_text",
					"text": "*this is plain_text text*",
				},
				"value": "value-0"
			},
			"action_ts": "1559021820.469700"
		}
	]
}

Type: Type corresponds to what type of response, there can be several types corresponding to different interactive messages like “buttons”, “overflows”, “datepickers”... etc.

Channel channel field holds the details about the channel in which user has interacted and it can contain fields like id, name, type.

User: User field holds the details of the user who interacted with the message. The User field can contain subfields like id, name, roles, username

Original_message: This field holds the JSON data of the original message which can be used by the bot to check the corresponding response actions against the original message.

Actions: This field holds the user selected option in the rich message component and contains details and value of the selected option like id, type, value.

Response_url The response_url is generated by the server and is unique to each interactive component. The response_url can be used to update the existing interactive component or send a new message in reply to the existing interactive component.

Slack Implementation

  1. The first step in the slack implementation would be configuring the App.

  1. After that, we can choose how the App should work. There are several options like interactive messages, Bot ...etc

  1. We can choose to create a bot and after that, we are given credentials to authenticate the bot programmatically.

  1. Now the bot is Setup Now to enable the interactivity in the message in the room we need to enable interactive components. In the Interactive Components, we are asked for a request URL where all the response payload will go to when user action happens in the interactive component.

  1. The request_url is the URL which is maintained by the user who created the bot i.e Administrator and all the response payloads are sent to this URL by the server when the user performs the action on an interactive component.

  2. Now bot has received the response payload and has done its work of processing and wants to send a response back to the room corresponding to the interacted component like updating the interactive message or send to room.

  3. There are several ways to send back to the room using response_url, incoming_webhooks or using SlackAPI chat.postMessage.

  4. Response_url response_url is unique to each interactive message and is used to update the existing interacted rich message component. The payload can be like in this format. The bot has to post this json to the response_url to update the message.

  1. Incoming_webhooks Incoming webhooks are unique to each channel and when configured a URL is generated and the bot can Post the message object to the incoming webhook URL and the message gets displayed in the room.

  2. chat.postMessage chat.postMessage is the standard Slack API used to send messages. It requires some fields like room name and message object

BOTS in Rocket.Chat

In Rocket.Chat, a bot is a special user account with the bot role and a specific set of permissions. In Rocket.chat Bot contains a JS SDK which defines all low-level API and allows to subscribe to message streams and And adapter is present to translate the low-level API from JS SDK to the Bot framework.

  1. In Rocket.chat the bot subscribes to message streams in the room i.e bot gets to know about a message only if the message is published in the room.

  2. But to have interactivity after the user interacts with the interactive component that corresponding response payload has to reach the bot.

  3. But the only way a bot receives a response payload is when a message is published in the room this means a message appears in the chat room whenever the user interacts with the interactive component. There’s no way a bot receives payload directly from the server.

  4. There’s a need for programmatic access like an API to direct message the bot

Telegram Implementation

In the telegram, all bots are created using one main bot called BotFather. And After creating a bot a BotId is provided by the bot father and this botID is unique to every bot and this BotID serves as authorization.

  1. Search Botfather and type “/newbot” and give the name and username of the bot and the bot will return a BOTID

  1. A new Bot token is created and this bot token is necessary to access the telegram API.

  2. Setting up a bot: Whenever a message is sent to a bot in the chat room, the telegram server sends a Post method containing the message to the bot. All queries to the Telegram Bot API must be served over HTTPS and need to be presented in this form

 https://api.telegram.org/bot<bottoken>/METHOD_NAME
  1. There are two ways we can go about receiving updates whenever someone sends messages to our bot

    1. getUpdates API: The telegram server stores the messages sent in the room by the users and whenever the bot access the getUpdates API all the message objects are retrieved. By using this method the bot has to poll the server every time.
     https://api.telegram.org/bot<bottoken>/getUpdates
    1. webhooks To setup a webhook user can post a url to the api like https://api.telegram.org/bot<bottoken>/setwebhook?url=URL or write a helper code which post url to the api. The webhook url server should support ipv4, Provides a supported, non-wildcard, verified or self-signed certificate, Is able to handle TLS1.0+ HTTPS-traffic. This webhook setup doesn’t require a botFather.

    2. To set up a Webhook first the bot has to authenticate with the telegram server. To reduce the burden of directly calling the API's using the url like https://api.telegram.org/bot<bottoken>/setwebhook there are several wrapper libraries which do that. After Authenticating the bot has to set a webhook by using the setwebhook method and passing the webhook url as parameter. After that an acknowledgment response is recieved telling that webhook is been correctly set. After this, the telegram server can communicate with the bot and bot can recieve any updates from the room.

    3. The webhook url server should support ipv4, Provides a supported, non-wildcard, verified or self-signed certificate, Is able to handle TLS1.0+ HTTPS-traffic. This webhook setup doesn’t require a botFather.

  1. So if the user wants to send a message directly to the bot without sending a message in the chat there is an field in telegram called CallbackQuery. The new 2.0 telegram API introduced inline keyboards for the messages and contains inlinekeyboard buttons and each button contains a callback data field which can be used by the bot when user clicks on the button.

  1. So when user clicks on the inlinekeyboardbutton the callback data is sent in the callbackQuery field with the parameters like callback data, id, user, Message with the callback button that originated the query. And the bot receives the data using the callbackquery type

  1. When the object posted by the telegram server contains the callbackquery field a message doesn’t appear in the chat but it directly reaches to the bot, a message only appears in the chat if the post object has the message field . And the bot can retrieve the data and can update the message text of the button in the chat or send a new message using sendMessage method in the API based upon the callback data.

Fields in Response Object

Field Type Description
type

user

Channel

Original _message

actions

String

Object

Object

Object

Object[]

Helps to identify the interactive component which sent the payload. For an element in block the type will be block_actions

the user who interacted to trigger this request.

The room from which the user interacted to trigger the request.

The message that the user initiated the interaction from.

This contains the response data from the specific interactive component that was used. There are several types of interactive components and each component have different specific response values

Actions Object for Button:

Field Type Description
action_id

block_id

type

value

action_ts

text

String

String

String

String

String

String

Id of the interactive block element present in the message object

The Id of the block in which interactive element is present

The type for the button element will be button

The value of the button sent in the message object

The time at which user has interacted with the button element

Text on the button

Actions Object for DatePicker

Field Type Description
action_id

block_id

type

initial_date

action_ts

selected_date

String

String

String

String

String

String

Id of the interactive block element present in the message object

The Id of the block in which interactive element is present

The type for the datepicker element will be datepicker

The initial date to display sent in the message object

The time at which user has interacted with the button element

The date which user has selected in the date picker UI

Actions Object for Menu and Overflow:

Overflow contains every field except the placeholder field.

Field Type Description
action_id

block_id

type

selected_option

placeholder

action_ts

String

String

String

Object

Object

String

Id of the interactive block element present in the message object

The Id of the block in which interactive element is present

The type for the menu element will be static_select for menu and overflow for overflow

The Option which user has selected contains text and the value of the option

The placeholder text which is sent in message object

The time at which user has interacted with the button element

Suggestions on Sending Response object to bot.

Suggestion 1

In this approach, we can use the webhooks like telegram where setting up a webhook will be a one-time configuration effort. We can have an API to set up a webhook URL with authorization after the bot has authorized with the Rocket.Chat Server Or For bots we can have an option to setup the webhook url in the web frontend. Telegram defines several set of rules to follow to use an URL as a webhook. After a webhook is setup any updates in the room like a new message or a interaction payload from a rich message from the client are sent to the Rocket chat server using an API and the server forwards it to the webhook URL. The bot will receive any messages in the room or any interactions payloads sent to the webhook url and sends an acknowledgment response to Rocket chat server. After the bot recieves the update the bot processes it and can respond back to room with a new message or a new rich message or can update an existing rich message. To send a message back to the room the bot can use Rocket.chat JS sdk which provides several methods like authenticate, login, and send messages and Rocket chat Rest API's. But currently the RocketChat provides API to update the text of the message given roomId, messageId, as parameters but to update a Rich message we need to update more than text of the message. This requires a New API in rocket chat server.

WorkFlow

  1. An administrator creates a user and specifies roles for the user for the bot Administrator specifies the bot role and set's up username and password for the bot.

2. Now bot can be authorized and can be logged in using Rocket.Chat JS sdk
  const conn = await driver.connect( { host: HOST, useSsl: SSL})
   myuserid = await driver.login({username: USER, password: PASS});
  1. After bot has been authorized and logged in to the Rocket.chat Server now the bot can call the API to setup the webhook URL. This requires a new API in Rocket.Chat RestAPI to setup the webhook for the bot
const webhook = driver.setupWebhook({"username": USER, "webhookUrl":URL})
  1. Now since webhook has been set for the bot, any interaction payload from the user actions like clicking on a rich message button can be received.
    1. The user clicks on an interactive rich message in the client and the client sends a response object to the rocket.chat server. The rocket.chat server then sends that response object known as interactive payload to the webhook url. This requires a new API in Rocket.chat server. After the client sends a response object to the Rocket chat server the server can add some additional fields necessary to the response object and becomes interactive payload.

    2. The new rocket.chat API will have the botId or username and response object as the parameters. And the API will retrieve the webhook URL corresponding to the botId and sends the response object a.k.a interaction payload to the webhookURL. The bot can send an acknowledgment response back to the server that it has received the payload

          ` client.sendToBot(BotId, responseObj)`
      
    3. After Rocket.chat server sends the interaction payload to webhookurl the bot can retrieve it.

app.post('/webhook_url', function (req, res) {
  let body = req.body;
  console.log(body);
  console.log(body.type);
})
  1. After Bot recieves the interactive payload the bot can process the interactive payload and can decide to send message back to the room or send an another interactive rich message or update an existing message. The interactive payload contains all the necessary data like the user who initiated the action, room in which the action has occurred, value of the interactive message ..etc these can be useful for the bot.

  2. The Rocket.chat bot SDK contains the methods to send a message back to the room or to send another interactive rich message.

const sentmsg = driver.sendMessage({ "rid": "GENERAL", "msg": "This is a test!" ,"attachments": attachments});
  1. To update the text of Existing message the SDK can access low lying Rocket.chat update API and pass the messageId, RoomId, text as parameters to update an existing message.
const { driver, api } = require('@rocket.chat/sdk');
const sentmsg = api.post('chat.update',{"rid":"GENERAL","_id":"qwer112","text":"Updated text"},true)
  1. But to update an existing Rich message there is no API in Rocket.Chat. To update an existing Rich message there's need of new API.

API's Required

setWebHookUrl : To setup webhook for the bot

sendToBot : Required for the clients to send a response object to Rocket.chat Server

updateMessage : Required to update the interactive rich messages.

Suggestion 2

This approach modifies the Rocket.chat message object to have a field which specifies whether the message should be displayed in the chat room or not. Since the bot gets to know about if there's any new messages in the room . If the user interacts with the interactive rich message the response object is included in the attachments field of the message object and the message object is sent as a normal message to the room. The bot can retrieve the message object with the response object in the attachments field processes it and can send back a new message to the room or a new rich message back to the room. The field in the message object determines whether the clients should display the message in the room or not. If the message is intended for the bot the field is set false and the clients wont show the message and if the message is normal the field is set to true and clients will display message in room.

Clone this wiki locally