Giter Site home page Giter Site logo

juvet / juvet Goto Github PK

View Code? Open in Web Editor NEW
71.0 71.0 2.0 597 KB

The MVC framework for chat apps built on a platform designed for communication systems.

Home Page: http://juvet.io

License: MIT License

Elixir 100.00%
bot chatbot chatbot-framework elixir elixir-library slack sponsorware

juvet's Issues

Connect to a Slack RTM Bot

Connecting to a Slack RTM should be done within a Connection module.

defmodule MyConnection do
  use Juvet.Connection.Slack

  def handle_connect(context) do
    IO.puts "Connected to #{context.connection.type}..."
    {:ok, context}
  end
end

A connection should handle the following:

  • handle_connect
  • handle_disconnect
  • handle_close

Message Broadcaster

A Process that receives new messages from multiple endpoints. These are the raw messages with an origin_platform that describes where the message came from.

This is a simple pubsub process that simply forwards messages to anything that is interested from the SlackRTM process right now.

Slack Router for actions

Create a router that can accept parameters for a block_actions in order to route the request to a controller and action.

A single route file will be available for every Juvet application which can define routes for a Slack endpoint. Here is an example of what some actions may look like within a route file:

# lib/tatsu_bot/router.ex

defmodule TatsuBot.Router do
  use Juvet.Router

  platform :slack do
    action "action_id", "controller#action"
  end
end

The above will find a route with a request that has a type of block_actions and it matches the action_id specified. Here is the documentation around the block_actions payload: https://api.slack.com/reference/interaction-payloads/block-actions

Connection Supervisor Tree

Add a supervisor tree to the connections so a new SlackRTM connection is created for each new connection (e.g. Slack API token) that exists.

The following should be created:

Juvet.ConnnectionFactory -> Worker that gets added to a Juvet.ConnectionFactorySupervisor
Juvet.ConnectionSupervisor -> Supervises workers that get created

Supervisor Process Architecture

I think the supervisor architecture may need to change. Currently, the archiecture is something like this:

On Startup:

[Juvet.ConnectionFactorySupervisor]
-> [Juvet.ConnectionFactory]
-> [Juvet.ConnectionSupervisor]

[Juvet.BotFactorySupervisor]
-> [Juvet.BotFactory]
-> [Juvet.BotSupervisor]

On Connecting:

[Juvet.ConnectionFactorySupervisor]
-> [Juvet.ConnectionFactory]
-> [Juvet.ConnectionSupervisor]
-> [Juvet.Connection.SlackRTM]

[Juvet.BotFactorySupervisor]
-> [Juvet.BotFactory]
-> [Juvet.BotSupervisor]
-> [tatsuio (Juvet.Bot.Server)]

It would be nice to connect each connection to the bot so a bot may have supervise multiple connections so if one goes down, they can be restarted by the bot that has the state.

Also, we should research the architecture a bit to see if the Factory workers are needed to be under the FactorySupervisor or if those can just be stand alone processes. If they can be standalone processes, we should rename the FactorySupervisor processes.

Setup CI

Setup CI using GitHub actions so the library is built on every merge into main as well as all new pull requests.

Slack State

The connections, bot processes, and bots should have an organized Juvet.State.Slack state struct that holds onto the state when the connection initially connects.

  • Allows for the modules to retrieve the platform
  • Allows for the modules to retrieve the connection_id (e.g. in Slack, this would be the team id)
  • Easily retrieve information about the team
  • Easily retrieve information about the champion (user)

Update README

  • Add installation details around adding it to an application
  • Add details around how to use bot behaviours

Bot State

The connections, bot processes, and bots should have an organized Juvet.State.Slack state struct that holds onto the state when the connection initially connects.

  • Allows for the modules to retrieve the platform
  • Allows for the modules to retrieve the connection_id (e.g. in Slack, this would be the team id)
  • Easily retrieve information about the team
  • Easily retrieve information about the champion (user)

Slack Signature Timestamp Range Configuration

Allow a client to configure the verifying of requests for Slack.

A user should be able to:

  1. Turn on/off the verifying of Slack Requests โœ…
  2. Turn on/off timestamp verification
  3. Extend/contract the default 5 minute time-limit for stale requests

rtm.start

Allow for the rtm.start method to be called instead of the rtm.connect method.

The start method is heavier weight because it returns much more state but some may opt to use it. This should be passed in as config but it would also be nice to config it on a per Slack bot basis.

Specify Middleware in Router

The user should be able to specify the middleware that gets run when a route is identified and then run.

Should work similar to GraphQL "base middleware".

Update the Juvet.Middleware module so the MiddlewareProcessor can retrieve the correct middleware.

Slack OAuth

Juvet should handle the intricacies of oauthing with Slack (and future providers like MS Teams and Amazon). This will allow the setup of a bot within a particular framework easier and built in.

Possible Solution

  • We may want to expose the request and callback routes through the SlackEndpointRouter via a SlackAuthenticationRouter and allow them to be overriden
  • Within the "request phase", we just need a way to get an authorize_url with configured scopes, app identifiers and secrets
  • The way to retrieve the authorize_url should be available publically within the OAuth library
  • Within the "callback phase", we should expose an Access callback which gets the token, an Authenticating callback which creates the bot and installs the user and bot, and an Authenticated callback which is called after the bot is installed (can be a callback on the bot).
  • The way to retrieve the token from the code should be available publically within the OAuth library

Design "Musts"

  • The OAuth functionality should be namespaced so that it can be pulled out into it's own package in the future if necessary.
  • It should not modify the payloads that come from the token endpoints. This will make it easier to debug and maintain if the payload matches the documentation.
  • The SlackAuthenticationRouter handler should be a one line call so it can easily be called in overridden callbacks

Extract View Submission Values

Create a module that allows a client to easily extract the submission values from a submission payload:

Juvet.Slack.View.values(payload)

This would extract a view payload like the following:

{
  payload: {
    type: "view_submission",
    view: {
      state: {
        values: {
          "block_id" => {
             "my_action" => {
               type: "plain_text_input",
               value: "my value"
             }
           }
        }
      }
    }
  }
}

And would return the following:

%{
  "my_action" => "my value"
}

Slack Bot Behavior

Create a behavior or module that can be injected into custom bots to help outside implementors create a bot.

defmodule MyBot do
  use Juvet.Bot

  def handle_message(:slack, %{type: "message"} = message) do
    #...
    send_message(:slack, %{})...
  end
end

`user_install` bot method

Called when a user authenticates with Juvet.

def user_install(bot, platform, payload)
end

# USAGE: Juvet.BotFactory.find_or_create(auth.team.team_name) |> MyBot.user_install(:slack, auth)
# Juvet.find_or_create_bot could be a shortcut

This method runs through a series of behavior callbacks which will perform the following:

  1. Call mounted callback if started -> maybe called when the bot is created?
  2. Call authenticated callback
  3. Call installed callback
  • Determines if user is new or existing
  • Looks at local state unless overridden
  1. Call failed_authentication callback if the auth failed
  2. Call signup if user is new
  3. Call signin if user is existing
  • State for the bot should now have the ability to retrieve the user list (via user_ids)
  • Need a way to map teams from different platforms
    • { team: { name: "Tatsu", identifiers: [{ slack: "T12345" }, { facebook: "" }] } }
  • Need a way to map users from different platforms
    • { user: { name: "Jimmy Page", identifiers: [{ slack: "T12345/U12345" }, { facebook: "" }] } }
  • This may remove the need for Juvet.create_bot!/1, Juvet.connect_bot!/3 and Juvet.start_bot!/3 because Juvet.user_install/3 would be the next logical step and it does what connect_bot! does.

Slack Router for Commands

Create a router that can accept parameters for a command in order to route the request to a controller and action.

A single route file will be available for every Juvet application which can define routes for a Slack endpoint. Here is an example of what some commands may look like within a route file:

# lib/tatsu_bot/router.ex

defmodule TatsuBot.Router do
  use Juvet.Router

  platform :slack do
    command :start, MeetingController, :start
  end
end

Supervisor Process Architecture

I think the supervisor architecture may need to change. Currently, the archiecture is something like this:

On Startup:

[Juvet.ConnectionFactorySupervisor]
-> [Juvet.ConnectionFactory]
-> [Juvet.ConnectionSupervisor]

[Juvet.BotFactorySupervisor]
-> [Juvet.BotFactory]
-> [Juvet.BotSupervisor]

On Connecting:

[Juvet.ConnectionFactorySupervisor]
-> [Juvet.ConnectionFactory]
-> [Juvet.ConnectionSupervisor]
-> [Juvet.Connection.SlackRTM]

[Juvet.BotFactorySupervisor]
-> [Juvet.BotFactory]
-> [Juvet.BotSupervisor]
-> [tatsuio (Juvet.Bot.Server)]

It would be nice to connect each connection to the bot so a bot may have supervise multiple connections so if one goes down, they can be restarted by the bot that has the state.

Also, we should research the architecture a bit to see if the Factory workers are needed to be under the FactorySupervisor or if those can just be stand alone processes. If they can be standalone processes, we should rename the FactorySupervisor processes.

Allow for `rtm.start` to be used when connecting via Slack RTM

Allow for the rtm.start method to be called instead of the rtm.connect method.

The start method is heavier weight because it returns much more state but some may opt to use it. This should be passed in as config but it would also be nice to config it on a per Slack bot basis.

Expose Router instead of Endpoint

Adding Juvet to an application should not on it's own start it's own Plug.Router as that is another HTTP endpoint that has to be managed in the deployed application's environment.

Since most bot applications are going to have their own web presence, Juvet should expose the Plug.Router that can be mounted inside another application like so:

defmodule Web.Router do
  use Plug.Router
  forward "/slack", to: Juvet.EndpointRouter
end

This should not start the Juvet.Endpoint supervisor as Juvet itself does not need to start a Cowboy plug. Future options may allow for a standalone bot instance that does not have an endpoint

Setup CI

CI should be setup so it is run and the GitHub Checks API checks and secures the master branch. CircleCI is preferred.

Bot Factory

Process that is used to create bots based on various messages that are received. This bot factory should have child processes for all of the bot children it creates.

It listens for the following messages:

  • new_slack_connection -> Creates a new bot process for the specified team

SlackAPI Request Updates

The SlackAPI is lacking some basic Slack API communication. These upgrades need to be made:

  • Use POST for the requests instead of using GET
  • Specify a default content-type of application/x-www-form-urlencoded
  • Remove the need to have a SlackAPI.request_params/1 and just use a Map (which should be handled by HTTPoison)

Send Message from Bot

The bot behavior should have a send_message function that can send text or a Map to Slack via the SlackRTM connection.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.