bitbot

package
v1.3.1 Latest Latest
Warning

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

Go to latest
Published: Jun 19, 2020 License: MIT Imports: 28 Imported by: 0

Documentation

Index

Constants

View Source
const DICE_USAGE = "Usage: [num dice]d[sides](+/-num) (opt: if fudging)"
View Source
const SourceRepo string = "https://github.com/bbriggs/bitbot"

Variables

View Source
var (
	GitTag    string // Dockerhub appears to use shallow clones which drop tag info. Set this as a default."
	GitCommit string
	GitBranch string
)
View Source
var AbyssTrigger = NamedTrigger{
	ID:   "abyss",
	Help: "State of the art advanced Abyss simulator. Non-interactive.",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG" && rand.Intn(1000) < 2
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		irc.Reply(m, "0.0")
		return true
	},
}
View Source
var BeefyTrigger = NamedTrigger{
	ID:   "beefy",
	Help: "It's big. It's beefy. It triggers any time someone says \"beefy\" in a message.",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		match, _ := regexp.MatchString(`(?i)beefy`, m.Trailing)
		return m.Command == "PRIVMSG" && match
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		responses := []string{
			"BEEFY",
			"it's what's for dinner",
			"https://i.imgur.com/VbC5GLl.jpg",
			"mmmmmm",
		}
		irc.Reply(m, responses[b.Random.Intn(len(responses))])
		return true
	},
}
View Source
var ChannelPopGaugeTrigger = NamedTrigger{
	ID:   "channelPopGauge",
	Help: "Updates a Prometheus gauge with the value of a channel's population",
	Condition: func(bot *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "JOIN" || m.Command == "PART" || m.Command == "QUIT"

	},
	Action: func(bot *hbot.Bot, m *hbot.Message) bool {
		switch m.Command {
		case "JOIN":
			b.gauges["channel_pop"].WithLabelValues(m.To).Inc()
		case "QUIT":
			for _, c := range b.Bot.Channels {
				bot.Send("LIST " + c)
			}
		default:
			b.gauges["channel_pop"].WithLabelValues(m.To).Dec()
		}

		return true
	},
}
View Source
var Covid19Trigger = NamedTrigger{
	ID:   "covid19",
	Help: "Fetch stats on Coronavirus by region",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG" && strings.HasPrefix(m.Trailing, "!covid")
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		data, ok := getCovid19Data()
		if !ok {
			irc.Reply(m, "Unable to get data at this time")
			return true
		}
		resp := parseCovid19Trigger(strings.Split(m.Trailing, " "), &data)
		irc.Reply(m, resp)
		return true
	},
}
View Source
var DecisionsTrigger = NamedTrigger{
	ID:   "decisions",
	Help: "Let the bot decide something for you. Usage: ${bot_name} choose option option [option...]",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		prefix := fmt.Sprintf("%s choose", irc.Nick)
		return m.Command == "PRIVMSG" && strings.HasPrefix(m.Content, prefix)
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		prefix := fmt.Sprintf("%s choose", irc.Nick)
		msg := strings.TrimPrefix(m.Content, prefix)
		r := choose(msg)
		if r == "" {
			r = "Choose what?"
		}
		irc.Reply(m, r)
		return true
	},
}
View Source
var EpeenTrigger = NamedTrigger{
	ID:   "epeen",
	Help: "epeen returns the length of the requesters epeen. Usage: !epeen",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG" && strings.TrimSpace(m.Content) == "!epeen"
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		var epeen = makeEpeenAnswer(m.From)
		irc.Reply(m, epeen)
		return true
	},
}
View Source
var HandleListReplyTrigger = NamedTrigger{
	ID:   "handleListReply",
	Help: "Sets the gauge for a channel pop when an RPL_LIST command is detected",
	Condition: func(bot *hbot.Bot, m *hbot.Message) bool {
		return m.Command == irc.RPL_LIST
	},
	Action: func(bot *hbot.Bot, m *hbot.Message) bool {
		log.Println("List Reply Received")
		channel := m.Params[1]
		pop, err := strconv.Atoi(m.Params[2])
		if err != nil {
			log.Println("RPL_LIST returned invalid reply")
		}
		b.gauges["channel_pop"].WithLabelValues(channel).Set(float64(pop))
		return true
	},
}
View Source
var HelpTrigger = NamedTrigger{
	ID:   "help",
	Help: "Usage: !help [trigger name]",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG" && strings.HasPrefix(m.Content, "!help")

	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		splitMsg := strings.Split(m.Trailing, " ")
		triggers := b.ListTriggers()
		if len(splitMsg) < 2 {
			irc.Reply(m, "Currently loaded plugins: "+strings.Join(triggers, ", "))
			return true
		}

		for _, t := range triggers {
			if splitMsg[1] == t {

				t, ok := b.FetchTrigger(splitMsg[1])
				if ok && t.Help != "" {
					irc.Reply(m, t.Help)
				} else {
					irc.Reply(m, "Trigger found but help unavailalbe")
				}
				return true
			}
		}

		irc.Reply(m, "Help text unavailable")
		return true

	},
}
View Source
var IPinfoTrigger = NamedTrigger{
	ID:   "ipinfo",
	Help: "!ipinfo <valid IP>",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG" && strings.HasPrefix(m.Content, "!ipinfo")
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		var resp string
		cmd := strings.Split(m.Content, " ")
		if len(cmd) > 1 {
			resp = query(cmd[1])
		} else {
			resp = "please provide an ip...ya twatsicle"
		}
		irc.Reply(m, resp)
		return true
	},
}
View Source
var InfoTrigger = NamedTrigger{
	ID:   "info",
	Help: "Get version and repo information about this bot. Usage: !info",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG" && strings.TrimSpace(m.Content) == "!info"
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		resp := fmt.Sprintf("Bitbot version %s (%s/%s) | %s", GitTag, GitBranch, GitCommit, SourceRepo)
		irc.Reply(m, resp)
		return true
	},
}
View Source
var InviteTrigger = NamedTrigger{
	ID:   "invite",
	Help: "Follow invites to other channels. Usage: /invite [bot nick]",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "INVITE"
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		irc.Join(m.Content)
		return true
	},
}
View Source
var Magic8BallTrigger = NamedTrigger{
	ID:   "8ball",
	Help: "Beseech the magic 8ball. Usage: !8ball [question]",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG" && strings.HasPrefix(m.Trailing, "!8ball")
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		irc.Reply(m, make8BallAnswer())
		return true
	},
}
View Source
var MarkovInitTrigger = NamedTrigger{
	ID:   "markovInit",
	Help: "Resets markov chain to a fresh chain, or bootstraps it with sample texts. Usage: !markov reset, !markov init",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG" && strings.HasPrefix(m.Content, "!markov ")
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		cmd := strings.Split(m.Content, " ")
		if len(cmd) < 2 {
			irc.Reply(m, "Usage: !markov reset, !markov init")
			return true
		}
		switch cmd[1] {
		case "reset":
			b.mChain = gomarkov.NewChain(1)
		case "init":
			b.mChain = gomarkov.NewChain(1)
			if markovInit(b.mChain) {
				irc.Reply(m, "Markov initialization succeeded.")
			} else {
				irc.Reply(m, "Markov initialization failed.")
			}
		default:
			return true
		}
		return true
	},
}
View Source
var MarkovResponseTrigger = NamedTrigger{
	ID:   "markovResponse",
	Help: "Returns a randomly generated markov string. Usage: !babble",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG" && (m.Content == "!babble" || rand.Intn(1000) == 0)
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		irc.Reply(m, generateBabble(b.mChain))
		return false
	},
}
View Source
var MarkovTrainerTrigger = NamedTrigger{
	ID:   "markovTrainer",
	Help: "Incrementally trains bitbot's markov model on every new privmsg",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG"
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		if b.mChain == nil {

			b.mChain = gomarkov.NewChain(1)
		}
		markovAdd(m.Content, b.mChain)
		return false
	},
}
View Source
var MessageCounterTrigger = NamedTrigger{
	ID:   "messageCounter",
	Help: "Increments a counter for every message it sees in chat.",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG"

	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		b.counters["messageCounter"].WithLabelValues(m.To, m.Name).Inc()
		return false
	},
}
View Source
var NickTakenTrigger = NamedTrigger{
	ID:   "nick",
	Help: "Avoids nick collisions by renaming the bot if the nick is already taken.",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		/* get the host's name by cutting the port number, and making sure that the message comes from host */
		var comesFromHost = (m.From == strings.Split(irc.Host, ":")[0])

		var nickTaken = strings.Contains(m.Content, "Nickname is already in use")

		return comesFromHost && nickTaken
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		irc.SetNick(irc.Nick + "_")
		return false
	},
}
View Source
var OperLogin = hbot.Trigger{
	func(bot *hbot.Bot, m *hbot.Message) bool {
		return m.Command == irc.RPL_MYINFO
	},

	func(bot *hbot.Bot, m *hbot.Message) bool {
		ns, ok := b.NickservLogin()
		if ok {
			bot.Msg("NickServ", ns)
		}
		time.Sleep(5 * time.Second)

		op, ok := b.OperLogin()
		if ok {
			bot.Send(op)
			time.Sleep(5 * time.Second)
			b.GetOper()
		}

		return true
	},
}
View Source
var PartTrigger = NamedTrigger{
	ID:   "part",
	Help: "Command the bot to leave the channel. Usage: [bot nick] part [channel]",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		isPartMessage, err := regexp.MatchString("^"+irc.Nick+".*part",
			m.Content)
		if err != nil {
			log.Error(err.Error())
		}
		return m.Command == "PRIVMSG" && isPartMessage
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		splitMsg := strings.Split(m.Content, " ")
		fmt.Println(splitMsg)
		if len(splitMsg) == 2 {

			irc.Part(m.Params[0], irc.Nick)
			return true
		} else if len(splitMsg) > 2 {

			irc.Part(splitMsg[2], irc.Nick)
			return true
		}

		return false
	},
}
View Source
var RaiderQuoteTrigger = NamedTrigger{
	ID: "raider",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG" && b.Random.Intn(1000) == 1
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		r, ok := getQuote("/fallout/raider")
		if ok {
			irc.Reply(m, r.Quote)
		}
		return false
	},
}
View Source
var ReminderTrigger = NamedTrigger{
	ID:   "reminder",
	Help: "Set up events and remind them to concerned people. Usage: !remind list|time|add|remove|join|part",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG" && strings.HasPrefix(m.Trailing, "!remind")
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		timeFormat = "2006-01-02 15:04"

		splitMSG := strings.Split(m.Content, " ")
		if len(splitMSG) < 2 {
			irc.Reply(m, "Not enough arguments provided")
			return true
		}

		switch splitMSG[1] {
		case "time":
			irc.Reply(m, getTime())
		case "add":
			irc.Reply(m, addEvent(m, irc))
		case "remove":
			irc.Reply(m, removeEvent(m))
		case "list":
			irc.Reply(m, listEvents(m, irc))
		case "join":
			irc.Reply(m, joinEvent(m))
		case "part":
			irc.Reply(m, partEvent(m))
		default:
			irc.Reply(m, "Wrong argument")
		}
		return true
	},
	Init: func() error {
		var err error

		location, err = time.LoadLocation("UTC")
		if err != nil {
			log.Error("Reminder : Couldn't load UTC timezone", err.Error())
			return err
		}

		b.DB.AutoMigrate(&ReminderEvent{})
		return nil
	},
}
View Source
var RollTrigger = NamedTrigger{
	ID:   "roll",
	Help: "!roll " + DICE_USAGE,
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG" && strings.HasPrefix(m.Content, "!roll")
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		var resp string
		cmd := strings.Split(m.Content, " ")
		if len(cmd) > 1 {
			resp = roll(cmd[1])
		} else {
			resp = DICE_USAGE
		}
		irc.Reply(m, resp)
		return true
	},
}
View Source
var SetChanPopGaugeTrigger = NamedTrigger{
	ID:   "setChannelPopGauge",
	Help: "Sets the gauge for a channel's population when the bot joins",
	Condition: func(bot *hbot.Bot, m *hbot.Message) bool {
		return m.Command == irc.RPL_NAMREPLY
	},
	Action: func(bot *hbot.Bot, m *hbot.Message) bool {
		names := strings.Split(strings.TrimSpace(m.Content), " ")
		channel := m.Params[len(m.Params)-1]

		b.gauges["channel_pop"].WithLabelValues(channel).Set(float64(len(names)))
		return true
	},
}
View Source
var ShrugTrigger = NamedTrigger{
	ID:   "shrug",
	Help: "Usage: !shrug",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG" && strings.TrimSpace(m.Content) == "!shrug"
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		irc.Reply(m, `¯\_(ツ)_/¯`)
		return true
	},
}
View Source
var SkipTrigger = NamedTrigger{
	ID:   "skip",
	Help: "Prevents a message from being processed by other triggers. Usage: !skip <something that would have invoked a trigger>",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG" && strings.HasPrefix(m.Content, "!skip")
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		return true
	},
}

SkipTrigger sets a message prefix that instructs bitbot not to process the message Should be set before any "skippable" triggers and after any triggers that run on all messages (unskippable)

View Source
var TableFlipTrigger = NamedTrigger{
	ID:   "tableflip",
	Help: "Flip a table. Usage: !tableflip",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		match := (m.Content == "!tableflip")
		return m.Command == "PRIVMSG" && match
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		irc.Reply(m, "(╯°□°)╯︵ ┻━┻")
		return true
	},
}
View Source
var TableUnflipTrigger = NamedTrigger{
	ID: "unflip",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		match := (m.Content == "!unflip")
		return m.Command == "PRIVMSG" && match
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		irc.Reply(m, "┬─┬ ノ( ゜-゜ノ)")
		return true
	},
}
View Source
var TarotTrigger = NamedTrigger{
	ID:   "Tarot",
	Help: "Request tarot cards, default 1. Usage !tarot [num cards].",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG" && strings.HasPrefix(m.Trailing, "!tarot")
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		if len(m.Content) < 7 {
			resp := tarotCards[rand.Intn(len(tarotCards)-1)]
			irc.Reply(m, resp)
		} else {

			deck := rand.Perm(len(tarotCards))
			msg := strings.TrimPrefix(m.Content, "!tarot ")
			if num, err := strconv.Atoi(msg); err == nil {
				if num < 1 || num > len(tarotCards) {
					num = 1
				}
				if num > 5 {
					for i := 0; i < num; i++ {
						irc.Msg(m.From, tarotCards[deck[i]])
					}
					irc.Reply(m, "I have PMed you your reading.")
				} else {
					for i := 0; i < num; i++ {
						irc.Reply(m, tarotCards[deck[i]])
					}
				}
			} else {
				irc.Reply(m, "Try again..")
			}
		}
		return true
	},
}
View Source
var TrollLauncherTrigger = NamedTrigger{
	ID:   "troll",
	Help: "Launches a random number of trolls for a random amount of damage. Usage: !troll <nick>",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG" && strings.HasPrefix(m.Content, "!troll ")
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		var damage_type = [13]string{"bludgeoning", "piercing", "slashing", "cold", "fire", "acid", "poison",
			"psychic", "necrotic", "radiant", "lightning", "thunder", "force"}
		cmd := strings.Split(m.Content, " ")
		if len(cmd) < 2 {
			irc.Reply(m, "Usage: !troll <nick>")
			return true
		}
		var nick = cmd[1]
		var trolls = rand.Intn(10)
		if trolls == 0 {
			irc.Reply(m, "The troll launcher malfunctioned.")
		} else {
			reply := fmt.Sprintf("Firing %d trolls at %s! You take %d points of %s damage!", trolls, nick,
				rand.Intn(20), damage_type[rand.Intn(12)])
			irc.Reply(m, reply)
		}
		return true
	},
}
View Source
var URLReaderTrigger = NamedTrigger{
	ID:   "urls",
	Help: "Looks up URLs in chat and returns the page title as a message.",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG" && isURL(m.Content)
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		resp := lookupPageTitle(m.Content)
		if resp != "" {
			title := lookupPageTitle(m.Content)
			if len(m.Content) > 70 {
				short := shortenURL(m.Content)
				short = strings.TrimRight(short, "\n")
				title = fmt.Sprintf("%s %s", short, title)
			}
			title = cleanTitle(title)
			irc.Reply(m, title)
		}
		return true
	},
}
View Source
var UrbanDictionaryTrigger = NamedTrigger{
	ID:   "urbandict",
	Help: "Get an urban dictionary issued definition. Usage: !urbd [term]",
	Condition: func(irc *hbot.Bot, m *hbot.Message) bool {
		return m.Command == "PRIVMSG" && strings.HasPrefix(m.Trailing, "!ud")
	},
	Action: func(irc *hbot.Bot, m *hbot.Message) bool {
		resp := urbanDefinition(m.Content)
		irc.Reply(m, resp)
		return true
	},
}

Functions

func GetHtmlTitle

func GetHtmlTitle(r io.Reader) (string, bool)

func Run

func Run(config Config)

Types

type ACL added in v1.1.0

type ACL struct {
	// Defines users explicitly allowed in this ACL
	Permitted []string
	// Defines users explicitly rejected by this ACL
	Rejected []string
}

ACL defines access lists the bot may use to check Authorization to use a trigger

type Bot

type Bot struct {
	Bot    *hbot.Bot
	DB     *gorm.DB
	Random *rand.Rand // Initialized PRNG
	Config Config
	// contains filtered or unexported fields
}

func (*Bot) DropTrigger added in v1.2.1

func (b *Bot) DropTrigger(t NamedTrigger) bool

func (*Bot) FetchTrigger added in v1.1.0

func (b *Bot) FetchTrigger(name string) (NamedTrigger, bool)

func (Bot) GetOper

func (b Bot) GetOper()

func (*Bot) ListTriggers added in v1.2.1

func (b *Bot) ListTriggers() []string

ListTriggers gets all trigger IDs currently registered to the bot

func (Bot) NickservLogin

func (b Bot) NickservLogin() (string, bool)

func (Bot) OperLogin

func (b Bot) OperLogin() (string, bool)

func (*Bot) RegisterTrigger added in v1.1.0

func (b *Bot) RegisterTrigger(t NamedTrigger)

type Config

type Config struct {
	NickservPass string         // Nickserv password
	OperUser     string         // Username for server oper
	OperPass     string         // Password for server oper
	Channels     []string       // slice of channels to connect to (must include #)
	Nick         string         // nick to use
	Server       string         // server:port for connections
	SSL          bool           // Enable SSL for the connection
	Admins       ACL            // slice of masks representing administrators
	Plugins      []NamedTrigger // Plugins to start with
	Prometheus   bool           // Enable Prometheus
	PromAddr     string         // Listen address for prometheus endpoint
	DBConfig     DBConfig       // Configuration settings for Database connection
}

type Confirmed added in v1.3.1

type Confirmed struct {
	Latest    int         `json:"latest"`
	Locations []Locations `json:"locations"`
}

type Coordinates added in v1.3.1

type Coordinates struct {
	Latitude  float64 `json:"latitude"`
	Longitude float64 `json:"longitude"`
}

type Covid19Data added in v1.3.1

type Covid19Data struct {
	Confirmed Confirmed `json:"confirmed"`
	Deaths    Deaths    `json:"deaths"`
	Latest    Latest    `json:"latest"`
	Recovered Recovered `json:"recovered"`
	UpdatedAt string    `json:"updatedAt"`
}

type DB

type DB struct {
	DB *gorm.DB
}

type DBConfig added in v1.3.0

type DBConfig struct {
	User    string
	Pass    string
	Host    string
	Port    string
	Name    string
	SSLMode string
}

Configuration struct for Postgresql backend

type Deaths added in v1.3.1

type Deaths struct {
	Latest    int         `json:"latest"`
	Locations []Locations `json:"locations"`
}

type GeoData added in v1.2.2

type GeoData struct {
	IP       string
	Hostname string
	City     string
	Region   string
	Country  string
	Loc      string
	Org      string
	Postal   string
	Timezone string
	Readme   string
}

type Latest added in v1.3.1

type Latest struct {
	Confirmed int `json:"confirmed"`
	Deaths    int `json:"deaths"`
	Recovered int `json:"recovered"`
}

type Locations added in v1.3.1

type Locations struct {
	Coordinates Coordinates `json:"coordinates"`
	Country     string      `json:"country"`
	CountryCode string      `json:"country_code"`
	Latest      int         `json:"latest"`
	Province    string      `json:"province"`
}

type NamedTrigger added in v1.1.0

type NamedTrigger struct {
	ID        string // Name of trigger, to use used to registering, searching, and deregistering
	Help      string // Help text
	Condition func(*hbot.Bot, *hbot.Message) bool
	Action    func(*hbot.Bot, *hbot.Message) bool
	Init      func() error
}

NamedTrigger is a local re-implementation of hbot.Trigger to support unique names

func (NamedTrigger) Handle added in v1.1.0

func (t NamedTrigger) Handle(b *hbot.Bot, m *hbot.Message) bool

Handle executes the trigger action if the condition is satisfied

func (NamedTrigger) Name added in v1.1.0

func (t NamedTrigger) Name() string

Name satisfies the hbot.Handler interface

type Recovered added in v1.3.1

type Recovered struct {
	Latest    int         `json:"latest"`
	Locations []Locations `json:"locations"`
}

type ReminderEvent added in v1.3.1

type ReminderEvent struct {
	ID          int `gorm:"unique;AUTO_INCREMENT;PRIMARY_KEY"`
	Channel     string
	Author      string
	Description string
	People      string
	Time        time.Time
}

ReminderEvent : The Gorm struct that represents an event in the DB.

Jump to

Keyboard shortcuts

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