go-sarah: github.com/oklahomer/go-sarah Index | Files | Directories

package sarah

import "github.com/oklahomer/go-sarah"

Package sarah is a general purpose bot framework that comes with set of utility packages.

Index

Package Files

adapter.go alert.go bot.go bottype.go command.go destination.go doc.go error.go input.go locker.go output.go runner.go scheduler.go status.go storage.go task.go watcher.go

Variables

var (
    // ErrTaskInsufficientArgument is returned when required parameters are not set.
    ErrTaskInsufficientArgument = xerrors.New("one or more of required fields -- BotType, Identifier or Func -- are empty")

    // ErrTaskScheduleNotGiven is returned when schedule is provided by neither ScheduledTaskPropsBuilder's parameter nor config.
    ErrTaskScheduleNotGiven = xerrors.New("task schedule is not set or given from config struct")
)
var ErrAlreadySubscribing = xerrors.New("already subscribing")

ErrAlreadySubscribing is returned when duplicated calls to ConfigWatcher.Watch() occur.

var (
    // ErrCommandInsufficientArgument depicts an error that not enough arguments are set to CommandProps.
    // This is returned on CommandProps.Build() inside of runner.Run()
    ErrCommandInsufficientArgument = xerrors.New("BotType, Identifier, InstructionFunc, MatchFunc and (Configurable)Func must be set.")
)
var ErrRunnerAlreadyRunning = xerrors.New("go-sarah's process is already running")

ErrRunnerAlreadyRunning indicates that sarah.Run() is already called and the process is already running. When this is returned, a second or later activations are prevented so the initially activated process is still protected.

var ErrWatcherNotRunning = xerrors.New("context is already canceled")

ErrWatcherNotRunning is returned when ConfigWatcher.Unwatch() is called but the context is already canceled.

func NewBlockedInputError Uses

func NewBlockedInputError(i int) error

NewBlockedInputError creates and return new BlockedInputError instance.

func NewBotNonContinuableError Uses

func NewBotNonContinuableError(errorContent string) error

NewBotNonContinuableError creates and return new BotNonContinuableError instance.

func RegisterAlerter Uses

func RegisterAlerter(alerter Alerter)

RegisterAlerter registers given sarah.Alerter implementation. When registered sarah.Bot implementation encounters critical state, given alerter is called to notify such state.

func RegisterBot Uses

func RegisterBot(bot Bot)

RegisterBot registers given sarah.Bot implementation to be run on sarah.Run(). This may be called multiple times to register as many bot instances as wanted. When a Bot with same sarah.BotType is already registered, this returns error on sarah.Run().

func RegisterBotErrorSupervisor Uses

func RegisterBotErrorSupervisor(fnc func(BotType, error) *SupervisionDirective)

RegisterBotErrorSupervisor registers a given supervising function that is called when a Bot escalates an error. This function judges if the given error is worth being notified to administrators and if the Bot should stop. A developer may return *SupervisionDirective to tell such order. If the escalated error can simply be ignored, a nil value can be returned.

Bot/Adapter can escalate an error via a function, func(error), that is passed to Run() as a third argument. When BotNonContinuableError is escalated, go-sarah's core cancels failing Bot's context and thus the Bot and related resources stop working. If one or more sarah.Alerters implementations are registered, such critical error is passed to the alerters and administrators will be notified. When other types of error are escalated, the error is passed to the supervising function registered via sarah.RegisterBotErrorSupervisor(). The function may return *SupervisionDirective to tell how go-sarah's core should react.

Bot/Adapter's implementation should be simple. It should not handle serious errors by itself. Instead, it should simply escalate an error every time when a noteworthy error occurs and let core judge how to react. For example, if the bot should stop when three reconnection trial fails in ten seconds, the scenario could be somewhat like below:

1. Bot escalates reconnection error, FooReconnectionFailureError, each time it fails to reconnect
2. Supervising function counts the error and ignores the first two occurrence
3. When the third error comes within ten seconds from the initial error escalation, return *SupervisionDirective with StopBot value of true

Similarly, if there should be a rate limiter to limit the calls to alerters, the supervising function should take care of this instead of the failing Bot. Each Bot/Adapter's implementation can be kept simple in this way. go-sarah's core should always supervise and control its belonging Bots.

func RegisterCommand Uses

func RegisterCommand(botType BotType, command Command)

RegisterCommand registers given sarah.Command. On sarah.Run(), Commands are registered to corresponding bot via Bot.AppendCommand().

func RegisterCommandProps Uses

func RegisterCommandProps(props *CommandProps)

RegisterCommandProps registers given sarah.CommandProps to build sarah.Command on sarah.Run(). This props is re-used when configuration file is updated and a corresponding sarah.Command needs to be re-built.

func RegisterConfigWatcher Uses

func RegisterConfigWatcher(watcher ConfigWatcher)

RegisterConfigWatcher registers given ConfigWatcher implementation.

func RegisterScheduledTask Uses

func RegisterScheduledTask(botType BotType, task ScheduledTask)

RegisterScheduledTask registers given sarah.ScheduledTask. On sarah.Run(), schedule is set for this task.

func RegisterScheduledTaskProps Uses

func RegisterScheduledTaskProps(props *ScheduledTaskProps)

RegisterScheduledTaskProps registers given sarah.ScheduledTaskProps to build sarah.ScheduledTask on sarah.Run(). This props is re-used when configuration file is updated and a corresponding sarah.ScheduledTask needs to be re-built.

func RegisterWorker Uses

func RegisterWorker(worker workers.Worker)

RegisterWorker registers given workers.Worker implementation. When this is not called, a worker instance with default setting is used.

func Run Uses

func Run(ctx context.Context, config *Config) error

Run is a non-blocking function that starts running go-sarah's process with pre-registered options. Workers, schedulers and other required resources for bot interaction starts running on this function call. This returns error when bot interaction cannot start; No error is returned when process starts successfully.

Refer to ctx.Done() or sarah.CurrentStatus() to reference current running status.

To control its lifecycle, a developer may cancel ctx to stop go-sarah at any moment. When bot interaction stops unintentionally without such context cancellation, the critical state is notified to administrators via registered sarah.Alerter. This is recommended to register multiple sarah.Alerter implementations to make sure critical states are notified.

func StripMessage Uses

func StripMessage(pattern *regexp.Regexp, input string) string

StripMessage is a utility function that strips string from given message based on given regular expression. This is to extract usable input value out of entire user message. e.g. ".echo Hey!" becomes "Hey!"

type AbortInput Uses

type AbortInput struct {
    OriginalInput Input
    // contains filtered or unexported fields
}

AbortInput is a common Input implementation that represents user's request for context cancellation. When this type is given, each Bot/Adapter implementation should cancel and remove corresponding user's conversational context.

func NewAbortInput Uses

func NewAbortInput(input Input) *AbortInput

NewAbortInput creates a new AbortInput instance with given input. When this type is given, each Bot/Adapter implementation should cancel the user's conversational context.

func (*AbortInput) Message Uses

func (ai *AbortInput) Message() string

Message returns sent message.

func (*AbortInput) ReplyTo Uses

func (ai *AbortInput) ReplyTo() OutputDestination

ReplyTo returns slack channel to send reply to.

func (*AbortInput) SenderKey Uses

func (ai *AbortInput) SenderKey() string

SenderKey returns string representing message sender.

func (*AbortInput) SentAt Uses

func (ai *AbortInput) SentAt() time.Time

SentAt returns message event's timestamp.

type Adapter Uses

type Adapter interface {
    // BotType represents what this Bot implements. e.g. slack, gitter, cli, etc...
    // This can be used as a unique ID to distinguish one from another.
    BotType() BotType

    // Run is called on Runner.Run by wrapping bot instance.
    // On this call, start interacting with corresponding service provider.
    // This may run in a blocking manner til given context is canceled since a new goroutine is allocated for this task.
    // When the service provider sends message to us, convert that message payload to Input and send to Input channel.
    // Runner will receive the Input instance and proceed to find and execute corresponding command.
    Run(context.Context, func(Input) error, func(error))

    // SendMessage sends message to corresponding service provider.
    // This can be called by scheduled task or in response to input from service provider.
    // Be advised: this method may be called simultaneously from multiple workers.
    SendMessage(context.Context, Output)
}

Adapter defines interface that each bot adapter implementation has to satisfy. Instance of its concrete struct and series of sarah.DefaultBotOptions can be fed to defaultBot via sarah.NewBot() to have sarah.Bot. Returned bot instance can be fed to Runner to have its life cycle managed.

type Alerter Uses

type Alerter interface {
    // Alert sends notification to developer/administrator so one may notify Bot's critical state.
    Alert(context.Context, BotType, error) error
}

Alerter can be used to report Bot's critical state to developer/administrator. Anything that implements this interface can be registered as Alerter via Runner.RegisterAlerter.

type BlockedInputError Uses

type BlockedInputError struct {
    ContinuationCount int
}

BlockedInputError indicates incoming input is blocked due to lack of resource. Excessive increase in message volume may result in this error. When this error occurs, Runner does not wait to enqueue input, but just skip the overflowing message and proceed.

Possible cure includes having more workers and/or more worker queue size, but developers MUST aware that this modification may cause more concurrent Command.Execute and Bot.SendMessage operation. With that said, increase workers by setting bigger number to worker.Config.WorkerNum to allow more concurrent executions and minimize the delay; increase worker queue size by setting bigger number to worker.Config.QueueSize to allow delay and have same concurrent execution number.

func (BlockedInputError) Error Uses

func (e BlockedInputError) Error() string

Error returns the detailed error about this blocking situation including the number of continuous occurrence. Do err.(*BlockedInputError).ContinuationCount to get the number of continuous occurrence. e.g. log if the remainder of this number divided by N is 0 to avoid excessive logging.

type Bot Uses

type Bot interface {
    // BotType represents what this Bot implements. e.g. slack, gitter, cli, etc...
    // This can be used as a unique ID to distinguish one from another.
    BotType() BotType

    // Respond receives user input, look for the corresponding command, execute it, and send the result back to the user if possible.
    Respond(context.Context, Input) error

    // SendMessage sends given message to the destination depending on the Bot implementation.
    // This is mainly used to send scheduled task's result.
    // Be advised: this method may be called simultaneously from multiple workers.
    SendMessage(context.Context, Output)

    // AppendCommand appends given Command implementation to Bot internal stash.
    // Stashed commands are checked against user input in Bot.Respond, and if Command.Match returns true, the
    // Command is considered as "corresponds" to the input, hence its Command.Execute is called and the result is
    // sent back to the user.
    AppendCommand(Command)

    // Run is called on sarah.Run() to let this Bot start interacting with corresponding service provider.
    // When the service provider sends a message to us, convert that message payload to sarah.Input and send to inputReceiver.
    // An internal worker will receive the Input instance and proceed to find and execute the corresponding command.
    // The worker is managed by go-sarah's core; Bot/Adapter developers do not have to worry about implementing one.
    //
    // sarah.Run() allocates a new goroutine for each bot so this method can block til interaction ends.
    // When this method returns, the interaction is considered finished.
    //
    // The bot lifecycle is entirely managed by go-sarah's core.
    // On critical situation, notify such event via notifyErr and let go-sarah's core handle the error.
    // When the bot is indeed in a critical state and cannot proceed further operation, ctx is canceled by go-sarah.
    // Bot/Adapter developers may listen to this ctx.Done() to clean up its internal resources.
    Run(ctx context.Context, inputReceiver func(Input) error, notifyErr func(error))
}

Bot provides an interface that each bot implementation must satisfy. Instance of concrete type can be registered via sarah.RegisterBot() to have its lifecycle under control. Multiple Bot implementation may be registered by multiple sarah.RegisterBot() calls.

func NewBot Uses

func NewBot(adapter Adapter, options ...DefaultBotOption) (Bot, error)

NewBot creates and returns new defaultBot instance with given Adapter. While Adapter takes care of actual collaboration with each chat service provider, defaultBot takes care of some common tasks including:

- receive Input
- see if sending user is in the middle of conversational context
  - if so, execute the next step with given Input
  - if not, find corresponding Command for given Input and execute it
- call Adapter.SendMessage to send output

The aim of defaultBot is to lessen the tasks of Adapter developer by providing some common tasks' implementations, and achieve easier creation of Bot implementation. Hence this method returns Bot interface instead of any concrete instance so this can be ONLY treated as Bot implementation to be fed to Runner.RegisterBot.

Some optional settings can be supplied by passing sarah.WithStorage and others that return DefaultBotOption.

// Use pre-defined storage.
storage := sarah.NewUserContextStorage(sarah.NewCacheConfig())
bot, err := sarah.NewBot(myAdapter, sarah.WithStorage(sarah.NewUserContextStorage(sarah.NewCacheConfig())))

It is highly recommended to provide concrete implementation of sarah.UserContextStorage, so the users' conversational context can be stored and executed on next Input. sarah.userContextStorage is provided by default to store user context in memory. This storage can be initialized by sarah.NewUserContextStorage like above example.

type BotNonContinuableError Uses

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

BotNonContinuableError represents critical error that Bot can't continue its operation. When Runner receives this, it must stop corresponding Bot, and should inform administrator by available mean.

func (BotNonContinuableError) Error Uses

func (e BotNonContinuableError) Error() string

Error returns detailed error about Bot's non-continuable state.

type BotStatus Uses

type BotStatus struct {
    Type    BotType
    Running bool
}

BotStatus represents the current status of a Bot.

type BotType Uses

type BotType string

BotType indicates what bot implementation a particular Bot/Plugin is corresponding to.

func (BotType) String Uses

func (botType BotType) String() string

String returns a stringified form of BotType

type CacheConfig Uses

type CacheConfig struct {
    ExpiresIn       time.Duration `json:"expires_in" yaml:"expires_in"`
    CleanupInterval time.Duration `json:"cleanup_interval" yaml:"cleanup_interval"`
}

CacheConfig contains some configuration variables for cache mechanism.

func NewCacheConfig Uses

func NewCacheConfig() *CacheConfig

NewCacheConfig creates and returns new CacheConfig instance with default settings. Use json.Unmarshal, yaml.Unmarshal, or manual manipulation to overload default values.

type Command Uses

type Command interface {
    // Identifier returns unique id that represents this Command.
    Identifier() string

    // Execute receives input from user and returns response.
    Execute(context.Context, Input) (*CommandResponse, error)

    // Instruction returns example of user input. This should be used to provide command usage for end users.
    Instruction(input *HelpInput) string

    // Match is used to judge if this command corresponds to given user input.
    // If this returns true, Bot implementation should proceed to Execute with current user input.
    Match(Input) bool
}

Command defines interface that all command MUST satisfy.

type CommandConfig Uses

type CommandConfig interface{}

CommandConfig provides an interface that every command configuration must satisfy, which actually means empty.

type CommandHelp Uses

type CommandHelp struct {
    Identifier  string
    Instruction string
}

CommandHelp represents help messages for corresponding Command.

type CommandHelps Uses

type CommandHelps []*CommandHelp

CommandHelps is an alias to slice of CommandHelps' pointers.

type CommandProps Uses

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

CommandProps is a designated non-serializable configuration struct to be used in Command construction. This holds relatively complex set of Command construction arguments that should be treated as one in logical term.

type CommandPropsBuilder Uses

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

CommandPropsBuilder helps to construct CommandProps. Developer may set desired property as she goes and call CommandPropsBuilder.Build or CommandPropsBuilder.MustBuild to construct CommandProps at the end. A validation logic runs on build, so the returning CommandProps instant is safe to be passed to Runner.

func NewCommandPropsBuilder Uses

func NewCommandPropsBuilder() *CommandPropsBuilder

NewCommandPropsBuilder returns new CommandPropsBuilder instance.

func (*CommandPropsBuilder) BotType Uses

func (builder *CommandPropsBuilder) BotType(botType BotType) *CommandPropsBuilder

BotType is a setter to provide belonging BotType.

func (*CommandPropsBuilder) Build Uses

func (builder *CommandPropsBuilder) Build() (*CommandProps, error)

Build builds new CommandProps instance with provided values.

func (*CommandPropsBuilder) ConfigurableFunc Uses

func (builder *CommandPropsBuilder) ConfigurableFunc(config CommandConfig, fn func(context.Context, Input, CommandConfig) (*CommandResponse, error)) *CommandPropsBuilder

ConfigurableFunc is a setter to provide command function. While Func let developers set simple function, this allows them to provide function that requires some sort of configuration struct. On Runner.Run configuration is read from YAML/JSON file located at /path/to/config/dir/{commandIdentifier}.(yaml|yml|json) and mapped to given CommandConfig struct. If no YAML/JSON file is found, runner considers the given CommandConfig is fully configured and ready to use. This configuration struct is passed to command function as its third argument.

func (*CommandPropsBuilder) Func Uses

func (builder *CommandPropsBuilder) Func(fn func(context.Context, Input) (*CommandResponse, error)) *CommandPropsBuilder

Func is a setter to provide command function that requires no configuration. If ConfigurableFunc and Func are both called, later call overrides the previous one.

func (*CommandPropsBuilder) Identifier Uses

func (builder *CommandPropsBuilder) Identifier(id string) *CommandPropsBuilder

Identifier is a setter for Command identifier.

func (*CommandPropsBuilder) Instruction Uses

func (builder *CommandPropsBuilder) Instruction(instruction string) *CommandPropsBuilder

Instruction is a setter to provide an instruction of command execution. This should be used to provide command usage for end users.

func (*CommandPropsBuilder) InstructionFunc Uses

func (builder *CommandPropsBuilder) InstructionFunc(fnc func(input *HelpInput) string) *CommandPropsBuilder

InstructionFunc is a setter to provide a function that receives user input and returns instruction. Use Instruction() when a simple text instruction can always be returned. If the instruction has to be customized per user or the instruction has to be hidden in a certain group or from a certain user, use InstructionFunc(). Use receiving *HelpInput and judge if an instruction should be returned. e.g. .reboot command is only supported for administrator users in admin group so this command should be hidden in other groups.

Also see MatchFunc() for such authentication mechanism.

func (*CommandPropsBuilder) MatchFunc Uses

func (builder *CommandPropsBuilder) MatchFunc(matchFunc func(Input) bool) *CommandPropsBuilder

MatchFunc is a setter to provide a function that judges if an incoming input "matches" to this Command. When this returns true, this Command is considered as "corresponding to user input" and becomes Command execution candidate.

MatchPattern may be used to specify a regular expression that is checked against user input, Input.Message(); MatchFunc can specify more customizable matching logic. e.g. only return true on specific sender's specific message on specific time range.

func (*CommandPropsBuilder) MatchPattern Uses

func (builder *CommandPropsBuilder) MatchPattern(pattern *regexp.Regexp) *CommandPropsBuilder

MatchPattern is a setter to provide command match pattern. This regular expression is used to find matching command with given Input.

Use MatchFunc to set more customizable matching logic.

func (*CommandPropsBuilder) MustBuild Uses

func (builder *CommandPropsBuilder) MustBuild() *CommandProps

MustBuild is like Build but panics if any error occurs on Build. It simplifies safe initialization of global variables holding built CommandProps instances.

type CommandResponse Uses

type CommandResponse struct {
    Content     interface{}
    UserContext *UserContext
}

CommandResponse is returned by Command or Task when the execution is finished.

func NewSuppressedResponseWithNext Uses

func NewSuppressedResponseWithNext(next ContextualFunc) *CommandResponse

NewSuppressedResponseWithNext creates new sarah.CommandResponse instance with no message and next function to continue

type Commands Uses

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

Commands stashes all registered Command.

func NewCommands Uses

func NewCommands() *Commands

NewCommands creates and returns new Commands instance.

func (*Commands) Append Uses

func (commands *Commands) Append(command Command)

Append let developers register new Command to its internal stash. If any command is registered with the same ID, the old one is replaced in favor of new one.

func (*Commands) ExecuteFirstMatched Uses

func (commands *Commands) ExecuteFirstMatched(ctx context.Context, input Input) (*CommandResponse, error)

ExecuteFirstMatched tries find matching command with the given input, and execute it if one is available.

func (*Commands) FindFirstMatched Uses

func (commands *Commands) FindFirstMatched(input Input) Command

FindFirstMatched look for first matching command by calling Command's Match method: First Command.Match to return true is considered as "first matched" and is returned.

This check is run in the order of Command registration: Earlier the Commands.Append is called, the command is checked earlier. So register important Command first.

func (*Commands) Helps Uses

func (commands *Commands) Helps(input *HelpInput) *CommandHelps

Helps returns underlying commands help messages in a form of *CommandHelps.

type Config Uses

type Config struct {
    TimeZone string `json:"timezone" yaml:"timezone"`
}

Config contains some basic configuration variables for go-sarah.

func NewConfig Uses

func NewConfig() *Config

NewConfig creates and returns new Config instance with default settings. Use json.Unmarshal, yaml.Unmarshal, or manual manipulation to override default values.

type ConfigNotFoundError Uses

type ConfigNotFoundError struct {
    BotType BotType
    ID      string
}

ConfigNotFoundError is returned when corresponding configuration is not found. This is typically returned when the caller tries to see if there is any configuration available via ConfigWatcher.Read().

func (*ConfigNotFoundError) Error Uses

func (err *ConfigNotFoundError) Error() string

Error returns stringified representation of the error.

type ConfigWatcher Uses

type ConfigWatcher interface {
    // Read reads the latest configuration value and apply that value to configPtr.
    Read(botCtx context.Context, botType BotType, id string, configPtr interface{}) error
    // Watch subscribes to given id's configuration.
    // When a change to the corresponding configuration value occurs, callback is called.
    // A call to callback function triggers go-sarah's core to call Read() to reflect the latest configuration value.
    Watch(botCtx context.Context, botType BotType, id string, callback func()) error
    // Unwatch is called when Bot is stopped and subscription is no longer required.
    Unwatch(botType BotType) error
}

ConfigWatcher provides an interface for such a component that subscribes to any changes for configuration value of Command and ScheduledTask. One example could be watchers.fileWatcher that subscribes to directory changes: while another reference implementation to subscribe changes on GitHub repository is hosted at https://github.com/oklahomer/go-sarah-githubconfig .

type ContextualFunc Uses

type ContextualFunc func(context.Context, Input) (*CommandResponse, error)

ContextualFunc defines a function signature that defines user's next step. When a function or instance method is given as CommandResponse.Next, Bot implementation must store this with Input.SenderKey. On user's next input, inside of Bot.Respond, Bot retrieves stored ContextualFunc and execute this. If CommandResponse.Next is given again as part of result, the same step must be followed.

type DefaultBotOption Uses

type DefaultBotOption func(bot *defaultBot)

DefaultBotOption defines function that defaultBot's functional option must satisfy.

func BotWithStorage Uses

func BotWithStorage(storage UserContextStorage) DefaultBotOption

BotWithStorage creates and returns DefaultBotOption to set preferred UserContextStorage implementation. Below example utilizes pre-defined in-memory storage.

config := sarah.NewCacheConfig()
configBuf, _ := ioutil.ReadFile("/path/to/storage/config.yaml")
yaml.Unmarshal(configBuf, config)
bot, err := sarah.NewBot(myAdapter, storage)

type DestinatedConfig Uses

type DestinatedConfig interface {
    DefaultDestination() OutputDestination
}

DestinatedConfig defines an interface that config with default destination MUST satisfy. When no default output destination is set with ScheduledTaskPropsBuilder.DefaultDestination, this value is taken as default on ScheduledTaskPropsBuilder.Build.

type HelpInput Uses

type HelpInput struct {
    OriginalInput Input
    // contains filtered or unexported fields
}

HelpInput is a common Input implementation that represents user's request for help. When this type is given, each Bot/Adapter implementation should list up registered Commands' instructions and send them back to user.

func NewHelpInput Uses

func NewHelpInput(input Input) *HelpInput

NewHelpInput creates a new HelpInput instance with given user input and returns it. This is Bot/Adapter's responsibility to receive an input from user, convert it to sarah.Input and see if the input requests for "help." For example, a slack adapter may check if the given message is equal to :help: emoji. If true, create a HelpInput instant with NewHelpInput and pass it to go-sarah's core.

func (*HelpInput) Message Uses

func (hi *HelpInput) Message() string

Message returns sent message.

func (*HelpInput) ReplyTo Uses

func (hi *HelpInput) ReplyTo() OutputDestination

ReplyTo returns slack channel to send reply to.

func (*HelpInput) SenderKey Uses

func (hi *HelpInput) SenderKey() string

SenderKey returns string representing message sender.

func (*HelpInput) SentAt Uses

func (hi *HelpInput) SentAt() time.Time

SentAt returns message event's timestamp.

type Input Uses

type Input interface {
    // SenderKey returns the text form of sender identifier.
    // This value can be used internally as a key to store the sender's conversational context in UserContextStorage.
    // Generally, When connecting chat service has the concept of group or chat room,
    // this sender key should contain the group/room identifier along with user identifier
    // so the user's conversational context is only applied in the exact same group/room.
    //
    // e.g. senderKey := fmt.Sprintf("%d_%d", roomID, userID)
    SenderKey() string

    // Message returns the text form of user input.
    // This may return empty string when this Input implementation represents non-text payload such as photo,
    // video clip or file.
    Message() string

    // SentAt returns the timestamp when the message is sent.
    // This may return a message reception time if the connecting chat service does not provide one.
    // e.g. XMPP server only provides timestamp as part of XEP-0203 when delayed message is delivered.
    SentAt() time.Time

    // ReplyTo returns the sender's address or location to be used to reply message.
    // This may be passed to Bot.SendMessage() as part of Output value to specify the sending destination.
    // This typically contains chat room, member id or mail address.
    // e.g. JID of XMPP server/client.
    ReplyTo() OutputDestination
}

Input defines interface that each incoming message must satisfy. Each Bot/Adapter implementation may define customized Input implementation for each messaging content.

See slack.MessageInput.

type Output Uses

type Output interface {
    Destination() OutputDestination
    Content() interface{}
}

Output defines interface that each outgoing message must satisfy.

func NewOutputMessage Uses

func NewOutputMessage(destination OutputDestination, content interface{}) Output

NewOutputMessage creates and returns new OutputMessage instance. This satisfies Output interface so can be passed to Bot.SendMessage.

type OutputDestination Uses

type OutputDestination interface{}

OutputDestination defines interface that every Bot/Adapter MUST satisfy to represent where the sending message is heading to, which actually means empty interface.

type OutputMessage Uses

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

OutputMessage represents outgoing message.

func (*OutputMessage) Content Uses

func (output *OutputMessage) Content() interface{}

Content returns sending content. This is just an empty interface, so each Bot/Adapter developer may define depending on whatever the struct should contain.

func (*OutputMessage) Destination Uses

func (output *OutputMessage) Destination() OutputDestination

Destination returns its destination in a form of OutputDestination interface. Each Bot/Adapter implementation must explicitly define destination type that satisfies OutputDestination.

type ScheduledConfig Uses

type ScheduledConfig interface {
    Schedule() string
}

ScheduledConfig defines an interface that config with schedule MUST satisfy. When no execution schedule is set with ScheduledTaskPropsBuilder.Schedule, this value is taken as default on ScheduledTaskPropsBuilder.Build.

type ScheduledTask Uses

type ScheduledTask interface {
    Identifier() string
    Execute(context.Context) ([]*ScheduledTaskResult, error)
    DefaultDestination() OutputDestination
    Schedule() string
}

ScheduledTask defines interface that all scheduled task MUST satisfy. As long as a struct satisfies this interface, the struct can be registered as ScheduledTask via Runner.RegisterScheduledTask.

type ScheduledTaskProps Uses

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

ScheduledTaskProps is a designated non-serializable configuration struct to be used in ScheduledTask construction. This holds relatively complex set of ScheduledTask construction arguments that should be treated as one in logical term.

type ScheduledTaskPropsBuilder Uses

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

ScheduledTaskPropsBuilder helps to construct ScheduledTaskProps. Developer may set desired property as she goes and call ScheduledTaskPropsBuilder.Build or ScheduledTaskPropsBuilder.MustBuild to construct ScheduledTaskProps at the end. A validation logic runs on build, so the returning ScheduledTaskProps instant is safe to be passed to Runner.

func NewScheduledTaskPropsBuilder Uses

func NewScheduledTaskPropsBuilder() *ScheduledTaskPropsBuilder

NewScheduledTaskPropsBuilder creates and returns ScheduledTaskPropsBuilder instance.

func (*ScheduledTaskPropsBuilder) BotType Uses

func (builder *ScheduledTaskPropsBuilder) BotType(botType BotType) *ScheduledTaskPropsBuilder

BotType is a setter to provide belonging BotType.

func (*ScheduledTaskPropsBuilder) Build Uses

func (builder *ScheduledTaskPropsBuilder) Build() (*ScheduledTaskProps, error)

Build builds new ScheduledProps instance with provided values.

func (*ScheduledTaskPropsBuilder) ConfigurableFunc Uses

func (builder *ScheduledTaskPropsBuilder) ConfigurableFunc(config TaskConfig, fn func(context.Context, TaskConfig) ([]*ScheduledTaskResult, error)) *ScheduledTaskPropsBuilder

ConfigurableFunc sets function for ScheduledTask with configuration struct. Passed configuration struct is passed to function as a third argument.

When resulting ScheduledTaskProps is passed to sarah.NewRunner() as part of sarah.WithScheduledTaskProps and Runner runs with Config.PluginConfigRoot, configuration struct gets updated automatically when corresponding configuration file is updated.

func (*ScheduledTaskPropsBuilder) DefaultDestination Uses

func (builder *ScheduledTaskPropsBuilder) DefaultDestination(dest OutputDestination) *ScheduledTaskPropsBuilder

DefaultDestination sets default output destination of this task. OutputDestination returned by task execution has higher priority.

func (*ScheduledTaskPropsBuilder) Func Uses

func (builder *ScheduledTaskPropsBuilder) Func(fn func(context.Context) ([]*ScheduledTaskResult, error)) *ScheduledTaskPropsBuilder

Func sets function to be called on task execution. To set function that requires some sort of configuration struct, use ConfigurableFunc.

func (*ScheduledTaskPropsBuilder) Identifier Uses

func (builder *ScheduledTaskPropsBuilder) Identifier(id string) *ScheduledTaskPropsBuilder

Identifier sets unique ID of this task. This is used to identify re-configure tasks and replace old ones.

func (*ScheduledTaskPropsBuilder) MustBuild Uses

func (builder *ScheduledTaskPropsBuilder) MustBuild() *ScheduledTaskProps

MustBuild is like Build, but panics if any error occurs on Build. It simplifies safe initialization of global variables holding built ScheduledTaskProps instances.

func (*ScheduledTaskPropsBuilder) Schedule Uses

func (builder *ScheduledTaskPropsBuilder) Schedule(schedule string) *ScheduledTaskPropsBuilder

Schedule sets execution schedule. Representation spec. is identical to that of github.com/robfig/cron.

type ScheduledTaskResult Uses

type ScheduledTaskResult struct {
    Content     interface{}
    Destination OutputDestination
}

ScheduledTaskResult is a struct that ScheduledTask returns on its execution.

type SerializableArgument Uses

type SerializableArgument struct {
    FuncIdentifier string
    Argument       interface{}
}

SerializableArgument defines user context data to be stored in external storage. This data is read from storage on next user input, deserialized, and executed to continue previous conversation.

type Status Uses

type Status struct {
    Running bool
    Bots    []BotStatus
}

Status represents the current status of the bot system including Runner and all registered Bots.

func CurrentStatus Uses

func CurrentStatus() Status

CurrentStatus returns the current status of go-sarah. This can still be called even if sarah.Run() is not called, yet. So developers can safely build two different goroutines:

- One to setup bot configuration and call sarah.Run()
- Another to periodically call sarah.CurrentStatus() and monitor status.
  When Status.Running is false and Status.Bots is empty, then bot is not initiated yet.

type SupervisionDirective Uses

type SupervisionDirective struct {
    // StopBot tells the core to stop the failing Bot and cleanup related resources.
    // When two or more Bots are registered and one or more Bots are to be still running after the failing Bot stops,
    // internal workers and scheduler keep running.
    //
    // When all Bots stop, then the core stops all resources.
    StopBot bool
    // AlertingErr is sent registered alerters and administrators will be notified.
    // Set nil when such alert notification is not required.
    AlertingErr error
}

SupervisionDirective tells go-sarah's core how to react when a Bot escalates an error. A customized supervisor can be defined and registered via RegisterBotErrorSupervisor().

type TaskConfig Uses

type TaskConfig interface{}

TaskConfig provides an interface that every task configuration must satisfy, which actually means empty.

type UserContext Uses

type UserContext struct {
    // Next contains a function to be called on next user input.
    // Default implementation of UserContextStorage, defaultUserContextStorage, uses this to store conversational contexts.
    //
    // Since this is a plain function, this is stored in the exact same memory space the Bot is currently running,
    // which means this function can not be shared with other Bot instance or can not be stored in external storage such as Redis.
    // To store user context in externally, set Serializable to store serialized arguments in external storage.
    Next ContextualFunc

    // Serializable, on the other hand, contains arguments and function identifier to be stored in external storage.
    // When user input is given next time, serialized SerializableArgument is fetched from storage, deserialized, and fed to pre-registered function.
    // Pre-registered function is identified by SerializableArgument.FuncIdentifier.
    // A reference implementation is available at https://github.com/oklahomer/go-sarah-rediscontext
    Serializable *SerializableArgument
}

UserContext represents a user's conversational context. If this is returned as part of CommandResponse, user is considered "in the middle of conversation," which means the next input of the user MUST be fed to a function declared in UserContext to continue the conversation. This has higher priority than finding and executing Command by checking Command.Match against Input.

Currently this structure supports two forms of context storage. See GitHub issue, https://github.com/oklahomer/go-sarah/issues/34, for detailed motives.

func NewUserContext Uses

func NewUserContext(next ContextualFunc) *UserContext

NewUserContext creates and returns new UserContext with given ContextualFunc. Once this instance is stored in Bot's internal storage, the next input from the same user must be fed to this ContextualFunc so the conversation continues.

type UserContextStorage Uses

type UserContextStorage interface {
    Get(string) (ContextualFunc, error)
    Set(string, *UserContext) error
    Delete(string) error
    Flush() error
}

UserContextStorage defines an interface of Bot's storage mechanism for users' conversational contexts.

func NewUserContextStorage Uses

func NewUserContextStorage(config *CacheConfig) UserContextStorage

NewUserContextStorage creates and returns new defaultUserContextStorage instance to store users' conversational contexts.

Directories

PathSynopsis
alerterPackage alerter and its sub packages provide alerting mechanisms that implement sarah.Alerter interface to inform bot's critical states to administrator.
alerter/linePackage line provides sarah.Alerter implementation for LINE Notify.
examples/simplePackage main provides a simple bot experience using slack.Adapter with multiple plugin commands and scheduled tasks.
examples/simple/plugins/countPackage count provides example code to setup sarah.CommandProps.
examples/simple/plugins/echoPackage echo provides example code to sarah.Command implementation.
examples/simple/plugins/fixedtimerPackage fixedtimer provides example code to setup ScheduledTaskProps with fixed schedule.
examples/simple/plugins/guessPackage guess provides example code to setup stateful command.
examples/simple/plugins/helloPackage hello provides example code to setup relatively simple sarah.CommandProps.
examples/simple/plugins/morningPackage morning provides example code to setup sarah.CommandProps with relatively complex matching function.
examples/simple/plugins/timerPackage timer provides example code to setup ScheduledTaskProps with re-configurable schedule and sending room.
examples/simple/plugins/todoPackage todo is an example of stateful command that let users input required arguments step by step in a conversational manner.
examples/simple/plugins/worldweatherPackage worldweather is a reference implementation that provides relatively practical use of sarah.CommandProps.
examples/statusPackage main provides an example that uses sarah.CurrentStatus() to get current go-sarah and its belonging Bot's status via HTTP server.
gitterPackage gitter provides sarah.Adapter implementation for gitter.
logPackage log provides logging mechanism including replaceable Logger interface and its default implementation.
retryPackage retry provides general retry logic and designated error structure that contains multiple errors.
slackPackage slack provides sarah.Adapter implementation for Slack.
watchers
workersPackage workers provides general purpose worker mechanism that outputs stacktrace when given job panics.

Package sarah imports 13 packages (graph). Updated 2019-10-22. Refresh now. Tools for package owners.