web

package
v0.0.0-...-ba21cce Latest Latest
Warning

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

Go to latest
Published: Apr 16, 2018 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package web implements custom websocket bots.

You start by creating a `Controller`, and calling `DirectMessages` on that returns a receive only channel, that'll give you incoming messages.

Calling `ConnectionHandler` returns an http.Handler that can be set as the handler for any endpoint that should accept websocket connections.

Index

Constants

View Source
const (
	ImageType        AttachmentType = "image"
	AudioType                       = "audio"
	VideoType                       = "video"
	LocationType                    = "location"
	FileDownloadType                = "file_download"
)

Variables

View Source
var (
	ErrNilControllerStore   = errors.New("Controller Store cannot be nil")
	ErrNilConversationStore = errors.New("Conversation Store cannot be nil")
	ErrNilErrorHandler      = errors.New("ErrorHandler cannot be nil")
	ErrNilIDCreator         = errors.New("ID Creator cannot be nil")

	ErrConversationExists        = errors.New("Conversation Already Exists")
	ErrConversationNotFound      = errors.New("Conversation Not Found")
	ErrConversationAlreadyActive = errors.New("Conversation Already Active")
	ErrNoStartState              = errors.New("Conversation Has no start state")
	ErrStateAlreadyExists        = errors.New("State Already Defined")
	ErrNilHandler                = errors.New("Nil Handler")

	ErrIDNotSet       = errors.New("cannot send a message without ID set")
	ErrPrevNextNotSet = errors.New("cannot send a message without either prev or next set")
	ErrSourceNotSet   = errors.New("cannot send a message without source set")
	ErrTypeNotSet     = errors.New("cannot send a message without type set")

	ErrItemNotFound        = errors.New("Item Not Found")
	ErrThreadNotFound      = errors.New("Thread Not Found")
	ErrBotNotFound         = errors.New("Bot Not Found")
	ErrBotAlreadyAdded     = errors.New("Bot Already Added")
	ErrCannotAddThreadZero = errors.New("Cannot explicitly add a thread with ID zero")

	ErrInvalidItem = errors.New("Invalid Item")
)

Functions

func WithBotIDCreator

func WithBotIDCreator(f BotIDCreator) func(*Controller) error

WithBotIDCreator can be passed as an option to NewController with the desired implementation of BotIDCreator.

func WithControllerStore

func WithControllerStore(store ControllerStore) func(*Controller) error

WithControllerStore can be passed as an option to NewController with the desired implementation of ControllerStore.

func WithConversationStore

func WithConversationStore(store ConversationStore) func(*Controller) error

WithConversationStore can be passed as an option to NewController with the desired implementation of ConversationStore.

func WithErrorHandler

func WithErrorHandler(f ErrorHandler) func(*Controller) error

WithErrorHandler can be passed as an option to NewController with the desired implementation of ErrorHandler.

func WithText

func WithText(text string) func(Attachment)

WithText is a shorthand that can add text to any message attachment

func WithTitle

func WithTitle(title string) func(Attachment)

WithTitle is a shorthand that can add a title to any message attachment

Types

type Attachment

type Attachment interface {
	Type() AttachmentType
}

Attachment defines the interface for all message attachments

func Audio

func Audio(url string, options ...func(Attachment)) Attachment

Audio defines a function to create an audio attachment

func FileDownload

func FileDownload(url string, options ...func(Attachment)) Attachment

FileDownload defines a function to create a download attachment

func Image

func Image(url, alt string, options ...func(Attachment)) Attachment

Image defines a function to create an image attachment

func Location

func Location(lat, long float64, options ...func(Attachment)) Attachment

Location defines a function to create a location attachment

func Video

func Video(url string, options ...func(Attachment)) Attachment

Video defines a function to create a video attachment

type AttachmentType

type AttachmentType string

AttachmentType defines a string identifying the type of an message attachment

type Bot

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

Bot is essentially managing a single WebSocket connection for a controller. It can also start conversations registered with a Controller.

func (*Bot) ID

func (bot *Bot) ID() BotID

ID returns the current bot's ID

func (*Bot) Reply

func (bot *Bot) Reply(original, reply *Message)

Reply replies to a client message, the outgoing message has the ID of the message being replied to set.

func (*Bot) ReplyInThread

func (bot *Bot) ReplyInThread(original, reply *Message)

ReplyInThread replies to a client message in the same thread or creates a new thread, if the original message wasn't in a thread.

func (*Bot) Say

func (bot *Bot) Say(msg *Message)

Say directly sends a message to the client.

func (*Bot) Send

func (bot *Bot) Send(item Item) error

Send adds an item to be sent without setting ID or cursors. This is typically used to send old messages from history that already have ID and cursors set, or cached items.

func (*Bot) StartConversation

func (bot *Bot) StartConversation(name string) error

StartConversation starts a conversation with the given name with the client.

func (*Bot) Update

func (bot *Bot) Update(msg *Message)

Update updates an existing message already sent to the client.

type BotID

type BotID int64

type BotIDCreator

type BotIDCreator func(*http.Request) (BotID, error)

BotIDCreator is a callback that gets a http request before it is hijacked and upgraded to WebSocket. Its sole job is to identify the bot ID from the request and return it.

type Controller

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

Controller is the main interface to manage and control bots at a particular endpoint. Essentially, you create a Controller object, and set the ConnectionHandler as the request handler for a particular endpoint, and clients connecting to that endpoint will be managed by this object.

func NewController

func NewController(options ...func(*Controller) error) (*Controller, error)

NewController creates a new Controller object. It can take options for specifying the ControllerStore, ConversationStore, BotIDCreator and ErrorHandler.

func (*Controller) BotAdded

func (c *Controller) BotAdded() <-chan *Bot

BotAdded gets a receive only channel that'll get a bot payload whenever a new connection is obtained. You can use this to send messages like "Hi, I'm Online" to new users.

func (*Controller) ConnectionHandler

func (c *Controller) ConnectionHandler() http.HandlerFunc

ConnectionHandler returns a http.HandlerFunc that can be used to intercept and handle connections from clients. It essentially creates a new Bot for each connection, and upgrades the connection to WebSocket.

func (*Controller) Messages

func (c *Controller) Messages() <-chan *MessagePair

Messages returns a receive only channel that will get a bot-message pair every time a new message comes over.

func (*Controller) RegisterConversation

func (c *Controller) RegisterConversation(name string, conv *Conversation) error

RegisterConversation registers a new Conversation with the Controller, so it can be used with bot.StartConversation(name)

type ControllerStore

type ControllerStore interface {
	// Add is supposed to add a new BotID and initialize the ItemStore for the bot.
	// Ideally returns an error if a bot with same ID is already there, or if ItemStore could not be initialized.
	Add(BotID) error

	// Get gets the store for a bot with id BotID, error if no such bot.
	Get(BotID) (ItemStore, error)

	// Remove will remove a bot with specified ID, error if no such bot.
	// Also clears the ItemStore associated with the Bot.
	Remove(BotID) error
}

ControllerStore defines the interface for storing all the bots connected to the app. By default an [in memory implementation](https://godoc.org/suy.io/bots/web#MemoryControllerStore) is used. Implement your own and pass it inside WithControllerStore(https://godoc.org/suy.io/bots/web#WithControllerStore) when initializing a Controller.

type Controls

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

Controls is a data structure passed to conversation handlers to control the current conversational flow, change states, store data, or end the conversation

func (*Controls) Bot

func (c *Controls) Bot() *Bot

Bot gets the bot in the current conversation

func (*Controls) End

func (c *Controls) End() error

End ends the conversation

func (*Controls) Get

func (c *Controls) Get(key string) (string, error)

Get gets the value for a key in the current conversation

func (*Controls) Set

func (c *Controls) Set(key string, value string) error

Set sets the value for a key in the current conversation

func (*Controls) To

func (c *Controls) To(state string) error

To makes a state transition

type Conversation

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

Conversation stores a set of states and ConversationHandler mappings

func NewConversation

func NewConversation() *Conversation

NewConversation creates a new conversation

func (*Conversation) On

func (s *Conversation) On(state string, handler ConversationHandler) error

On adds a new state to the conversation

type ConversationHandler

type ConversationHandler func(msg *Message, controls *Controls)

ConversationHandler is the callback that is invoked for each state in a conversation

type ConversationRegistry

type ConversationRegistry map[string]*Conversation

ConversationRegistry stores a mapping of string ids and conversations

func NewConversationRegistry

func NewConversationRegistry() ConversationRegistry

NewConversationRegistry creates a new registry

func (ConversationRegistry) Add

func (c ConversationRegistry) Add(name string, conv *Conversation) error

Add adds a new conversation with the specified name

func (ConversationRegistry) Get

Get gets the conversation with the specified name

type ConversationStore

type ConversationStore interface {
	Start(bot BotID, id string) error
	IsActive(bot BotID) bool
	Active(bot BotID) (id, state string, err error)
	SetState(bot BotID, state string) error
	SetData(bot BotID, key, value string) error
	GetData(bot BotID, key string) (string, error)
	End(bot BotID) error
}

ConversationStore stores current active conversation data for bots, as well as state data.

type Cursor

type Cursor struct {
	Type ItemType `json:"type"`
	ID   ItemID   `json:"id"`
}

Cursor objects point to the previous and next item for both messages and threads

func (*Cursor) MarshalJSON

func (j *Cursor) MarshalJSON() ([]byte, error)

MarshalJSON marshal bytes to json - template

func (*Cursor) MarshalJSONBuf

func (j *Cursor) MarshalJSONBuf(buf fflib.EncodingBuffer) error

MarshalJSONBuf marshal buff to json - template

func (*Cursor) UnmarshalJSON

func (j *Cursor) UnmarshalJSON(input []byte) error

UnmarshalJSON umarshall json - template of ffjson

func (*Cursor) UnmarshalJSONFFLexer

func (j *Cursor) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error

UnmarshalJSONFFLexer fast json unmarshall - template ffjson

type ErrorHandler

type ErrorHandler func(err error)

ErrorHandler is a function that can be specified to intercept different errors occuring during operation that are not a result of a user action

type Item

type Item interface {
	ItemID() ItemID
	ThreadItemID() ItemID
	ItemType() ItemType
}

Item defines common elements for messages and threads

type ItemID

type ItemID int64

type ItemSource

type ItemSource string

ItemSource field lets a client know if a message is a bot message or a user message

const (
	BotItemSource  ItemSource = "bot"
	UserItemSource ItemSource = "user"
)

type ItemStore

type ItemStore interface {
	// Add a message to a thread, defaults to 0.
	// Once added, the message should have cursors set.
	// You can't add a thread with ID zero, that is reserved to
	// represent messages in global namespace.
	Add(Item) error

	// Get gets a specific item in a specific thread
	Get(ItemID, ItemID) (Item, error)

	// Update updates an existing item
	// returns an error if no item with the id was present
	Update(Item) error
}

ItemStore stores data associated with a single bot.

type ItemType

type ItemType string
const (
	MessageItemType ItemType = "message"
	ThreadItemType  ItemType = "thread"
	UpdateItemType  ItemType = "update"
)

type MemoryControllerStore

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

MemoryControllerStore is an in-memory ControllerStore implementation.

func NewMemoryControllerStore

func NewMemoryControllerStore() *MemoryControllerStore

NewMemoryControllerStore creates a new MemoryControllerStore.

func (*MemoryControllerStore) Add

func (s *MemoryControllerStore) Add(id BotID) error

Add adds a new BotID to the store, and initializes ItemStore for it.

func (*MemoryControllerStore) Get

Get gets a new BotID to the store

func (*MemoryControllerStore) Remove

func (s *MemoryControllerStore) Remove(id BotID) error

Remove removes a bot from the store.

type MemoryConversationStore

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

MemoryConversationStore implements an in memory ConversationStore.

func NewMemoryConversationStore

func NewMemoryConversationStore() *MemoryConversationStore

NewMemoryConversationStore creates a new MemoryConversationStore.

func (*MemoryConversationStore) Active

func (s *MemoryConversationStore) Active(bot BotID) (id, state string, err error)

Active returns conversation id and state for the bot with specified ID.

func (*MemoryConversationStore) End

func (s *MemoryConversationStore) End(bot BotID) error

End ends the active conversation for the current bot.

func (*MemoryConversationStore) GetData

func (s *MemoryConversationStore) GetData(bot BotID, key string) (string, error)

GetData gets data with specified key for the current conversation.

func (*MemoryConversationStore) IsActive

func (s *MemoryConversationStore) IsActive(bot BotID) bool

IsActive returns true of the specified has an active conversation.

func (*MemoryConversationStore) SetData

func (s *MemoryConversationStore) SetData(bot BotID, key, value string) error

SetData sets a key-value pair for the current conversation.

func (*MemoryConversationStore) SetState

func (s *MemoryConversationStore) SetState(bot BotID, state string) error

SetState sets the conversation state for the specified ID.

func (*MemoryConversationStore) Start

func (s *MemoryConversationStore) Start(bot BotID, id string) error

Start starts a conversation of specified ID with the specified Bot.

type MemoryItemStore

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

MemoryItemStore provides a highly inefficient, pretty much incompetent in-memory implementation for an ItemStore.

func NewMemoryItemStore

func NewMemoryItemStore() *MemoryItemStore

NewMemoryItemStore creates a new MemoryItemStore

func (*MemoryItemStore) Add

func (store *MemoryItemStore) Add(item Item) error

Add adds a new item to the current store

func (*MemoryItemStore) All

func (store *MemoryItemStore) All(thread ItemID) ([]Item, error)

All gets all items in a particular thread in this store.

func (*MemoryItemStore) Get

func (store *MemoryItemStore) Get(id, thread ItemID) (Item, error)

Get gets a specific item in a specific thread.

func (*MemoryItemStore) Update

func (store *MemoryItemStore) Update(item Item) error

Update updates an already stored item's data.

type Message

type Message struct {
	Attachments []Attachment `json:"attachments"`
	Source      ItemSource   `json:"source"`
	Type        ItemType     `json:"type"`
	Text        string       `json:"text"`
	ThreadID    ItemID       `json:"threadId"`
	ReplyID     ItemID       `json:"replyId"`
	ID          ItemID       `json:"id"`
	Prev        *Cursor      `json:"prev"`
	Next        *Cursor      `json:"next"`
}

Message defines the contents of a single message sent by the bot

func TextMessage

func TextMessage(text string) *Message

TextMessage is a shorthand function that creates a message from the passed text

func (*Message) ItemID

func (msg *Message) ItemID() ItemID

ItemID gets the ID of the message

func (*Message) ItemType

func (msg *Message) ItemType() ItemType

ItemType gets the type for the message i.e. MessageItemType

func (*Message) MarshalJSON

func (j *Message) MarshalJSON() ([]byte, error)

MarshalJSON marshal bytes to json - template

func (*Message) MarshalJSONBuf

func (j *Message) MarshalJSONBuf(buf fflib.EncodingBuffer) error

MarshalJSONBuf marshal buff to json - template

func (*Message) ThreadItemID

func (msg *Message) ThreadItemID() ItemID

ThreadItemID gets the thread ID of the message

func (*Message) UnmarshalJSON

func (j *Message) UnmarshalJSON(input []byte) error

UnmarshalJSON umarshall json - template of ffjson

func (*Message) UnmarshalJSONFFLexer

func (j *Message) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error

UnmarshalJSONFFLexer fast json unmarshall - template ffjson

type MessagePair

type MessagePair struct {
	*Message
	*Bot
}

MessagePair is the payload sent for DirectMessage Event.

ffjson: skip

func (*MessagePair) Reply

func (mp *MessagePair) Reply(msg *Message)

Reply uses the pair's bot to reply with the passed message

func (*MessagePair) ReplyInThread

func (mp *MessagePair) ReplyInThread(msg *Message)

ReplyInThread uses the pair's bot to reply in a new thread

func (*MessagePair) Update

func (mp *MessagePair) Update()

Update uses the pair's bot to update an existing message.

type Thread

type Thread struct {
	Type     ItemType `json:"type"`
	ThreadID ItemID   `json:"threadId"`
	ID       ItemID   `json:"id"`
	Prev     *Cursor  `json:"prev"`
	Next     *Cursor  `json:"next"`
}

Thread defines a single messaging thread, which contains messages in itself

func (*Thread) ItemID

func (t *Thread) ItemID() ItemID

ItemID returns the id of the thread

func (*Thread) ItemType

func (t *Thread) ItemType() ItemType

ItemType returns ThreadItemType for a thread

func (*Thread) MarshalJSON

func (j *Thread) MarshalJSON() ([]byte, error)

MarshalJSON marshal bytes to json - template

func (*Thread) MarshalJSONBuf

func (j *Thread) MarshalJSONBuf(buf fflib.EncodingBuffer) error

MarshalJSONBuf marshal buff to json - template

func (*Thread) ThreadItemID

func (t *Thread) ThreadItemID() ItemID

ThreadItemID returns the id of the parent thread for this thread

func (*Thread) UnmarshalJSON

func (j *Thread) UnmarshalJSON(input []byte) error

UnmarshalJSON umarshall json - template of ffjson

func (*Thread) UnmarshalJSONFFLexer

func (j *Thread) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error

UnmarshalJSONFFLexer fast json unmarshall - template ffjson

Directories

Path Synopsis
contrib

Jump to

Keyboard shortcuts

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