discordcr-middleware

extension to discordcr for webserver-like middlewares discordcr-middleware discord-bot discordcr
0.2.0 released
z64/discordcr-middleware
12 3 3
Zac Nowicki

discordcr-middleware

An extension of discordcr's Client that adds middleware functionality, similar to that of webserver libraries. The goal is provide a very customizable way to conditionally execute event handlers, and make great reuse of code and state between events.

Installation

Add this to your application's shard.yml:

dependencies:
  discordcr-middleware:
    github: z64/discordcr-middleware

Usage

Require the extension:

require "discordcr-middleware"

Creating Middleware

Custom middleware inherits from Discord::Middleware and implements def call(context, done).

class MyMiddleware < Discord::Middleware
  def call(context, done)
    # Do things with `context` here..
    # ..
    # Now call the next middleware in the chain:
    done.call
  end
end

context is an instance of Discord::Context, which contains a reference to your Client and the invoking Message.

done represents the next middleware in the chain, which is grabbed and subsequently called lazily. If you do not send done.call, the rest of the middleware chain won't be executed. Use this to leverage flow control across the middleware stack.

You can also extend Context and add more custom properties to be set and shared between middleware, just like you would a class with property and property!:

# Add `Context#db_user`, with type `Database::UserModel?`
Discord.add_ctx_property(db_user, Database::UserModel)

# Add `Context#db_user`, with type `Database::UserModel`
# This performs a `not_nil!` assertion whenever you try to call it to guarantee the type to the compiler.
# You are responsible for ensuring it will never be `nil`.
Discord.add_ctx_property!(db_user, Database::UserModel)

And use it in some middleware:

Discord.add_ctx_property!(db_user, Database::UserModel)

class UserQuery < Discord::Middleware
  def call(context, done)
    author_id = context.message.author.id
    user = Database::UserModel.find(discord_id: author_id)
    context.db_user = user

    # Only call the next middleware if the user was in our DB,
    # otherwise send an error message
    if user
      done.call
    else
      channel_id = context.message.channel_id
      context.client.create_message(channel_id, "User not found")
    end
  end
end

Middleware#initialize is not defined, so you can define this to accept any arguments to customize the behavior of your middleware per-stack.

class Prefix < Discord::Middleware
  def initialize(@prefix : String)
  end

  def call(context, done)
    # Only call the next middleware if the prefix matches:
    done.call if context.message.content.starts_with?(@prefix)
  end
end

Creating Stacks

Stacks represent a chain of middleware that are executed in succession.

Stacks can be registered on the Client with Client#stack and are uniquely identified with a symbol.

client.stack(:db_info, Prefix.new("!dbinfo"), UserQuery.new) do |context|
  user = context.db_user
  channel_id = context.message.channel_id

  # Send back some info about our database row..
  client.create_message(channel_id, user.to_s)
end

Stacks can be made with a "trailing block" like above, or consist purely of middleware.

client.stack(:foo, MiddlewareA.new, MiddlewareB.new)

Additional Examples

Stock Middleware

A collection of basic, common use-case middleware are provided in discordcr-middleware/middleware.

Require them explicitly to make use of them:

require "discordcr-middleware/middleware/prefix"

DiscordMiddleware::Prefix.new("!help")

Contributors

  • z64 - creator, maintainer

Inspired by the raze web framework and its middleware system.

discordcr-middleware:
  github: z64/discordcr-middleware
  version: ~> 0.2.0
License MIT
Crystal 0.24.0

Authors

Dependencies 2

Development Dependencies 0

Dependents 1

Last synced .
search fire star recently