Documentation ¶
Overview ¶
Package sarah is a general purpose bot framework that comes with set of utility packages.
Index ¶
- Variables
- func NewBlockedInputError(i int) error
- func NewBotNonContinuableError(errorContent string) error
- func RegisterAlerter(alerter Alerter)
- func RegisterBot(bot Bot)
- func RegisterBotErrorSupervisor(fnc func(BotType, error) *SupervisionDirective)
- func RegisterCommand(botType BotType, command Command)
- func RegisterCommandProps(props *CommandProps)
- func RegisterConfigWatcher(watcher ConfigWatcher)
- func RegisterScheduledTask(botType BotType, task ScheduledTask)
- func RegisterScheduledTaskProps(props *ScheduledTaskProps)
- func RegisterWorker(worker workers.Worker)
- func Run(ctx context.Context, config *Config) error
- func StripMessage(pattern *regexp.Regexp, input string) string
- type AbortInput
- type Adapter
- type Alerter
- type BlockedInputError
- type Bot
- type BotNonContinuableError
- type BotStatus
- type BotType
- type CacheConfig
- type Command
- type CommandConfig
- type CommandHelp
- type CommandHelps
- type CommandProps
- type CommandPropsBuilder
- func (builder *CommandPropsBuilder) BotType(botType BotType) *CommandPropsBuilder
- func (builder *CommandPropsBuilder) Build() (*CommandProps, error)
- func (builder *CommandPropsBuilder) ConfigurableFunc(config CommandConfig, ...) *CommandPropsBuilder
- func (builder *CommandPropsBuilder) Func(fn func(context.Context, Input) (*CommandResponse, error)) *CommandPropsBuilder
- func (builder *CommandPropsBuilder) Identifier(id string) *CommandPropsBuilder
- func (builder *CommandPropsBuilder) Instruction(instruction string) *CommandPropsBuilder
- func (builder *CommandPropsBuilder) InstructionFunc(fnc func(input *HelpInput) string) *CommandPropsBuilder
- func (builder *CommandPropsBuilder) MatchFunc(matchFunc func(Input) bool) *CommandPropsBuilder
- func (builder *CommandPropsBuilder) MatchPattern(pattern *regexp.Regexp) *CommandPropsBuilder
- func (builder *CommandPropsBuilder) MustBuild() *CommandProps
- type CommandResponse
- type Commands
- type Config
- type ConfigNotFoundError
- type ConfigWatcher
- type ContextualFunc
- type DefaultBotOption
- type DestinatedConfig
- type HelpInput
- type Input
- type Output
- type OutputDestination
- type OutputMessage
- type ScheduledConfig
- type ScheduledTask
- type ScheduledTaskProps
- type ScheduledTaskPropsBuilder
- func (builder *ScheduledTaskPropsBuilder) BotType(botType BotType) *ScheduledTaskPropsBuilder
- func (builder *ScheduledTaskPropsBuilder) Build() (*ScheduledTaskProps, error)
- func (builder *ScheduledTaskPropsBuilder) ConfigurableFunc(config TaskConfig, ...) *ScheduledTaskPropsBuilder
- func (builder *ScheduledTaskPropsBuilder) DefaultDestination(dest OutputDestination) *ScheduledTaskPropsBuilder
- func (builder *ScheduledTaskPropsBuilder) Func(fn func(context.Context) ([]*ScheduledTaskResult, error)) *ScheduledTaskPropsBuilder
- func (builder *ScheduledTaskPropsBuilder) Identifier(id string) *ScheduledTaskPropsBuilder
- func (builder *ScheduledTaskPropsBuilder) MustBuild() *ScheduledTaskProps
- func (builder *ScheduledTaskPropsBuilder) Schedule(schedule string) *ScheduledTaskPropsBuilder
- type ScheduledTaskResult
- type SerializableArgument
- type Status
- type SupervisionDirective
- type TaskConfig
- type UserContext
- type UserContextStorage
Constants ¶
This section is empty.
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.
Functions ¶
func NewBlockedInputError ¶
NewBlockedInputError creates and return new BlockedInputError instance.
func NewBotNonContinuableError ¶
NewBotNonContinuableError creates and return new BotNonContinuableError instance.
func RegisterAlerter ¶
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 ¶
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 ¶
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:
- Bot escalates reconnection error, FooReconnectionFailureError, each time it fails to reconnect
- Supervising function counts the error and ignores the first two occurrence
- 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 ¶
RegisterCommand registers given sarah.Command. On sarah.Run(), Commands are registered to corresponding bot via Bot.AppendCommand().
func RegisterCommandProps ¶
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 ¶
func RegisterConfigWatcher(watcher ConfigWatcher)
RegisterConfigWatcher registers given ConfigWatcher implementation.
func RegisterScheduledTask ¶
func RegisterScheduledTask(botType BotType, task ScheduledTask)
RegisterScheduledTask registers given sarah.ScheduledTask. On sarah.Run(), schedule is set for this task.
func RegisterScheduledTaskProps ¶
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 ¶
RegisterWorker registers given workers.Worker implementation. When this is not called, a worker instance with default setting is used.
func Run ¶
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.
Types ¶
type AbortInput ¶
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 ¶
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) ReplyTo ¶
func (ai *AbortInput) ReplyTo() OutputDestination
ReplyTo returns slack channel to send reply to.
func (*AbortInput) SenderKey ¶
func (ai *AbortInput) SenderKey() string
SenderKey returns string representing message sender.
func (*AbortInput) SentAt ¶
func (ai *AbortInput) SentAt() time.Time
SentAt returns message event's timestamp.
type Adapter ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
func (e BotNonContinuableError) Error() string
Error returns detailed error about Bot's non-continuable state.
type BotType ¶
type BotType string
BotType indicates what bot implementation a particular Bot/Plugin is corresponding to.
type CacheConfig ¶
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 ¶
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 ¶
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 ¶
type CommandConfig interface{}
CommandConfig provides an interface that every command configuration must satisfy, which actually means empty.
type CommandHelp ¶
CommandHelp represents help messages for corresponding Command.
type CommandHelps ¶
type CommandHelps []*CommandHelp
CommandHelps is an alias to slice of CommandHelps' pointers.
type CommandProps ¶
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 ¶
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 ¶
func NewCommandPropsBuilder() *CommandPropsBuilder
NewCommandPropsBuilder returns new CommandPropsBuilder instance.
func (*CommandPropsBuilder) BotType ¶
func (builder *CommandPropsBuilder) BotType(botType BotType) *CommandPropsBuilder
BotType is a setter to provide belonging BotType.
func (*CommandPropsBuilder) Build ¶
func (builder *CommandPropsBuilder) Build() (*CommandProps, error)
Build builds new CommandProps instance with provided values.
func (*CommandPropsBuilder) ConfigurableFunc ¶
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 ¶
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 ¶
func (builder *CommandPropsBuilder) Identifier(id string) *CommandPropsBuilder
Identifier is a setter for Command identifier.
func (*CommandPropsBuilder) Instruction ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
type CommandResponse struct { Content interface{} UserContext *UserContext }
CommandResponse is returned by Command or Task when the execution is finished.
func NewSuppressedResponseWithNext ¶
func NewSuppressedResponseWithNext(next ContextualFunc) *CommandResponse
NewSuppressedResponseWithNext creates new sarah.CommandResponse instance with no message and next function to continue
type Commands ¶
type Commands struct {
// contains filtered or unexported fields
}
Commands stashes all registered Command.
func NewCommands ¶
func NewCommands() *Commands
NewCommands creates and returns new Commands instance.
func (*Commands) Append ¶
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 ¶
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 ¶
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 ¶
func (commands *Commands) Helps(input *HelpInput) *CommandHelps
Helps returns underlying commands help messages in a form of *CommandHelps.
type Config ¶
type Config struct {
TimeZone string `json:"timezone" yaml:"timezone"`
}
Config contains some basic configuration variables for go-sarah.
type ConfigNotFoundError ¶
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 ¶
func (err *ConfigNotFoundError) Error() string
Error returns stringified representation of the error.
type ConfigWatcher ¶
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 ¶
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 ¶
type DefaultBotOption func(bot *defaultBot)
DefaultBotOption defines function that defaultBot's functional option must satisfy.
func BotWithStorage ¶
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 ¶
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 ¶
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 ¶
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) ReplyTo ¶
func (hi *HelpInput) ReplyTo() OutputDestination
ReplyTo returns slack channel to send reply to.
type Input ¶
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 ¶
type Output interface { Destination() OutputDestination Content() interface{} }
Output defines interface that each outgoing message must satisfy.
func NewOutputMessage ¶
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 ¶
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 ¶
type OutputMessage struct {
// contains filtered or unexported fields
}
OutputMessage represents outgoing message.
func (*OutputMessage) Content ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
func NewScheduledTaskPropsBuilder() *ScheduledTaskPropsBuilder
NewScheduledTaskPropsBuilder creates and returns ScheduledTaskPropsBuilder instance.
func (*ScheduledTaskPropsBuilder) BotType ¶
func (builder *ScheduledTaskPropsBuilder) BotType(botType BotType) *ScheduledTaskPropsBuilder
BotType is a setter to provide belonging BotType.
func (*ScheduledTaskPropsBuilder) Build ¶
func (builder *ScheduledTaskPropsBuilder) Build() (*ScheduledTaskProps, error)
Build builds new ScheduledProps instance with provided values.
func (*ScheduledTaskPropsBuilder) ConfigurableFunc ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
func (builder *ScheduledTaskPropsBuilder) Schedule(schedule string) *ScheduledTaskPropsBuilder
Schedule sets execution schedule. Representation spec. is identical to that of github.com/robfig/cron.
type ScheduledTaskResult ¶
type ScheduledTaskResult struct { Content interface{} Destination OutputDestination }
ScheduledTaskResult is a struct that ScheduledTask returns on its execution.
type SerializableArgument ¶
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 ¶
Status represents the current status of the bot system including Runner and all registered Bots.
func CurrentStatus ¶
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 ¶
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 ¶
type TaskConfig interface{}
TaskConfig provides an interface that every task configuration must satisfy, which actually means empty.
type UserContext ¶
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 ¶
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 ¶
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 ¶
func NewUserContextStorage(config *CacheConfig) UserContextStorage
NewUserContextStorage creates and returns new defaultUserContextStorage instance to store users' conversational contexts.
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
Package alerter and its sub packages provide alerting mechanisms that implement sarah.Alerter interface to inform bot's critical states to administrator.
|
Package alerter and its sub packages provide alerting mechanisms that implement sarah.Alerter interface to inform bot's critical states to administrator. |
line
Package line provides sarah.Alerter implementation for LINE Notify.
|
Package line provides sarah.Alerter implementation for LINE Notify. |
examples
|
|
simple
Package main provides a simple bot experience using slack.Adapter with multiple plugin commands and scheduled tasks.
|
Package main provides a simple bot experience using slack.Adapter with multiple plugin commands and scheduled tasks. |
simple/plugins/count
Package count provides example code to setup sarah.CommandProps.
|
Package count provides example code to setup sarah.CommandProps. |
simple/plugins/echo
Package echo provides example code to sarah.Command implementation.
|
Package echo provides example code to sarah.Command implementation. |
simple/plugins/fixedtimer
Package fixedtimer provides example code to setup ScheduledTaskProps with fixed schedule.
|
Package fixedtimer provides example code to setup ScheduledTaskProps with fixed schedule. |
simple/plugins/guess
Package guess provides example code to setup stateful command.
|
Package guess provides example code to setup stateful command. |
simple/plugins/hello
Package hello provides example code to setup relatively simple sarah.CommandProps.
|
Package hello provides example code to setup relatively simple sarah.CommandProps. |
simple/plugins/morning
Package morning provides example code to setup sarah.CommandProps with relatively complex matching function.
|
Package morning provides example code to setup sarah.CommandProps with relatively complex matching function. |
simple/plugins/timer
Package timer provides example code to setup ScheduledTaskProps with re-configurable schedule and sending room.
|
Package timer provides example code to setup ScheduledTaskProps with re-configurable schedule and sending room. |
simple/plugins/todo
Package todo is an example of stateful command that let users input required arguments step by step in a conversational manner.
|
Package todo is an example of stateful command that let users input required arguments step by step in a conversational manner. |
simple/plugins/worldweather
Package worldweather is a reference implementation that provides relatively practical use of sarah.CommandProps.
|
Package worldweather is a reference implementation that provides relatively practical use of sarah.CommandProps. |
status
Package main provides an example that uses sarah.CurrentStatus() to get current go-sarah and its belonging Bot's status via HTTP server.
|
Package main provides an example that uses sarah.CurrentStatus() to get current go-sarah and its belonging Bot's status via HTTP server. |
Package gitter provides sarah.Adapter implementation for gitter.
|
Package gitter provides sarah.Adapter implementation for gitter. |
Package log provides logging mechanism including replaceable Logger interface and its default implementation.
|
Package log provides logging mechanism including replaceable Logger interface and its default implementation. |
Package retry provides general retry logic and designated error structure that contains multiple errors.
|
Package retry provides general retry logic and designated error structure that contains multiple errors. |
Package slack provides sarah.Adapter implementation for Slack.
|
Package slack provides sarah.Adapter implementation for Slack. |
Package workers provides general purpose worker mechanism that outputs stacktrace when given job panics.
|
Package workers provides general purpose worker mechanism that outputs stacktrace when given job panics. |