lightning

package
v0.9.4 Latest Latest
Warning

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

Go to latest
Published: Sep 4, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package lightning provides a cross-platform extensible bot framework, allowing you to make bots that support multiple platforms while abstracting platform-specific code with plugins. It handles features such as attachments, commands, embeds, mentions, and more.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Attachment

type Attachment struct {
	// A downloadable https (not http, which will fail) URL pointing to the file.
	URL string `json:"url"`
	// A somewhat user-friendly file name.
	Name string `json:"name"`
	// File size in bytes.
	Size int64 `json:"size"`
	// Mimetype for the file (not always set).
	Type string `json:"type,omitempty"`
	// Description for the file (not always set).
	Description string `json:"description,omitempty"`
}

An Attachment represents a downloadable file used in a Message.

type BaseMessage

type BaseMessage struct {
	// Time the event was created (or possibly received).
	Time time.Time `json:"time,omitzero"`
	// Unique identifier for the event.
	EventID string `json:"event_id"`
	// Channel where the event happened.
	ChannelID string `json:"channel_id"`
}

BaseMessage is a minimal reference to a given message, containing a timestamp, ID, and originating channel. It is used to represent deleted message events with Bot.AddHandler and Plugin.ListenDeletes, and is also used in [Message]s to provide a common type for these fields and for event handling abstractions.

type Bot

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

Bot represents the collection of platform plugins, commands, and event handlers, keeping track of those along with the command prefix.

func NewBot

func NewBot(prefix string) *Bot

NewBot creates a new *Bot instance with the specified prefix, along with listeners handling platform-specific command events (like slash commands) and text commands.

func (*Bot) AddCommand

func (b *Bot) AddCommand(commands ...Command)

AddCommand registers the provided [Command]s on a Bot instance and will call Plugin.SetupCommands on each loaded plugin to register platform-native command handling. Registered commands will get called when either a text command beginning with the prefix provided to NewBot, or a CommandEvent provided through plugin.ListenCommands, are received. For example, the following is a basic ping command:

bot.AddCommand(lightning.Command{
	Name: "ping", Description: "pings the bot",
	Executor: func (options *lightning.CommandOptions) {
		options.Reply(&lightning.Message{
			Content: "pong!",
		})
	}
})

func (*Bot) AddHandler

func (b *Bot) AddHandler(listener any)

AddHandler registers an event handler on a Bot instance, allowing you to receive specific event types from registered plugins. Each handler should be in the form of `func(*Bot, T)`, where T is a struct that corresponds to the event you wish to listen for. For example, to listen for new messages and print their content:

bot.AddHandler(func(b *lightning.Bot, msg *lightning.Message) {
	log.Printf("incoming message: %+v\n", msg)
})

Event types you may listen for are as follows:

- *EditedMessage: edited messages;

- *Message: created messages; and

- *BaseMessage: deleted messages.

func (*Bot) AddPluginType

func (b *Bot) AddPluginType(name string, constructor PluginConstructor)

AddPluginType registers a given PluginConstructor by name for future use in Bot.UsePluginType. For example, the following will allow you to register an instance of a Discord plugin later using Bot.UsePluginType:

 import (
	"codeberg.org/jersey/lightning/pkg/lightning"
	"codeberg.org/jersey/lightning/pkg/platforms/discord"
 )

 func main() {
	bot := lightning.NewBot("!")

	bot.AddPluginType("discord", discord.New)
 }

It will overwrite existing registered plugin types if the name is a duplicate, though this will not affect existing instances created by Bot.UsePluginType.

func (*Bot) DeleteMessages

func (b *Bot) DeleteMessages(channelID string, ids []string, opts *MessageOptions) error

DeleteMessages deletes the provided message ids provided by Bot.SendMessage or Bot.EditMessage in a given channel with the provided MessageOptions.

func (*Bot) EditMessage

func (b *Bot) EditMessage(message *Message, ids []string, opts *MessageOptions) ([]string, error)

EditMessage edits the provided Message with ids provided by Bot.SendMessage and the options in the provided MessageOptions.

func (*Bot) IsAdmin added in v0.8.5

func (b *Bot) IsAdmin(channelID, user string) (bool, error)

IsAdmin allows you to check if a given user has administrator (or similar) privileges within a channel.

func (*Bot) SendMessage

func (b *Bot) SendMessage(message *Message, opts *MessageOptions) ([]string, error)

SendMessage sends the provided Message to the channel ID provided with the given MessageOptions.

func (*Bot) SendTyping added in v0.9.3

func (b *Bot) SendTyping(channelID, userID string, opts *MessageOptions) error

SendTyping shows the bot as typing in a given channel with the provided MessageOptions.

func (*Bot) SetupChannel

func (b *Bot) SetupChannel(channelID string) (map[string]string, error)

SetupChannel allows you to create channel data used in MessageOptions to send messages with a webhook, or another interface allowing for masquerades or similar.

func (*Bot) UsePluginType

func (b *Bot) UsePluginType(typeName, instanceName string, config map[string]string, data PluginDataStorage) error

UsePluginType creates a plugin of a provided typeName, as specified in Bot.AddPluginType, using the provided instanceName, config struct, and optional PluginDataStorage. It will return an error if a duplicate instanceName exists, or if the provided typeName has not been registered. For example, the following will register a Discord plugin and create an instance of it:

 import (
	"codeberg.org/jersey/lightning/pkg/lightning"
	"codeberg.org/jersey/lightning/pkg/platforms/discord"
 )

 func main() {
	bot := lightning.NewBot("!")

	bot.AddPluginType("discord", discord.New)

	err := bot.AddPluginType("discord", "discord", map[string]string{
		// see the documentation for [Discord.New] for configuration information
	}, nil)
 }

The provided config struct will be documented by the PluginConstructor provided to Bot.AddPluginType.

Once a plugin has been registered, [startPluginListeners] will be called to allow event handlers registered with Bot.AddHandler to receive events from the new plugin instance, and you will be able to call methods on Bot that refer to channels from that plugin instance, such as Bot.SendMessage.

type BotReliant added in v0.9.3

type BotReliant interface {
	DoNotUseThisUnlessYouAreAnAPIPluginGetBot(bot *Bot, instanceName string)
}

BotReliant is an optional interface which a Plugin can implement to receive the *Bot instance which calls it. It should not be relied upon by most plugins, except in instances where it needs to forward events to external sources.

type ChannelDisabled

type ChannelDisabled struct {
	// Read indicates whether you are unable to read from a channel anymore (getting messages).
	Read bool `json:"read"`
	// Write indicates whether you are unable to write to a channel anymore (sending messages).
	Write bool `json:"write"`
}

ChannelDisabled is used in errors implementing ChannelDisabler to indicate whether an error affecting a channel prevents future reads from or writes to the channel.

type ChannelDisabler

type ChannelDisabler interface {
	error

	// Disable returns a [*ChannelDisabled] which describes whether you are unable to read/write to a channel.
	Disable() *ChannelDisabled
}

ChannelDisabler is an optional interface where plugin errors indicate the properties described in ChannelDisabled.

type Command

type Command struct {
	// Executor is the function that gets called when a user executes the command.
	Executor func(options *CommandOptions)
	// Name is a unique string identifying the command.
	Name string
	// Description is a string describing the command and its purpose.
	Description string
	// Subcommands is a map of nested commands.
	Subcommands map[string]Command
	// Arguments are input fields which get parsed into [CommandOptions.Arguments] and passed to the Executor.
	Arguments []CommandArgument
}

A Command is a user-facing executable action which can generate a response by calling CommandOptions.Reply and using the given arguments and options. It may have subcommands, which are nested commands.

type CommandArgument

type CommandArgument struct {
	// Name is a unique string identifying the argument.
	Name string
	// Description is a string describing the argument and its purpose.
	Description string
}

A CommandArgument is a possible argument for a Command.

type CommandEvent

type CommandEvent struct {
	CommandOptions

	// Subcommand the first subcommand used, if any. Should not be used with Options.
	Subcommand string
	// Command is the name of the command called; it is required.
	Command string
	// Options is a variadic list of arguments which have not been parsed and may include a subcommand. Should not be
	// used with Options.
	Options []string
}

CommandEvent represents a command being called by a user on a platform using native commands, such as slash-commands on Discord.

type CommandOptions

type CommandOptions struct {
	BaseMessage

	// Arguments contains parsed [CommandArgument] key-value pairs.
	Arguments map[string]string
	// Author is the user which executed the [Command].
	Author MessageAuthor
	// Bot refers to the [*Bot] instance a [Command] was executed on.
	Bot *Bot
	// Reply creates a new [Message] which replies to the message executing the command.
	Reply func(message *Message, sensitive bool)
	// Prefix is the prefix used when creating the [*Bot] instance the [Command] was executed on.
	Prefix string
}

CommandOptions are provided to a Command executor.

type EditedMessage

type EditedMessage struct {
	Message
}

EditedMessage is an edited Message.

type Embed

type Embed struct {
	// Author is an optional author on an embed.
	Author *EmbedAuthor `json:"author,omitempty"`
	// Footer is an optional footer on an embed.
	Footer *EmbedFooter `json:"footer,omitempty"`
	// Image is full-width optional [Media] on an embed.
	Image *Media `json:"image,omitempty"`
	// Thumbnail is small optional [Media] on an embed typically in the top-right.
	Thumbnail *Media `json:"thumbnail,omitempty"`
	// Video is full-width optional [Media] on an embed.
	Video *Media `json:"video,omitempty"`
	// Timestamp is an optional RFC3339 formatted time.
	Timestamp string `json:"timestamp,omitempty"`
	// Title is an optional title preceding an embed.
	Title string `json:"title,omitempty"`
	// URL is an optional link for an embed title.
	URL string `json:"url,omitempty"`
	// Description is the main body of an embed.
	Description string `json:"description,omitempty"`
	// Fields are optional additions to an embed.
	Fields []EmbedField `json:"fields,omitempty"`
	// Color is an RGB color value for an embed.
	Color int `json:"color,omitzero"`
}

Embed is a Discord-style embed.

func (*Embed) ToMarkdown

func (embed *Embed) ToMarkdown() string

ToMarkdown transforms Discord-style [Embed]s into a Markdown-formatted string. Elements are mapped sequentially based on the order used in the Discord app: Title (with optional URL and Timestamp); Author Information; Descriptions; Embedded Media; Fields; and Footers.

type EmbedAuthor

type EmbedAuthor struct {
	// URL is a link the Name points to.
	URL string `json:"url,omitempty"`
	// IconURL is an https URL pointing to an icon to be shown next to the Name.
	IconURL string `json:"icon_url,omitempty"`
	// Name is a string to be shown above the rest of an [Embed].
	Name string `json:"name,omitempty"`
}

EmbedAuthor is an author on an Embed.

type EmbedField

type EmbedField struct {
	// Name is bold text shown above/next to the Value.
	Name string `json:"name,omitempty"`
	// Value is a string show below an [Embed.Description].
	Value string `json:"value,omitempty"`
	// Inline controls whether a field should be shown on a newline.
	Inline bool `json:"inline,omitzero"`
}

EmbedField is a field on an Embed.

type EmbedFooter

type EmbedFooter struct {
	// IconURL is an https URL pointing to an icon to be shown next to the Text.
	IconURL string `json:"icon_url,omitempty"`
	// Text is a string to be shown below the rest of an [Embed].
	Text string `json:"text,omitempty"`
}

EmbedFooter is a footer on an Embed.

type Media

type Media struct {
	// URL is a downloadable https url pointing to the image.
	URL string `json:"url"`
	// Height is an optional height for an embed image.
	Height int `json:"height,omitzero"`
	// Width is an optional width for an embed image.
	Width int `json:"width,omitzero"`
}

Media represents images/videos on an Embed.

type Mention added in v0.9.0

type Mention struct {
	// Name is a user-facing fallback for the thing being mentioned.
	Name string `json:"name"`
	// Text is the content mentioning the user.
	Mention string `json:"mention"`
	// URL is an optional link pointing to the thing mentioned.
	URL string `json:"url,omitempty"`
	// Type is the thing being mentioned.
	Type MentionType `json:"type"`
}

A Mention is a way to mention a specific person, group of people, all the online users, or everyone in a channel.

type MentionType added in v0.9.0

type MentionType int

MentionType is a specific type of mention.

const (
	// MentionUser is for mentioning an individual user.
	MentionUser MentionType = iota
	// MentionRole is for mentioning a specific group of users.
	MentionRole
	// MentionOnline is for @here/@online mentions, allowing you to ping all the online users.
	MentionOnline
	// MentionEveryone is for @room/@everyone mentions, allowing you to ping everyone in the channel.
	MentionEveryone
	// MentionEmoji is for emoji. Although these aren't mentions, they reference specific emoji.
	MentionEmoji
	// MentionTimestamp represents a timestamp mention.
	MentionTimestamp
)

type Message

type Message struct {
	BaseMessage

	// Author is the person or bot who sent a message.
	Author MessageAuthor `json:"author,omitzero"`
	// Content is a Markdown-like string in a message.
	Content string `json:"content,omitempty"`
	// [Attachment]s are downloadable files on a message.
	Attachments []Attachment `json:"attachments,omitempty"`
	// Embeds are Discord-like [Embed]s on a message. Some platforms transform them into text using [Embed.ToMarkdown].
	Embeds []Embed `json:"embeds,omitempty"`
	// RepliedTo contains a list of message IDs to reply to. Some platforms only support using the first reply ID.
	RepliedTo []string `json:"replied_to,omitempty"`
	// Mentions are the specific [Mention]s on a message.
	Mentions []Mention `json:"mentions,omitempty"`
}

Message is a representation of a message on a platform.

type MessageAuthor

type MessageAuthor struct {
	// ID is the user's ID on their originating platform.
	ID string `json:"id"`
	// Username is the user's display name.
	Username string `json:"username"`
	// ProfilePicture is a URL pointing to a downloadable profile picture.
	ProfilePicture string `json:"profile_picture,omitempty"`
	// Color is a six character hex color code (with preceding hashtag) representing a role/profile color.
	Color string `json:"color,omitempty"`
}

MessageAuthor is an author on an Message.

type MessageOptions added in v0.9.0

type MessageOptions struct {
	// DMUser allows you to send a message to a given user directly, if available on the platform.
	DMUser string `json:"dm_user,omitempty"`
	// ChannelData allows you to send messages with a webhook, or another interface allowing for masquerades or similar.
	ChannelData map[string]string `json:"channel_data,omitempty"`
	// UsernameSuffix allows you to specify an optional suffix for the given username. It exists to make bridging
	// slightly easier by ensuring the suffix is added appropriately.
	UsernameSuffix string `json:"username_suffix,omitempty"`
	// AllowEveryonePings, when set, allows you sending a [Mention] with a type of either [MentionOnline] or
	// [MentionEveryone].
	AllowEveryonePings bool `json:"allow_everyone_pings,omitzero"`
}

MessageOptions allows you to change how messages are sent/edited/deleted.

type MissingPluginError added in v0.9.0

type MissingPluginError struct {
	Name string
}

MissingPluginError is returned by Bot.UsePluginType when a plugin constructor for a given typeName cannot be found or by [Bot.getPluginFromChannel] when an instanceName cannot be found when trying to run a plugin method.

func (MissingPluginError) Error added in v0.9.0

func (p MissingPluginError) Error() string

type Plugin

type Plugin interface {
	// IsAdmin allows you to check if a given user has administrator (or similar) privileges within a channel.
	IsAdmin(channel, user string) (bool, error)
	// SetupChannel allows you to create channel data used in [MessageOptions] to send messages with a webhook, or
	// another interface allowing for masquerades or similar.
	SetupChannel(channel string) (map[string]string, error)
	// SendMessage sends the provided [Message] to the channel ID provided with the given [MessageOptions].
	SendMessage(message *Message, opts *MessageOptions) ([]string, error)
	// EditMessage edits the provided [Message] with ids provided by [Plugin.SendMessage] and the options in the
	// provided [MessageOptions].
	EditMessage(message *Message, ids []string, opts *MessageOptions) ([]string, error)
	// DeleteMessage deletes the provided message ids provided by [Plugin.SendMessage] or [Plugin.EditMessage] in a
	// given channel with the provided [MessageOptions].
	DeleteMessage(channel string, ids []string, opts *MessageOptions) error
	// SendTyping allows you to show typing in a channel in a given channel with the provided [MessageOptions].
	SendTyping(channel, user string, opts *MessageOptions) error
	// SetupCommands allows calls to [Bot.AddCommand] to register platform-specific handlers for commands, such as slash
	// commands.
	SetupCommands(command map[string]Command)
	// ListenMessages allows calls to [Bot.AddHandler] to receive message creation events from the platform.
	ListenMessages() <-chan *Message
	// ListenEdits allows calls to [Bot.AddHandler] to receive message edit events from the platform.
	ListenEdits() <-chan *EditedMessage
	// ListenDeletes allows calls to [Bot.AddHandler] to receive message deletion events from the platform.
	ListenDeletes() <-chan *BaseMessage
	// ListenCommands allows commands registered in [Bot.AddCommand] to be executed by platform-specific handlers for
	// commands, such as slash commands.
	ListenCommands() <-chan *CommandEvent
	// ListenTyping allows calls to [Bot.AddHandler] to receive typing events from the platform.
	ListenTyping() <-chan *TypingEvent
}

A Plugin is the interface used to define interactions with a given chat platform. It's used by Bot to allow the framework, and bots written using it, to support an arbitrary number of platforms without having to worry about platform-specifics.

type PluginConstructor

type PluginConstructor func(config map[string]string, data PluginDataStorage) (Plugin, error)

A PluginConstructor is used by Bot.UsePluginType to allow registration of a future plugin instance, abstracting platform support and allowing for the creation of cross-platform bots. Typically, a PluginConstructor documents the config it takes in with documentation comments describing expected parameters. Additionally, a PluginConstructor or the actual plugin should not rely on the existence of a non-nil PluginDataStorage argument, as one may choose not to persist this data.

type PluginDataStorage added in v0.9.0

type PluginDataStorage interface {
	StoreData(data map[string]any) error
	ReadData() (map[string]any, error)
}

PluginDataStorage is an optional interface allowing for plugins to persist permanent data, such as channel lists on IRC. To provide the ability to persist data, pass a non-nil value for the interface to a PluginConstructor.

type PluginMethodError

type PluginMethodError struct {
	ID     string
	Method string
	// contains filtered or unexported fields
}

PluginMethodError is returned by various Bot methods when a plugin returns an error for a given method.

func (PluginMethodError) Error

func (p PluginMethodError) Error() string

func (PluginMethodError) Unwrap

func (p PluginMethodError) Unwrap() error

type PluginRegisteredError

type PluginRegisteredError struct {
	Name string
}

PluginRegisteredError is returned by Bot.UsePluginType when a given instanceName is already in use on a Bot.

func (PluginRegisteredError) Error

func (p PluginRegisteredError) Error() string

type TypingEvent added in v0.9.3

type TypingEvent struct {
	// Time the typing started.
	Time time.Time `json:"time,omitzero"`
	// Channel where the event happened.
	ChannelID string `json:"channel_id"`
	// User who is typing.
	UserID string `json:"user_id"`
}

TypingEvent represents a user starting to type in a channel.

Jump to

Keyboard shortcuts

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