Documentation ¶
Index ¶
- type Adapter
- type Bot
- type Brain
- func (b *Brain) Close() error
- func (b *Brain) Delete(key string) (bool, error)
- func (b *Brain) Emit(event interface{}, callbacks ...func(Event))
- func (b *Brain) Get(key string) (string, bool, error)
- func (b *Brain) HandleEvents(ctx context.Context)
- func (b *Brain) Memories() (map[string]string, error)
- func (b *Brain) RegisterHandler(fun interface{})
- func (b *Brain) Set(key, value string) error
- type BrainMemoryEvent
- type CLIAdapter
- type Config
- type Event
- type EventEmitter
- type EventRegistry
- type InitEvent
- type Memory
- type Message
- type Module
- type ReceiveMessageEvent
- type ShutdownEvent
- type TestBot
- type TestingT
- type User
- type UserTypingEvent
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Adapter ¶
type Adapter interface { Register(EventRegistry) Send(text, channel string) error Close() error }
An Adapter connects the bot with the chat by enabling it to receive and send messages. Additionally advanced adapters can emit more events than just the ReceiveMessageEvent (e.g. the slack adapter also emits the UserTypingEvent). All adapter events must be setup in the Register function of the Adapter.
Joe provides a default CLIAdapter implementation which connects the bot with the local shell to receive messages from stdin and print messages to stdout.
type Bot ¶
type Bot struct { Name string Adapter Adapter Brain *Brain Logger *zap.Logger // contains filtered or unexported fields }
A Bot represents an event based chat bot. For the most simple usage you can use the Bot.Respond(…) function to make the bot execute a function when it receives a message that matches a given pattern.
More advanced usage includes persisting memory or emitting your own events using the Brain of the robot.
func New ¶
New creates a new Bot and initializes it with the given Modules and Options. By default the Bot will use an in-memory in Brain and a CLI adapter that reads messages from stdin and writes to stdout.
The modules can be used to change the Memory or Adapter or register other new functionality. Additionally you can pass Options which allow setting some simple configuration such as the event handler timeouts or injecting a different context. All Options are available as functions in this package that start with "With…".
If there was an error initializing a Module it is stored and returned on the next call to Bot.Run(). Before you start the bot however you should register your custom event handlers.
Example:
b := joe.New("example", redis.Memory("localhost:6379"), slack.Adapter("xoxb-58942365423-…"), joehttp.Server(":8080"), joe.WithHandlerTimeout(time.Second), ) b.Respond("ping", b.Pong) b.Brain.RegisterHandler(b.Init) err := b.Run() …
func (*Bot) Respond ¶
Respond registers an event handler that listens for the ReceiveMessageEvent and executes the given function only if the message text matches the given message. The message will be matched against the msg string as regular expression that must match the entire message in a case insensitive way.
You can use sub matches in the msg which will be passed to the function via Message.Matches.
If you need complete control over the regular expression, e.g. because you want the patter to match only a substring of the message but not all of it, you can use Bot.RespondRegex(…).
func (*Bot) RespondRegex ¶
RespondRegex is like Bot.Respond(…) but gives a little more control over the regular expression. However, also with this function messages are matched in a case insensitive way.
func (*Bot) Run ¶
Run starts the bot and runs its event handler loop until the bots context is canceled (by default via SIGINT, SIGQUIT or SIGTERM). If there was an an error when setting up the Bot via New() or when registering the event handlers it will be returned before the bot starts to process any events.
type Brain ¶
type Brain struct {
// contains filtered or unexported fields
}
The Brain contains the core logic of a Bot by implementing an event handler that dispatches events to all registered event handlers. Additionally the Brain is directly connected to the Memory of the bot to manage concurrent access as well as to emit the BrainMemoryEvent if memory is created, edited or deleted on the brain.
func NewBrain ¶
NewBrain creates a new robot Brain. By default the Brain will use a Memory implementation that stores all keys and values directly in memory. You can change the memory implementation afterwards by simply assigning to Brain.Memory. If the passed logger is nil it will fallback to the zap.NewNop() logger. By default no timeout will be enforced on the event handlers.
func (*Brain) Close ¶
Close is a wrapper around the Brains Memory.Close function to allow concurrent access.
func (*Brain) Delete ¶
Delete is a wrapper around the Brains Memory.Delete function to allow concurrent access and emit the corresponding BrainMemoryEvent.
func (*Brain) Emit ¶
Emit sends the first argument as event to the brain from where it is dispatched to all registered handlers.
func (*Brain) Get ¶
Get is a wrapper around the Brains Memory.Get function to allow concurrent access and emit the corresponding BrainMemoryEvent.
func (*Brain) HandleEvents ¶
HandleEvents starts the event handler loop of the Brain. This function blocks until the passed context is canceled. If no handler timeout was configured the brain might block indefinitely even if the context is canceled but an event handler or callback is not respecting the context.
func (*Brain) Memories ¶
Memories is a wrapper around the Brains Memory.Memories function to allow concurrent access.
func (*Brain) RegisterHandler ¶
func (b *Brain) RegisterHandler(fun interface{})
RegisterHandler registers a function to be executed when a specific event is fired. The function signature must comply with the following rules or the bot that uses this Brain will return an error on its next Bot.Run() call:
Allowed function signatures:
// MyCustomEventStruct must be any struct but not a pointer to a struct. func(MyCustomEventStruct) // You can optionally accept a context as the first argument. It will // receive the correct context of the Bot func(context.Context, MyCustomEventStruct) // You can optionally return a single error value. Returning any other type // or returning more than one value will lead to an error. If the handler // returns an error it will be logged. func(MyCustomEventStruct) error
The event that will be dispatched to the passed handler function corresponds directly to the accepted function argument. For instance if you want to emit and receive a custom event you can implement it like this:
type CustomEvent struct {} b := NewBrain(nil) b.RegisterHandler(func(
Example ¶
done := make(chan bool) type CustomEvent struct{ Test bool } b := NewBrain(nil) b.RegisterHandler(func(event CustomEvent) { fmt.Printf("Received custom event: %+v\n", event) done <- true }) ctx, cancel := context.WithCancel(context.Background()) b.Emit(CustomEvent{Test: true}) go b.HandleEvents(ctx) <-done cancel()
Output: Received custom event: {Test:true}
type BrainMemoryEvent ¶
The BrainMemoryEvent is emitted whenever the Brain reads, writes or deletes a single key-value pair from the brain.
type CLIAdapter ¶
type CLIAdapter struct { Prefix string Input io.ReadCloser Output io.Writer Logger *zap.Logger // contains filtered or unexported fields }
The CLIAdapter is the default Adapter implementation that the bot uses if no other adapter was configured. It emits a ReceiveMessageEvent for each line it receives from stdin and prints all sent messages to stdout.
func NewCLIAdapter ¶
func NewCLIAdapter(name string, logger *zap.Logger) *CLIAdapter
NewCLIAdapter creates a new CLIAdapter. The caller must call Close to make the CLIAdapter stop reading messages and emitting events.
func (*CLIAdapter) Close ¶
func (a *CLIAdapter) Close() error
Close makes the CLIAdapter stop emitting any new events or printing any output. Calling this function more than once will result in an error.
func (*CLIAdapter) Register ¶
func (a *CLIAdapter) Register(events EventRegistry)
Register starts the CLIAdapter by reading messages from stdin and emitting a ReceiveMessageEvent for each of them. Additionally the adapter hooks into the InitEvent to print a nice prefix to stdout to show to the user it is ready to accept input.
func (*CLIAdapter) Send ¶
func (a *CLIAdapter) Send(text, channel string) error
Send implements the Adapter interface by sending the given text to stdout. The channel argument is required by the Adapter interface but is otherwise ignored.
type Config ¶
type Config struct { Context context.Context Name string HandlerTimeout time.Duration // contains filtered or unexported fields }
Config is the configuration of a Bot that can be used or changed during setup in a Module. Some configuration settings such as the Logger are read only can only be accessed via the corresponding getter function of the Config.
func (*Config) EventEmitter ¶
func (c *Config) EventEmitter() EventEmitter
EventEmitter returns the EventEmitter that can be used to send events to the Bot and other modules.
func (*Config) RegisterHandler ¶
func (c *Config) RegisterHandler(fun interface{})
RegisterHandler can be used to register an event handler in a Module.
func (*Config) SetAdapter ¶
SetAdapter can be used to change the Adapter implementation of the Bot.
type Event ¶
type Event struct { Data interface{} Callbacks []func(Event) }
An Event represents a concrete event type and optional callbacks that are triggered when the event was processed by any handler.
type EventEmitter ¶
type EventEmitter interface {
Emit(event interface{}, callbacks ...func(Event))
}
The EventEmitter can be used by a Module by calling Config.EventEmitter(). Events are emitted asynchronously so every call to Emit is non-blocking.
type EventRegistry ¶
type EventRegistry interface { Channel() chan<- Event RegisterHandler(function interface{}) }
The EventRegistry is the interface that is exposed to Adapter implementations when connecting to the Brain. Note that this interface actually exposes direct write access to the events channel to allow adapters to deliver events synchronously and in deterministic order.
type InitEvent ¶
type InitEvent struct{}
The InitEvent is the first event that is handled by the Brain after the Bot is started via Bot.Run().
type Memory ¶
type Memory interface { Set(key, value string) error Get(key string) (string, bool, error) Delete(key string) (bool, error) Memories() (map[string]string, error) Close() error }
The Memory interface allows the robot Brain to persist data as key-value pairs. The default implementation of the Memory is to store all keys and values in a map (i.e. in-memory). Other implementations typically offer actual long term persistence into a file or to redis.
type Message ¶
type Message struct { Context context.Context Text string Channel string Matches []string // contains all sub matches of the regular expression that matched the Text // contains filtered or unexported fields }
A Message is automatically created from a ReceiveMessageEvent and then passed to the RespondFunc that was registered via Bot.Respond(…) or Bot.RespondRegex(…) when the message matches the regular expression of the handler.
type Module ¶
A Module is an optional Bot extension that can add new capabilities such as a different Brain.Memory implementation or a different Adapter.
func WithContext ¶
WithContext is an option to replace the default context of a bot.
func WithHandlerTimeout ¶
WithHandlerTimeout is an option to set a timeout on event handlers functions. By default no timeout is enforced.
type ReceiveMessageEvent ¶
The ReceiveMessageEvent is typically emitted by an Adapter when the Bot sees a new message from the chat.
type ShutdownEvent ¶
type ShutdownEvent struct{}
The ShutdownEvent is the last event that is handled by the Brain before it stops handling any events after the bot context is done.
type TestingT ¶
type TestingT interface { Logf(string, ...interface{}) Errorf(string, ...interface{}) Fail() Failed() bool Name() string FailNow() }
TestingT is the minimal required subset of the API provided by all *testing.T and *testing.B objects.
type UserTypingEvent ¶
The UserTypingEvent is emitted by the Adapter and indicates that the Bot sees that a user is typing. This event may not be emitted on all Adapter implementations but only when it is actually supported (e.g. on slack).