hugot

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 6, 2016 License: GPL-3.0 Imports: 19 Imported by: 9

README

Hugot GoDoc

WARNING: This code requires go1.7 context support in http.Request. NOTE: The API is in flux at present.

Hugot is a package for building chat bots. It is inspired by Go's http stdlib package.

Please see the GoDoc for examples and usage.

Documentation

Overview

Package hugot provides a simple interface for building extensible chat bots in an idiomatic go style. It is heavily influenced by net/http, and uses an internal message format that is compatible with Slack messages.

Note: This package requires go1.7

Adapters

Adapters are used to integrate with external chat systems. Currently the following adapters exist:

slack - github.com/tcolgate/hugot/adapters/slack - for https://slack.com/
mattermost - github.com/tcolgate/hugot/adapters/mattermost - for https://www.mattermost.org/
irc - github.com/tcolgate/hugot/adapters/irc - simple irc adapter
shell - github.com/tcolgate/hugot/adapters/shell - simple readline based adapter
ssh - github.com/tcolgate/hugot/adapters/ssh - Toy implementation of unauth'd ssh interface

Examples of using these adapters can be found in github.com/tcolgate/hugot/cmd

Handlers

Handlers process messages. There are a several built in handler types:

RawHandlers will execute for every message sent to them.

HearsHandlers will execute for any message which matches a given regular expression. They are passed all string sub-matches from any capture groups.

Command Handlers act on any direct message. Message are attempted to be processed as a command line. Quoted text is handle as a single argument. The passed message can be used as a flag.FlagSet

Background handlers, are started when the bot is started. They do not receive messages but can send them. They are intended to implement long lived background tasks that react to external inputs.

WebHook handlers can be used to implement web hooks by adding the bot to a http.ServeMux. A URL is build from the name of the handler.

Mux

The Mux will multiplex message across a set of handlers. In addition, a top level "help" Command handler is added to provide help on usage of the various handlers added to the Mux.

WARNING: The API is still subject to change.

Example
package main

import (
	"flag"
	"os"

	"context"

	"github.com/golang/glog"

	"github.com/tcolgate/hugot"

	"github.com/tcolgate/hugot/adapters/slack"

	"github.com/tcolgate/hugot/handlers/ping"
	"github.com/tcolgate/hugot/handlers/tableflip"
	"github.com/tcolgate/hugot/handlers/testcli"
	"github.com/tcolgate/hugot/handlers/testweb"
)

func main() {
	slackToken := flag.String("token", os.Getenv("SLACK_TOKEN"), "Slack API Token")
	nick := flag.String("nick", "minion", "Bot nick")
	flag.Parse()

	// The context can be used to shutdown the bot and any
	// Background handlers gracefully.
	ctx := context.Background()
	a, err := slack.New(*slackToken, *nick)
	if err != nil {
		glog.Fatal(err)
	}

	hugot.Handle(ping.New())
	hugot.Handle(tableflip.New())
	hugot.Handle(testcli.New())

	hugot.HandleHTTP(testweb.New())

	// This will start read , process and forward
	// messages from the adapter into the default
	// handler mux./
	hugot.ListenAndServe(ctx, nil, a)
}
Output:

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrSkipHears is used by Command handlers to indicate they have
	// handled a mesage and that any following Hear handlers should be
	// skipped.
	ErrSkipHears = errors.New("skip hear messages")

	// ErrUnknownCommand is returned by a command mux if the command did
	// not match any of it's registered handlers.
	ErrUnknownCommand = errors.New("unknown command")

	// ErrBadCLI implies that we could not process this message as a
	// command line. E.g. due to potentially mismatched quoting or bad
	// escaping.
	ErrBadCLI = errors.New("could not process as command line")
)

Functions

func ErrNextCommand

func ErrNextCommand(ctx context.Context) error

ErrNextCommand is returned if the command wishes the message to be passed to one of the sub-ommands of a CommandSet. The ctx will be passed through to the next CommandHandler

func Handle

func Handle(h Handler) error

Handle adds the provided handler to the DefaultMux

func HandleBackground

func HandleBackground(h BackgroundHandler) error

HandleBackground adds the provided handler to the DefaultMux

func HandleCommand

func HandleCommand(h CommandHandler)

HandleCommand adds the provided handler to the DefaultMux

func HandleHTTP

func HandleHTTP(h WebHookHandler)

HandleHTTP adds the provided handler to the DefaultMux

func HandleHears

func HandleHears(h HearsHandler) error

HandleHears adds the provided handler to the DefaultMux

func HandleRaw

func HandleRaw(h RawHandler) error

HandleRaw adds the provided handler to the DefaultMux

func IsTextOnly

func IsTextOnly(s Sender) bool

IsTextOnly returns true if the sender only support text.

func ListenAndServe

func ListenAndServe(ctx context.Context, h Handler, a Adapter, as ...Adapter)

ListenAndServe runs the handler h, passing all messages to/from the provided adapter. The context may be used to gracefully shut down the server.

func Loop

func Loop(ctx context.Context, h Handler, a Adapter, as ...Adapter)

Loop processes messages from adapters a and as, and passes them to the provided handler h. ctx can be used to stop the processesing and inform any running handlers. WebHookHandlers and BackgroundHandlers will be configured to use a as the default handler

func NewAdapterContext

func NewAdapterContext(ctx context.Context, a Adapter) context.Context

NewAdapterContext creates a context for passing an adapter. This is mainly used by web handlers.

func SetURL

func SetURL(b *url.URL)

SetURL sets the base URL for web hooks.

func URL

func URL() *url.URL

URL returns the base URL for the default Mux

Types

type Adapter

type Adapter interface {
	Sender
	Receiver
}

Adapter can be used to communicate with an external chat system such as slack or IRC.

func AdapterFromContext

func AdapterFromContext(ctx context.Context) (Adapter, bool)

AdapterFromContext returns the Adapter stored in a context.

type Attachment

type Attachment slack.Attachment

Attachment represents a rich message attachment and is directly modeled on the Slack attachments API

type BackgroundFunc

type BackgroundFunc func(ctx context.Context, w ResponseWriter)

BackgroundFunc describes the calling convention for Background handlers

type BackgroundHandler

type BackgroundHandler interface {
	Handler
	StartBackground(ctx context.Context, w ResponseWriter)
}

BackgroundHandler gets run when the bot starts listening. They are intended for publishing messages that are not in response to any specific incoming message.

func NewBackgroundHandler

func NewBackgroundHandler(name, desc string, f BackgroundFunc) BackgroundHandler

NewBackgroundHandler wraps f up as a BackgroundHandler with the name and description provided.

type Channel

type Channel string

Channel represents discussion channel, such as an IRC channel or Slack channel. The Adapter is responsible for translating between a human name for the channel, and any internal representation

type CommandFunc

type CommandFunc func(ctx context.Context, w ResponseWriter, m *Message) error

CommandFunc describes the calling convention for CommandHandler

type CommandHandler

type CommandHandler interface {
	Handler
	Command(ctx context.Context, w ResponseWriter, m *Message) error
}

CommandHandler handlers are used to implement CLI style commands. Before the Command method is called, the in the incoming message m will have the Text of the message parsed into invidual strings, accouting for quoting. m.Args(0) will be the name of the command as the handler was called, as per os.Args(). Command should add any requires falgs to m and then call m.Parse() ErrNextCommand(ctx) can be returned to inform the command mux to hand the resulting Args to any known sub CommandHandler.

type CommandSet

type CommandSet map[string]CommandHandler

CommandSet assists with supporting command handlers with sub-commands.

func NewCommandSet

func NewCommandSet() *CommandSet

NewCommandSet creates an empty commands set.

func (*CommandSet) AddCommandHandler

func (cs *CommandSet) AddCommandHandler(c CommandHandler)

AddCommandHandler adds a CommandHandler to a CommandSet

func (*CommandSet) List

func (cs *CommandSet) List() ([]string, []string, []CommandHandler)

List returns the names and usage of the subcommands of a CommandSet.

func (*CommandSet) NextCommand

func (cs *CommandSet) NextCommand(ctx context.Context, w ResponseWriter, m *Message) error

NextCommand picks the next commands to run from this command set based on the content of the message

type CommandWithSubsHandler

type CommandWithSubsHandler interface {
	CommandHandler
	SubCommands() *CommandSet // List the supported sub-commands
}

CommandWithSubsHandler should be implemented by any command that includes sub commands.

func NewCommandHandler

func NewCommandHandler(name, desc string, f CommandFunc, cs *CommandSet) CommandWithSubsHandler

NewCommandHandler wraps the given function f as a CommandHandler with the provided name and description.

type Describer

type Describer interface {
	Describe() (string, string)
}

Describer returns the name and description of a handler. This is used to identify the handler within Command and HTTP Muxs, and to provide a descriptive name for the handler in help text.

type ErrUsage

type ErrUsage struct {
	// contains filtered or unexported fields
}

ErrUsage indicates that Command handler was used incorrectly. The string returned is a usage message generated by a call to -help for this command

func (ErrUsage) Error

func (e ErrUsage) Error() string

Error implements the Error interface for an ErrUsage.

type Handler

type Handler interface {
	Describer
}

Handler is a handler with no actual functionality

type HeardFunc

type HeardFunc func(ctx context.Context, w ResponseWriter, m *Message, submatches [][]string) // Called once a message matches, and is passed any submatches from the regexp capture groups

HeardFunc describes the calling convention for a Hears handler.

type HearsHandler

type HearsHandler interface {
	Handler
	Hears() *regexp.Regexp                                                          // Returns the regexp we want to hear
	Heard(ctx context.Context, w ResponseWriter, m *Message, submatches [][]string) // Called once a message matches, and is passed any submatches from the regexp capture groups
}

HearsHandler is a handler which responds to messages matching a specific pattern

func NewHearsHandler

func NewHearsHandler(name, desc string, rgxp *regexp.Regexp, f HeardFunc) HearsHandler

NewHearsHandler wraps f as a Hears handler that reponnds to the regexp provided, with the given name a description

type Message

type Message struct {
	To      string
	From    string
	Channel string

	UserID string // Verified user identitify within the source adapter

	Text        string // A plain text message
	Attachments []Attachment

	Private bool
	ToBot   bool

	Extra interface{} // Arbitrary storage

	*flag.FlagSet
	// contains filtered or unexported fields
}

Message describes a Message from or to a user. It is intended to provided a resonable lowest common denominator for modern chat systems. It takes the Slack message format to provide that minimum but makes no assumption about support for any markup. If used within a command handler, the message can also be used as a flag.FlagSet for adding and processing the message as a CLI command.

func (*Message) Parse

func (m *Message) Parse() error

Parse process any Args for this message in line with any flags that have been added to the message.

func (*Message) Reply

func (m *Message) Reply(txt string) *Message

Reply returns a messsage with Text tx and the From and To fields switched

func (*Message) Replyf

func (m *Message) Replyf(s string, is ...interface{}) *Message

Replyf returns message with txt set to the fmt.Printf style formatting, and the from/to fields switched.

type Mux

type Mux struct {
	*sync.RWMutex
	// contains filtered or unexported fields
}

Mux is a Handler that multiplexes messages to a set of Command, Hears, and Raw handlers.

var DefaultMux *Mux

DefaultMux is a default Mux instance, http Handlers will be added to http.DefaultServeMux

func NewMux

func NewMux(name, desc string) *Mux

NewMux creates a new Mux.

func (*Mux) Describe

func (mx *Mux) Describe() (string, string)

Describe implements the Describe method of Handler for the Mux

func (*Mux) Handle

func (mx *Mux) Handle(h Handler) error

Handle adds a generic handler that supports one or more of the handler types. WARNING: This may be removed in the future. Prefer to the specific Add*Handler methods.

func (*Mux) HandleBackground

func (mx *Mux) HandleBackground(h BackgroundHandler) error

HandleBackground adds the provided handler to the Mux. It will be started with the Mux is started.

func (*Mux) HandleCommand

func (mx *Mux) HandleCommand(h CommandHandler)

HandleCommand adds the provided handler to the mux.

func (*Mux) HandleHTTP

func (mx *Mux) HandleHTTP(h WebHookHandler)

HandleHTTP registers h as a WebHook handler. The name of the Mux, and the name of the handler are used to construct a unique URL that can be used to send web requests to this handler

func (*Mux) HandleHears

func (mx *Mux) HandleHears(h HearsHandler) error

HandleHears adds the provided handler to the mux. All messages matching the Hears patterns will be forwarded to the handler.

func (*Mux) HandleRaw

func (mx *Mux) HandleRaw(h RawHandler) error

HandleRaw adds the provided handler to the Mux. All messages sent to the mux will be forwarded to this handler.

func (*Mux) ProcessMessage

func (mx *Mux) ProcessMessage(ctx context.Context, w ResponseWriter, m *Message) error

ProcessMessage implements the Handler interface. Message will first be passed to any registered RawHandlers. If the message has been deemed, by the Adapter to have been sent directly to the bot, any comand handlers will be processed. Then, if appropriate, the message will be matched against any Hears patterns and all matching Heard functions will then be called. Any unrecognized errors from the Command handlers will be passed back to the user that sent us the message.

func (*Mux) ServeHTTP

func (mx *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP iplements http.ServeHTTP for a Mux to allow it to act as a web server.

func (*Mux) SetAdapter

func (mx *Mux) SetAdapter(a Adapter)

SetAdapter sets the adapter on all the webhook of this mux.

func (*Mux) SetURL

func (mx *Mux) SetURL(b *url.URL)

SetURL sets the base URL for this mux's web hooks.

func (*Mux) StartBackground

func (mx *Mux) StartBackground(ctx context.Context, w ResponseWriter)

StartBackground starts any registered background handlers.

func (*Mux) URL

func (mx *Mux) URL() *url.URL

URL returns the base URL for this Mux

type RawFunc

type RawFunc func(ctx context.Context, w ResponseWriter, m *Message) error

RawFunc describes the calling convention for RawHandler. m is the incoming message. Responses can be written to w.

type RawHandler

type RawHandler interface {
	Handler
	ProcessMessage(ctx context.Context, w ResponseWriter, m *Message) error
}

RawHandler will recieve every message sent to the handler, without any filtering.

func NewRawHandler

func NewRawHandler(name, desc string, f RawFunc) RawHandler

NewRawHandler will wrap the function f as a RawHandler with the name and description provided

type Receiver

type Receiver interface {
	Receive() <-chan *Message // Receive returns a channel that can be used to read one message, nil indicated there will be no more messages
}

Receiver cam ne used to receive messages

type ResponseWriter

type ResponseWriter interface {
	Sender
	io.Writer

	SetChannel(c string) // Forces messages to a certain channel
	SetTo(to string)     // Forces messages to a certain user
	SetSender(a Sender)  // Forces messages to a different sender or adapter

	Copy() ResponseWriter // Returns a copy of this response writer
}

ResponseWriter is used to Send messages back to a user.

func NewNullResponseWriter

func NewNullResponseWriter(m Message) ResponseWriter

NewNullResponseWriter creates a ResponseWriter that discards all message sent to it.

func ResponseWriterFromContext

func ResponseWriterFromContext(ctx context.Context) (ResponseWriter, bool)

ResponseWriterFromContext constructs a ResponseWriter from the adapter stored in the context. A destination Channel/User must be set to send messages..

type Sender

type Sender interface {
	Send(ctx context.Context, m *Message)
}

Sender can be used to send messages

func SenderFromContext

func SenderFromContext(ctx context.Context) (Sender, bool)

SenderFromContext can be used to retrieve a valid sender from a context. This is mostly useful in WebHook handlers for sneding messages back to the inbound Adapter.

type Storer

type Storer interface {
	Get(key string) (*store.KVPair, error)
	Put(key string, value []byte, options *store.WriteOptions) error
	Delete(key string) error
}

type TextOnly

type TextOnly interface {
	Sender
	IsTextOnly()
}

TextOnly is an interface to hint to handlers that the adapter they are talking to is a text only handler, to help adjust output.

type User

type User string

User represents a user within the chat sytems. The adapter is responsible for translating the string User to and from it's external representation

type WebHookHandler

type WebHookHandler interface {
	Handler
	URL() *url.URL      // Is called to retrieve the location of the Handler
	SetURL(*url.URL)    // Is called after the WebHook is added, to inform it where it lives
	SetAdapter(Adapter) // Is called to set the default adapter for this handler to use
	http.Handler
}

WebHookHandler handlers are used to expose a registered handler via a web server. The SetURL method is called to inform the handler what it's external URL will be. This will normally be done by the Mux. Other handlers can use URL to generate links suitable for external use. You can use the http.Handler Request.Context() to get a ResponseWriter to write into the bots adapters. You need to SetChannel the resulting ResponseWriter to send messages.

func NewWebHookHandler

func NewWebHookHandler(name, desc string, hf http.HandlerFunc) WebHookHandler

NewWebHookHandler creates a new WebHookHandler provided name and description.

type WebHookHandlerFunc

type WebHookHandlerFunc func(ctx context.Context, hw ResponseWriter, w http.ResponseWriter, r *http.Request)

WebHookHandlerFunc describes the called convention for a WebHook.

Directories

Path Synopsis
adapters
irc
Package irc implements a simple adapter for IRC using github.com/fluffle/goirc/client
Package irc implements a simple adapter for IRC using github.com/fluffle/goirc/client
mattermost
Package mattermost implements an adapter for http://mm.com using github.com/nlopes/mm
Package mattermost implements an adapter for http://mm.com using github.com/nlopes/mm
shell
Package shell implements a simple adapter that provides a readline style shell adapter for debugging purposes
Package shell implements a simple adapter that provides a readline style shell adapter for debugging purposes
slack
Package slac implements an adapter for http://slack.com using github.com/nlopes/slack
Package slac implements an adapter for http://slack.com using github.com/nlopes/slack
ssh
cmd
handlers
ping
Package ping provides a handler that replies to any message sent
Package ping provides a handler that replies to any message sent
tableflip
Package tableflip provides an exacmple Hears handler that will flip tables on behalf of embittered users.
Package tableflip provides an exacmple Hears handler that will flip tables on behalf of embittered users.
testcli
Package testcli provides an example Command handler with nested command handling.
Package testcli provides an example Command handler with nested command handling.
testweb
Package testweb provides an example webhook handler
Package testweb provides an example webhook handler
uptime
Package uptime provides a handler that replies to any message sent
Package uptime provides a handler that replies to any message sent

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL