robot

package module
v0.0.0-...-a7e43b8 Latest Latest
Warning

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

Go to latest
Published: Dec 11, 2023 License: MIT Imports: 4 Imported by: 13

README

Tiny library for writing Gopherbot Go extensions, see: https://lnxjedi.github.io/gopherbot

Usage:

import (
    "github.com/lnxjedi/gopherbot/robot"
)
...

Documentation

Overview

Package robot defines interfaces and constants for pluggable go modules

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AttrRet

type AttrRet struct {
	Attribute string
	RetVal
}

AttrRet implements Stringer so it can be interpolated with fmt if the plugin author is ok with ignoring the RetVal.

func (AttrRet) String

func (a AttrRet) String() string

type BrainSpec

type BrainSpec struct {
	Name  string
	Brain func(Handler) SimpleBrain
}

BrainSpec for specifying a connector

type Connector

type Connector interface {
	// SetUserMap provides the connector with a map from usernames to userIDs,
	// the protocol-internal ID for a user. The connector can use this map
	// to replace @name mentions in messages, and/or build a map of userIDs
	// to configured usernames.
	SetUserMap(map[string]string)
	// GetProtocolUserAttribute retrieves a piece of information about a user
	// from the connector protocol, or "",!ok if the connector doesn't have the
	// information. Plugins should normally call GetUserAttribute, which
	// supplements protocol data with data from users.json.
	// The connector should expect "username" or "<userid>".
	// The current attributes are:
	// email, realName, firstName, lastName, phone, sms, connections
	GetProtocolUserAttribute(user, attr string) (value string, ret RetVal)
	// MessageHeard tells the connector that the user should be notified that
	// the message has been heard and is being responded to. The connector
	// can then e.g. send a typing notifier.
	MessageHeard(user, channel string)
	// FormatHelp takes a (bot)/(alias) (command) - (description) string, and
	// returns a protocol-specific string formatted for display in the protocol.
	FormatHelp(string) string
	// DefaultHelp allows a connector to override the default help lines when
	// there is no keyword.
	DefaultHelp() []string
	// JoinChannel joins a channel given it's human-readable name, e.g. "general"
	JoinChannel(c string) RetVal
	/* NOTE: Each of the Send* methods takes a pointer to a ConnectorMessage.
	   For plugins, this is the original ConnectorMessage that triggered a
	   command, and provides context back to the connector in sending replies.
	*/
	// SendProtocolChannelThreadMessage sends a message to a thread in a channel,
	// starting a thread if none exists. If thread is unset or unsupported by the
	// protocol, it just sends a message to the channel.
	SendProtocolChannelThreadMessage(channelname, threadid, msg string, format MessageFormat, msgObject *ConnectorMessage) RetVal
	// SendProtocolUserChannelThreadMessage directs a message to a user in a channel/thread.
	// This method also supplies what the bot engine believes to be the username.
	SendProtocolUserChannelThreadMessage(userid, username, channelname, threadid, msg string, format MessageFormat, msgObject *ConnectorMessage) RetVal
	// SendProtocolUserMessage sends a direct message to a user if supported.
	// The value of user will be either "<userid>", the connector internal
	// userID in brackets, or "username", a string name the connector associates
	// with the user.
	SendProtocolUserMessage(user, msg string, format MessageFormat, msgObject *ConnectorMessage) RetVal
	// The Run method starts the main loop and takes a channel for stopping it.
	Run(stopchannel <-chan struct{})
}

Connector is the interface defining methods that should be provided by the connector for use by bot

type ConnectorMessage

type ConnectorMessage struct {
	// Protocol - string name of connector, e.g. "Slack"
	Protocol string
	// optional UserName and required internal UserID
	UserName, UserID string
	// optional / required channel values
	ChannelName, ChannelID string
	// Opaque values
	ThreadID, MessageID string
	ThreadedMessage     bool
	// true when the incoming message originated from the robot itself
	SelfMessage bool
	// DirectMessage - whether the message should be considered private between user and robot
	DirectMessage bool
	// BotMessage - true when the connector is certain the message has been sent to the robot,
	// e.g. for slack slash commands
	BotMessage bool
	// HiddenMessage - true when the user sent a message to the robot that can't be seen by
	// other users, also true for slack slash commands
	HiddenMessage bool
	// MessageText - sanitized message text, with all protocol-added junk removed
	MessageText string
	// MessageObject, Client - interfaces for the raw objects; go extensions can use
	// these with type switches/assertions to access object internals
	MessageObject, Client interface{}
}

ConnectorMessage is passed in to the robot for every incoming message seen. The *ID fields are required invariant internal representations that the protocol accepts in it's interface methods.

type ConnectorSpec

type ConnectorSpec struct {
	Name      string
	Connector func(Handler, *log.Logger) Connector
}

ConnectorSpec for specifying a connector

type Handler

type Handler interface {
	// IncomingMessage is called by the connector for all messages the bot
	// can hear. See the fields for ConnectorMessage for information about
	// this object.
	IncomingMessage(*ConnectorMessage)
	// GetProtocolConfig unmarshals the ProtocolConfig section of robot.yaml
	// into a connector-provided struct
	GetProtocolConfig(interface{}) error
	// GetBrainConfig unmarshals the BrainConfig section of robot.yaml
	// into a struct provided by the brain provider
	GetBrainConfig(interface{}) error
	// GetEventStrings for developing tests with the terminal connector
	GetEventStrings() *[]string
	// GetHistoryConfig unmarshals the HistoryConfig section of robot.yaml
	// into a struct provided by the brain provider
	GetHistoryConfig(interface{}) error
	// SetID allows the connector to set the robot's internal ID
	SetBotID(id string)
	// SetTerminalWriter allows the terminal connector to provide an io.Writer
	// to log to.
	SetTerminalWriter(io.Writer)
	// SetBotMention allows the connector to set the bot's @(mention) ID
	// (without the @) for protocols where it's a fixed value. This allows
	// the robot to recognize "@(protoMention) foo", needed for e.g. Rocket
	// where the robot username may not match the configured name.
	SetBotMention(mention string)
	// GetLogLevel allows the connector to check the robot's configured log level
	// to make it's own decision about how much it should log. For slack, this
	// determines whether the plugin does api logging.
	GetLogLevel() LogLevel
	// GetInstallPath returns the installation path of the gopherbot
	GetInstallPath() string
	// GetConfigPath returns the path to the config directory if set
	GetConfigPath() string
	// Log provides a standard logging interface with a level as defined in
	// bot/logging.go
	Log(l LogLevel, m string, v ...interface{})
	// GetDirectory lets infrastructure plugins create directories, for e.g.
	// file-based history and brain providers. When privilege separation is in
	// use, the directory is created with the privileged uid.
	GetDirectory(path string) error
	// ExtractID is a convenience function for connectors, keeps 'import "regexp"
	// out of robot.
	ExtractID(u string) (string, bool)
	// RaisePriv raises the privilege of the current thread, allowing
	// filesystem access in GOPHER_HOME. Reason is informational.
	RaisePriv(reason string)
}

Handler is the interface that defines the API for the handler object passed to Connectors, history providers and brain providers.

type HistoryLogger

type HistoryLogger interface {
	// Log a line of output, normally timestamped; bot should prefix with OUT or ERR
	Log(line string)
	// Add a plain line to the log, without a timestamp
	Line(line string)
	// Close a log file against further writes, but keep
	Close()
	// Finalize called after pipeline finishes, log can be removed.
	Finalize()
}

HistoryLogger is provided by a HistoryProvider for each job / plugin run where it's requested

type HistoryProvider

type HistoryProvider interface {
	// NewLog provides a HistoryLogger for the given tag / index, and
	// cleans up logs older than maxHistories.
	NewLog(tag string, index, maxHistories int) (HistoryLogger, error)
	// GetLog gets an io.Reader() for a given history log
	GetLog(tag string, index int) (io.Reader, error)
	// GetLogURL provides a static URL for the history file if there is one
	GetLogURL(tag string, index int) (URL string, exists bool)
	// MakeLogURL publishes a log to a URL and returns the URL; this
	// URL need only be available for a short timespan, e.g. 42 seconds
	MakeLogURL(tag string, index int) (URL string, exists bool)
}

HistoryProvider is responsible for storing and retrieving job histories

type HistorySpec

type HistorySpec struct {
	Name     string
	Provider func(Handler) HistoryProvider
}

HistorySpec for specifying a connector

type JobHandler

type JobHandler struct {
	Handler func(r Robot, args ...string) TaskRetVal // The callback function called by the robot when the job is run
	Config  interface{}                              // An optional empty struct defining custom configuration for the job
}

JobHandler is the struct registered for a Go job

type JobSpec

type JobSpec struct {
	Name    string
	Handler JobHandler
}

JobSpec used by loadable plugins that return a slice of JobSpecs

type LogLevel

type LogLevel int

LogLevel for determining when to output a log entry

const (
	Trace LogLevel = iota
	Debug
	Info
	Audit // For plugins to emit auditable events
	Warn
	Error
	Fatal
)

Definitions of log levels in order from most to least verbose

func (LogLevel) String

func (i LogLevel) String() string

type Logger

type Logger interface {
	Log(l LogLevel, m string, v ...interface{})
}

Logger is used by a Brain for logging errors

type Manifest

type Manifest struct {
	Tasks     []TaskSpec
	Plugins   []PluginSpec
	Jobs      []JobSpec
	Connector ConnectorSpec
	Brain     BrainSpec
	History   HistorySpec
}

Manifest lists all the handlers available from a given loadable module

type Message

type Message struct {
	User            string            // The user who sent the message; this can be modified for replying to an arbitrary user
	ProtocolUser    string            // the protocol internal ID of the user
	Channel         string            // The channel where the message was received, or "" for a direct message. This can be modified to send a message to an arbitrary channel.
	ProtocolChannel string            // the protocol internal channel ID
	Protocol        Protocol          // slack, terminal, test, others; used for interpreting rawmsg or sending messages with Format = 'Raw'
	Incoming        *ConnectorMessage // raw IncomingMessage object
	Format          MessageFormat     // The outgoing message format, one of Raw, Fixed, or Variable
}

Message is passed to each task as it runs, initialized from the botContext. Tasks can copy and modify the Robot without affecting the botContext.

type MessageFormat

type MessageFormat int

MessageFormat indicates how the connector should display the content of the message. One of Variable, Fixed or Raw

const (
	Raw MessageFormat = iota // protocol native, zero value -> default if not specified
	Fixed
	Variable
)

Outgoing message format, Variable or Fixed

func (MessageFormat) String

func (i MessageFormat) String() string

type Parameter

type Parameter struct {
	Name, Value string
}

Parameter items are provided to jobs and plugins as environment variables

type PluginHandler

type PluginHandler struct {
	DefaultConfig string /* A yaml-formatted multiline string defining the default Plugin configuration. It should be liberally commented for use in generating
	custom configuration for the plugin. If a Config: section is defined, it should match the structure of the optional Config interface{} */
	Handler func(r Robot, command string, args ...string) TaskRetVal // The callback function called by the robot whenever a Command is matched
	Config  interface{}                                              // An optional empty struct defining custom configuration for the plugin
}

PluginHandler is the struct a Go plugin registers for the Gopherbot plugin API.

type PluginSpec

type PluginSpec struct {
	Name    string
	Handler PluginHandler
}

PluginSpec used by loadable plugins that return a slice of PluginSpecs

type Protocol

type Protocol int

Protocol - connector protocols

const (
	// Slack connector
	Slack Protocol = iota
	// Rocket for Rocket.Chat
	Rocket
	// Terminal connector
	Terminal
	// Test connector for automated test suites
	Test
	// Null connector for unconfigured robots
	Null
)

func (Protocol) String

func (i Protocol) String() string

type Repository

type Repository struct {
	Type         string // task extending the namespace needs to match for parameters
	CloneURL     string
	Dependencies []string // List of repositories this one depends on; changes to a dependency trigger a build
	// Logs to keep for this repo; pointer allows "undefined" to be detected,
	// in which case the value is inherited from the build type.
	KeepLogs   *int
	Parameters []Parameter // per-repository parameters
}

Repository represents a buildable git repository, for CI/CD

type RetVal

type RetVal int

RetVal is a integer type for returning error conditions from bot methods, or 0 for Ok

const (
	// Ok indicates a successful result
	Ok RetVal = iota // success

	// UserNotFound - failed lookup
	UserNotFound
	// ChannelNotFound - failed lookup
	ChannelNotFound
	// AttributeNotFound - failed looking up user/robot attributes like email, name, etc.
	AttributeNotFound
	// FailedMessageSend - the bot was not able to send a message
	FailedMessageSend
	// FailedChannelJoin - the robot couldn't join a channel; e.g. slack doesn't allow bots to join
	FailedChannelJoin

	// DatumNotFound - key not found in the global hash when update called
	DatumNotFound
	// DatumLockExpired - A datum was checked out for too long, and the lock expired
	DatumLockExpired
	// DataFormatError - Problem unmarshalling JSON
	DataFormatError
	// BrainFailed - An error condition prevented the brain from storing/retrieving; redis down, file write failed, etc.
	BrainFailed
	// InvalidDatumKey - Key name didn't match the regex for valid key names
	InvalidDatumKey

	// InvalidDblPtr - GetTaskConfig wasn't called with a double-pointer to a config struct
	InvalidDblPtr
	// InvalidCfgStruct - The struct type in GetTaskConfig doesn't match the struct registered for the plugin
	InvalidCfgStruct
	// NoConfigFound - The plugin/job doesn't have any config data
	NoConfigFound

	// RetryPrompt - There was already a prompt in progress for the user/channel
	RetryPrompt
	// ReplyNotMatched - The user reply didn't match the pattern waited for
	ReplyNotMatched
	// UseDefaultValue - The user replied with a single '=', meaning use a default value
	UseDefaultValue
	// TimeoutExpired - The user didn't reply within the given timeout
	TimeoutExpired
	// Interrupted - The user replied with '-' (cancel)
	Interrupted
	// MatcherNotFound - There was no matcher configured with the given string, or the regex didn't compile
	MatcherNotFound

	// NoUserEmail - Couldn't look up the user's email address
	NoUserEmail
	// NoBotEmail - Couldn't look up the robot's email address
	NoBotEmail
	// MailError - There was an error sending email
	MailError

	// TaskNotFound - no task with the given name
	TaskNotFound
	// MissingArguments - AddTask requires a command and args for a plugin
	MissingArguments
	// InvalidStage - tasks can only be added when the robot is running primaryTasks
	InvalidStage
	// InvalidTaskType - mismatch of task/plugin/job method with provided name
	InvalidTaskType
	// CommandNotMatched - the command string didn't match a command for the plugin
	CommandNotMatched
	// TaskDisabled - a method call attempted to add a disabled task to a pipeline
	TaskDisabled
	// PrivilegeViolation - error adding a privileged job/command to an unprivileged pipeline
	PrivilegeViolation
)

func (RetVal) String

func (i RetVal) String() string

type Robot

type Robot interface {
	// Primarily plugin methods
	CheckAdmin() bool
	Elevate(bool) bool
	GetBotAttribute(a string) *AttrRet
	GetUserAttribute(u, a string) *AttrRet
	GetSenderAttribute(a string) *AttrRet
	GetTaskConfig(dptr interface{}) RetVal
	GetMessage() *Message
	GetParameter(name string) string
	Email(subject string, messageBody *bytes.Buffer, html ...bool) (ret RetVal)
	EmailUser(user, subject string, messageBody *bytes.Buffer, html ...bool) (ret RetVal)
	EmailAddress(address, subject string, messageBody *bytes.Buffer, html ...bool) (ret RetVal)
	Fixed() Robot
	MessageFormat(f MessageFormat) Robot
	Direct() Robot
	Threaded() Robot
	Log(l LogLevel, m string, v ...interface{}) bool
	SendChannelMessage(ch, msg string, v ...interface{}) RetVal
	SendChannelThreadMessage(ch, thr, msg string, v ...interface{}) RetVal
	SendUserChannelMessage(u, ch, msg string, v ...interface{}) RetVal
	SendUserChannelThreadMessage(u, ch, thr, msg string, v ...interface{}) RetVal
	SendUserMessage(u, msg string, v ...interface{}) RetVal
	Reply(msg string, v ...interface{}) RetVal
	ReplyThread(msg string, v ...interface{}) RetVal
	Say(msg string, v ...interface{}) RetVal
	SayThread(msg string, v ...interface{}) RetVal
	RandomInt(n int) int
	RandomString(s []string) string
	Pause(s float64)
	PromptForReply(regexID string, prompt string, v ...interface{}) (string, RetVal)
	PromptThreadForReply(regexID string, prompt string, v ...interface{}) (string, RetVal)
	PromptUserForReply(regexID string, user string, prompt string, v ...interface{}) (string, RetVal)
	PromptUserChannelForReply(regexID string, user, channel string, prompt string, v ...interface{}) (string, RetVal)
	PromptUserChannelThreadForReply(regexID string, user, channel, thread string, prompt string, v ...interface{}) (string, RetVal)
	CheckoutDatum(key string, datum interface{}, rw bool) (locktoken string, exists bool, ret RetVal)
	CheckinDatum(key, locktoken string)
	UpdateDatum(key, locktoken string, datum interface{}) (ret RetVal)
	Remember(key, value string, shared bool)
	RememberThread(key, value string, shared bool)
	RememberContext(context, value string)
	RememberContextThread(context, value string)
	Recall(key string, shared bool) string
	// Primarily job/pipeline methods
	GetRepoData() map[string]Repository
	ExtendNamespace(string, int) bool
	SpawnJob(string, ...string) RetVal
	AddTask(string, ...string) RetVal
	FinalTask(string, ...string) RetVal
	FailTask(string, ...string) RetVal
	AddJob(string, ...string) RetVal
	AddCommand(string, string) RetVal
	FinalCommand(string, string) RetVal
	FailCommand(string, string) RetVal
	// Go plugins only, for filesystem access to GOPHER_HOME
	RaisePriv(string)
	SetParameter(string, string) bool
	SetWorkingDirectory(string) bool
}

Robot defines the methods exposed by gopherbot.bot Robot struct, for use by plugins/jobs/tasks. See bot/Robot for complete definitions.

type SimpleBrain

type SimpleBrain interface {
	// Store stores a blob of data with a string key, returns error
	// if there's a problem storing the datum.
	Store(key string, blob *[]byte) error
	// Retrieve returns a blob of data (probably JSON) given a string key,
	// and exists=true if the data blob was found, or error if the brain
	// malfunctions.
	Retrieve(key string) (blob *[]byte, exists bool, err error)
	// List returns a list of all memories - Gopherbot isn't a database,
	// so it _should_ be pretty short.
	List() (keys []string, err error)
	// Delete deletes a memory
	Delete(key string) error
}

SimpleBrain is the simple interface for a configured brain, where the robot handles all locking issues.

type TaskHandler

type TaskHandler struct {
	Handler func(r Robot, args ...string) TaskRetVal // The callback for this Go task
}

TaskHandler is the struct registered for a Go task

type TaskRetVal

type TaskRetVal int

TaskRetVal is an integer type for return values from plugins, mainly for elevation & authorization

const (
	// Normal exit is for non-auth/non-elevating plugins; since this is the
	// default exit value, we don't use it to indicate successful authentication
	// or elevation.
	Normal TaskRetVal = iota
	// Fail indicates requested authorization or elevation failed
	Fail
	// MechanismFail indicates authorization or elevation couldn't be determined due to a technical issue that should be logged
	MechanismFail
	// ConfigurationError indicates authorization or elevation failed due to misconfiguration
	ConfigurationError
	// PipelineAborted - failed exclusive w/o queueTask
	PipelineAborted
	// RobotStopping - the robot is shutting down and can't start any new pipelines
	RobotStopping
	// NotFound - generic return value when the asked for item couldn't be returned
	NotFound
	// Success indicates successful authorization or elevation; using '7' (three bits set)
	// reduces the likelihood of an authorization plugin mistakenly exiting with a success
	// value
	Success = 7
)

func (TaskRetVal) String

func (i TaskRetVal) String() string

type TaskSpec

type TaskSpec struct {
	Name              string
	RequiresPrivilege bool
	Handler           TaskHandler
}

TaskSpec used by loadable plugins that return a slice of TaskSpecs

Jump to

Keyboard shortcuts

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