Skip to content
Snippets Groups Projects
Commit 46c5dc5b authored by Ophestra's avatar Ophestra
Browse files

rewrite of Nitori's internal multiplexer

parents
Branches
Tags v0.0.1
No related merge requests found
.idea/
package multiplexer
// Predefined command categories.
var (
AudioCategory = NewCategory("Audio",
"Audio related utilities.")
ExperienceCategory = NewCategory("Experience",
"Chat experience and ranking system.")
ManualsCategory = NewCategory("Manuals",
"The operation manual pager utility.")
MediaCategory = NewCategory("Media",
"Media related utilities.")
ModerationCategory = NewCategory("Moderation",
"Chat moderation utilities.")
SystemCategory = NewCategory("System",
"System-related utilities.")
)
package multiplexer
import (
"github.com/bwmarrin/discordgo"
"strconv"
"strings"
)
// NoCommandMatched is called when no command is matched.
var NoCommandMatched = func(context *Context) {
context.SendMessage("Command not found.")
}
// CommandHandler represents the handler function of a Route.
type CommandHandler func(*Context)
// Route represents a command route.
type Route struct {
Pattern string
AliasPatterns []string
Description string
Category *CommandCategory
Handler CommandHandler
}
// CommandCategory represents a category of Route.
type CommandCategory struct {
Routes []*Route
Title string
Description string
}
// MatchRoute fuzzy matches a message to a route.
func (mux *Multiplexer) MatchRoute(message string) (*Route, []string) {
fields := strings.Fields(message)
if len(fields) == 0 {
return nil, nil
}
var route *Route
var similarityRating int
var fieldIndex int
for fieldIndex, fieldIter := range fields {
for _, routeIter := range mux.Routes {
if routeIter.Pattern == fieldIter {
return routeIter, fields[fieldIndex:]
}
for _, aliasPattern := range routeIter.AliasPatterns {
if aliasPattern == fieldIter {
return routeIter, fields[fieldIndex:]
}
}
if strings.HasPrefix(routeIter.Pattern, fieldIter) {
if len(fieldIter) > similarityRating {
route = routeIter
similarityRating = len(fieldIter)
}
}
}
}
return route, fields[fieldIndex:]
}
func (mux *Multiplexer) handleMessageCommand(session *discordgo.Session, create *discordgo.MessageCreate) {
// Ignore self and bot messages
if create.Author.ID == session.State.User.ID || create.Author.Bot {
return
}
// Make Context
context := mux.NewContextMessage(session, create.Message, create)
if context == nil {
return
}
// Call not targeted hooks and return
if !context.IsTargeted {
go func() {
for _, hook := range mux.NotTargeted {
hook(context)
}
}()
return
}
// Log the processed message
var hostName string
if context.IsPrivate {
hostName = "Private Messages"
} else {
hostName = "\"" + context.Guild.Name + "\""
}
log.Infof("(Shard %s) \"%s\"@%s > %s",
strconv.Itoa(session.ShardID),
context.User.Username+"#"+context.User.Discriminator,
hostName,
context.Message.Content)
// Figure out the route of the message
if !(context.HasMention && !context.HasLeadingMention) {
route, fields := mux.MatchRoute(context.Text)
if route != nil {
context.Fields = fields
route.Handler(context)
return
}
}
NoCommandMatched(context)
}
package multiplexer
import (
"errors"
embedutil "git.randomchars.net/FreeNitori/EmbedUtil"
"github.com/bwmarrin/discordgo"
"github.com/sirupsen/logrus"
"regexp"
"strconv"
"strings"
)
// ErrUserNotFound represents the error returned when a user is not found.
var ErrUserNotFound = errors.New("user not found")
// GetPrefix is the function used to get a prefix of a guild.
var GetPrefix = func(context *Context) string {
return context.Multiplexer.Prefix
}
// Context carries an event's information.
type Context struct {
Multiplexer *Multiplexer
User *discordgo.User
Member *discordgo.Member
Message *discordgo.Message
Session *discordgo.Session
Guild *discordgo.Guild
Channel *discordgo.Channel
Event interface{}
Text string
Fields []string
IsPrivate bool
IsTargeted bool
HasPrefix bool
HasMention bool
HasLeadingMention bool
}
var numericalRegex = regexp.MustCompile("[^0-9]+")
// NumericalRegex returns a compiled regular expression that matches only numbers.
func (Context) NumericalRegex() *regexp.Regexp {
return numericalRegex
}
// SendMessage sends a text message in the current channel and returns the message.
func (context *Context) SendMessage(message string) *discordgo.Message {
permissions, err := context.Session.State.UserChannelPermissions(context.Session.State.User.ID, context.Message.ChannelID)
if !(err == nil && (permissions&discordgo.PermissionSendMessages == discordgo.PermissionSendMessages)) {
return nil
}
resultMessage, err := context.Session.ChannelMessageSend(context.Message.ChannelID, message)
if err != nil {
log.Errorf("Error while sending message to guild %s, %s", context.Message.GuildID, err)
_, _ = context.Session.ChannelMessageSend(context.Message.ChannelID,
ErrorOccurred)
return nil
}
return resultMessage
}
// SendEmbed sends an embedutil message in the current channel and returns the message.
func (context *Context) SendEmbed(message string, embed embedutil.Embed) *discordgo.Message {
var err error
permissions, err := context.Session.State.UserChannelPermissions(context.Session.State.User.ID, context.Message.ChannelID)
if !(err == nil && (permissions&discordgo.PermissionSendMessages == discordgo.PermissionSendMessages)) {
return nil
}
var resultMessage *discordgo.Message
if message == "" {
resultMessage, err = context.Session.ChannelMessageSendEmbed(context.Message.ChannelID, embed.MessageEmbed)
} else {
resultMessage, err = context.Session.ChannelMessageSendComplex(context.Message.ChannelID, &discordgo.MessageSend{
Content: message,
Embed: embed.MessageEmbed,
TTS: false,
Files: nil,
AllowedMentions: nil,
File: nil,
})
}
if err != nil {
log.Errorf("Error while sending embedutil to guild %s, %s", context.Message.GuildID, err)
_, _ = context.Session.ChannelMessageSend(context.Message.ChannelID,
ErrorOccurred)
return nil
}
return resultMessage
}
// HandleError handles a returned error and send the information of it if in debug mode.
func (context *Context) HandleError(err error) bool {
if err != nil {
log.Errorf("Error occurred while executing command, %s", err)
context.SendMessage(ErrorOccurred)
if log.GetLevel() == logrus.DebugLevel {
context.SendMessage(err.Error())
}
return false
}
return true
}
// HasPermission checks a user for a permission.
func (context *Context) HasPermission(permission int) bool {
// Override check for operators and system administrators
if context.User.ID == context.Multiplexer.Administrator.ID {
return true
}
for _, user := range context.Multiplexer.Operator {
if context.User.ID == user.ID {
return true
}
}
// Check against the user
permissions, err := context.Session.State.UserChannelPermissions(context.User.ID, context.Message.ChannelID)
return err == nil && (int(permissions)&permission == permission)
}
// IsOperator checks of a user is an operator.
func (context *Context) IsOperator() bool {
if context.User.ID == context.Multiplexer.Administrator.ID {
return true
}
for _, operator := range context.Multiplexer.Operator {
if context.User.ID == operator.ID {
return true
}
}
return false
}
// IsAdministrator checks of a user is the system administrator.
func (context *Context) IsAdministrator() bool {
return context.User.ID == context.Multiplexer.Administrator.ID
}
// GetMember gets a member from a string representing it.
func (context *Context) GetMember(query string) *discordgo.Member {
// Guild only function
if context.IsPrivate {
return nil
}
// Check if it's a mention or the string is numerical
_, err := strconv.Atoi(query)
if strings.HasPrefix(query, "<@") && strings.HasSuffix(query, ">") || err == nil {
// Strip off the mention thingy
userID := numericalRegex.ReplaceAllString(query, "")
// Length of a real snowflake after stripping off stuff
if len(userID) == 18 {
for _, member := range context.Guild.Members {
if member.User.ID == userID {
return member
}
}
}
} else {
// Find as username or nickname
for _, member := range context.Guild.Members {
if member.User.Username == query || member.Nick == query {
return member
}
}
}
return nil
}
// GetChannel gets a channel from a string representing it.
func (context *Context) GetChannel(query string) *discordgo.Channel {
// Guild only function
if context.IsPrivate {
return nil
}
// Check if it's a mention or the string is numerical
_, err := strconv.Atoi(query)
if strings.HasPrefix(query, "<#") && strings.HasSuffix(query, ">") || err == nil {
// Strip off the mention thingy
channelID := numericalRegex.ReplaceAllString(query, "")
// Length of a real snowflake after stripping off stuff
if len(channelID) == 18 {
for _, channel := range context.Guild.Channels {
if channel.ID == channelID {
return channel
}
}
}
} else {
// Find as channel name
for _, channel := range context.Guild.Channels {
if channel.Name == query {
return channel
}
}
}
return nil
}
// GetRole gets a channel from a string representing it.
func (context *Context) GetRole(query string) *discordgo.Role {
// Guild only function
if context.IsPrivate {
return nil
}
// Check if it's a mention or the string is numerical
_, err := strconv.Atoi(query)
if strings.HasPrefix(query, "<@&") && strings.HasSuffix(query, ">") || err == nil {
// Strip off the mention thingy
roleID := numericalRegex.ReplaceAllString(query, "")
// Length of a real snowflake after stripping off stuff
if len(roleID) == 18 {
for _, role := range context.Guild.Roles {
if role.ID == roleID {
return role
}
}
}
} else {
// Find as channel name
for _, role := range context.Guild.Roles {
if role.Name == query {
return role
}
}
}
return nil
}
// StitchFields stitches together fields of the message.
func (context *Context) StitchFields(start int) string {
message := context.Fields[start]
for i := start + 1; i < len(context.Fields); i++ {
message += " " + context.Fields[i]
}
return message
}
// Prefix returns the command prefix of a context.
func (context *Context) Prefix() string {
if context.IsPrivate {
return context.Multiplexer.Prefix
} else {
return GetPrefix(context)
}
}
// GetVoiceState returns the voice state of a user if found.
func (context *Context) GetVoiceState() (*discordgo.VoiceState, bool) {
if context.IsPrivate {
return nil, false
}
for _, voiceState := range context.Guild.VoiceStates {
if voiceState.UserID == context.User.ID {
return voiceState, true
}
}
return nil, false
}
// MakeVoiceConnection returns the voice connection to a user's voice channel if join-able.
func (context *Context) MakeVoiceConnection() (*discordgo.VoiceConnection, error) {
if context.IsPrivate {
return nil, nil
}
voiceState, ok := context.GetVoiceState()
if !ok {
return nil, nil
}
return context.Session.ChannelVoiceJoin(voiceState.GuildID, voiceState.ChannelID, false, true)
}
// Ban creates a ban on the specified user.
func (context *Context) Ban(query string) error {
// If Nitori has permission
permissions, err := context.Session.State.UserChannelPermissions(context.Session.State.User.ID, context.Message.ChannelID)
if !(err == nil && (permissions&discordgo.PermissionBanMembers == discordgo.PermissionBanMembers)) {
return discordgo.ErrUnauthorized
}
// Check if it's a mention or the string is numerical
_, err = strconv.Atoi(query)
if strings.HasPrefix(query, "<@") && strings.HasSuffix(query, ">") || err == nil {
// Strip off the mention thingy
userID := context.NumericalRegex().ReplaceAllString(query, "")
// Length of a real snowflake after stripping off stuff
if len(userID) == 18 {
err = context.Session.GuildBanCreate(context.Guild.ID, userID, 0)
return err
}
} else {
member := context.GetMember(query)
if member == nil {
return ErrUserNotFound
}
err = context.Session.GuildBanCreate(context.Guild.ID, member.User.ID, 0)
return err
}
return ErrUserNotFound
}
fetch.go 0 → 100644
package multiplexer
import "github.com/bwmarrin/discordgo"
// GetGuild fetches guild from cache then API and returns nil if all fails.
func GetGuild(session *discordgo.Session, id string) *discordgo.Guild {
var err error
var guild *discordgo.Guild
if id != "" {
guild, err = session.State.Guild(id)
if err != nil {
// Attempt direct API fetching
guild, err = session.Guild(id)
if err != nil {
log.Errorf("Unable to fetch guild from API or cache, %s", err)
return nil
}
// Attempt caching the channel
err = session.State.GuildAdd(guild)
if err != nil {
log.Warnf("Unable to cache guild fetched from API, %s", err)
}
}
}
return guild
}
// GetChannel fetches channel from cache then API and returns nil if all fails.
func GetChannel(session *discordgo.Session, id string) *discordgo.Channel {
var err error
var channel *discordgo.Channel
channel, err = session.State.Channel(id)
if err != nil {
// Attempt direct API fetching
channel, err = session.Channel(id)
if err != nil {
log.Errorf("Unable to fetch channel from API or cache, %s", err)
return nil
}
// Attempt caching the channel
err = session.State.ChannelAdd(channel)
if err != nil {
log.Warnf("Unable to cache channel fetched from API, %s", err)
}
}
return channel
}
package multiplexer
import "github.com/bwmarrin/discordgo"
// Event handler that fires when ready
func (mux *Multiplexer) onReady(session *discordgo.Session, ready *discordgo.Ready) {
go func() {
for _, hook := range mux.Ready {
hook(&Context{
Multiplexer: mux,
User: session.State.User,
Session: session,
Event: ready,
})
}
}()
return
}
// Event handler that fires when a guild member is added
func (mux *Multiplexer) onGuildMemberAdd(session *discordgo.Session, add *discordgo.GuildMemberAdd) {
go func() {
for _, hook := range mux.GuildMemberAdd {
guild := GetGuild(session, add.GuildID)
if guild == nil {
return
}
hook(&Context{
Multiplexer: mux,
Member: add.Member,
Session: session,
Guild: guild,
Event: add,
})
}
}()
return
}
// Event handler that fires when a guild member is removed
func (mux *Multiplexer) onGuildMemberRemove(session *discordgo.Session, remove *discordgo.GuildMemberRemove) {
go func() {
for _, hook := range mux.GuildMemberRemove {
guild := GetGuild(session, remove.GuildID)
if guild == nil {
return
}
hook(&Context{
Multiplexer: mux,
Member: remove.Member,
Session: session,
Guild: guild,
Event: remove,
})
}
}()
return
}
// Event handler that fires when a guild is deleted
func (mux *Multiplexer) onGuildDelete(session *discordgo.Session, delete *discordgo.GuildDelete) {
go func() {
for _, hook := range mux.GuildDelete {
hook(&Context{
Multiplexer: mux,
Session: session,
Guild: delete.Guild,
Event: delete,
})
}
}()
return
}
// Event handler that fires when a message is created
func (mux *Multiplexer) onMessageCreate(session *discordgo.Session, create *discordgo.MessageCreate) {
go func() {
for _, hook := range mux.MessageCreate {
context := mux.NewContextMessage(session, create.Message, create)
if context == nil {
return
}
hook(context)
}
}()
return
}
// Event handler that fires when a message is deleted
func (mux *Multiplexer) onMessageDelete(session *discordgo.Session, delete *discordgo.MessageDelete) {
go func() {
for _, hook := range mux.MessageDelete {
context := mux.NewContextMessage(session, delete.Message, delete)
if context == nil {
return
}
hook(context)
}
}()
return
}
// Event handler that fires when a message is updated
func (mux *Multiplexer) onMessageUpdate(session *discordgo.Session, update *discordgo.MessageUpdate) {
go func() {
for _, hook := range mux.MessageUpdate {
context := mux.NewContextMessage(session, update.Message, update)
if context == nil {
return
}
hook(context)
}
}()
return
}
// Event handler that fires when a reaction is added
func (mux *Multiplexer) onMessageReactionAdd(session *discordgo.Session, add *discordgo.MessageReactionAdd) {
go func() {
for _, hook := range mux.MessageReactionAdd {
message, err := session.ChannelMessage(add.ChannelID, add.MessageID)
if err != nil {
log.Errorf("Unable to get message %s from channel %s, %s", add.MessageID, add.ChannelID, err)
return
}
context := mux.NewContextMessage(session, message, add)
if context == nil {
return
}
hook(context)
}
}()
return
}
// Event handler that fires when a reaction is removed
func (mux *Multiplexer) onMessageReactionRemove(session *discordgo.Session, remove *discordgo.MessageReactionRemove) {
go func() {
for _, hook := range mux.MessageReactionRemove {
message, err := session.ChannelMessage(remove.ChannelID, remove.MessageID)
if err != nil {
log.Errorf("Unable to get message %s from channel %s, %s", remove.MessageID, remove.ChannelID, err)
return
}
context := mux.NewContextMessage(session, message, remove)
if context == nil {
return
}
hook(context)
}
}()
}
go.mod 0 → 100644
go.sum 0 → 100644
git.randomchars.net/FreeNitori/EmbedUtil v1.0.0 h1:EVJAigHC+1af3ncqRhzhdkypWmnbZlHCMsWMtxWAh1I=
git.randomchars.net/FreeNitori/EmbedUtil v1.0.0/go.mod h1:kZj3AXs1ozTGsziMu2GaUJv2KHnStOeqlDUAPVPfkY8=
github.com/bwmarrin/discordgo v0.23.2 h1:BzrtTktixGHIu9Tt7dEE6diysEF9HWnXeHuoJEt2fH4=
github.com/bwmarrin/discordgo v0.23.2/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g=
github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/magefile/mage v1.11.0 h1:C/55Ywp9BpgVVclD3lRnSYCwXTYxmSppIgLeDYlNuls=
github.com/magefile/mage v1.11.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.8.0 h1:nfhvjKcUMhBMVqbKHJlk5RPrrfYr/NMo3692g0dwfWU=
github.com/sirupsen/logrus v1.8.0/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210223095934-7937bea0104d h1:u0GOGnBJ3EKE/tNqREhhGiCzE9jFXydDo2lf7hOwGuc=
golang.org/x/sys v0.0.0-20210223095934-7937bea0104d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
log.go 0 → 100644
package multiplexer
import "github.com/sirupsen/logrus"
var log = logrus.New()
func init() {
log.SetFormatter(&logrus.TextFormatter{
ForceColors: false,
DisableColors: false,
ForceQuote: false,
DisableQuote: false,
EnvironmentOverrideColors: false,
DisableTimestamp: false,
FullTimestamp: true,
TimestampFormat: "",
DisableSorting: true,
SortingFunc: nil,
DisableLevelTruncation: false,
PadLevelText: false,
QuoteEmptyFields: false,
FieldMap: nil,
CallerPrettyfier: nil,
})
}
func SetLogger(logger *logrus.Logger) {
log = logger
}
package multiplexer
import "github.com/bwmarrin/discordgo"
// Multiplexer represents the event router.
type Multiplexer struct {
// Prefix is the default command prefix.
Prefix string
// Routes is a slice of pointers to command routes.
Routes []*Route
// Categories is a slice of pointers to CommandCategory.
Categories []*CommandCategory
// EventHandlers is a slice of event handler functions registered to the library directly
EventHandlers []interface{}
NotTargeted []func(context *Context)
Ready []func(context *Context)
GuildMemberAdd []func(context *Context)
GuildMemberRemove []func(context *Context)
GuildDelete []func(context *Context)
MessageCreate []func(context *Context)
MessageDelete []func(context *Context)
MessageUpdate []func(context *Context)
MessageReactionAdd []func(context *Context)
MessageReactionRemove []func(context *Context)
// Administrator is the privileged administrator user with all privilege overrides and full access to all commands.
Administrator *discordgo.User
// Operator is a slice of operator users with all privilege overrides and access to some restricted commands.
Operator []*discordgo.User
}
// Route registers a route to the router.
func (mux *Multiplexer) Route(route *Route) *Route {
route.Category.Routes = append(route.Category.Routes, route)
mux.Routes = append(mux.Routes, route)
return route
}
func (mux *Multiplexer) SessionRegisterHandlers(session *discordgo.Session) {
for _, handler := range mux.EventHandlers {
session.AddHandler(handler)
}
}
new.go 0 → 100644
package multiplexer
import (
"fmt"
"github.com/bwmarrin/discordgo"
"regexp"
"strings"
)
// New returns a command router.
func New(prefix string) *Multiplexer {
mux := &Multiplexer{
Prefix: prefix,
Categories: []*CommandCategory{AudioCategory, ExperienceCategory, ManualsCategory, MediaCategory, ModerationCategory, SystemCategory},
}
mux.EventHandlers = []interface{}{
mux.onReady,
}
return mux
}
// NewCategory returns a new command category
func NewCategory(name string, description string) *CommandCategory {
cat := &CommandCategory{
Title: name,
Description: description,
}
return cat
}
// NewContextMessage returns pointer to Context generated from a message.
func (mux *Multiplexer) NewContextMessage(session *discordgo.Session, message *discordgo.Message, event interface{}) *Context {
guild := GetGuild(session, message.GuildID)
if guild == nil {
return nil
}
channel := GetChannel(session, message.ChannelID)
if channel == nil {
return nil
}
context := &Context{
Multiplexer: mux,
User: message.Author,
Message: message,
Session: session,
Guild: guild,
Channel: channel,
Event: event,
Text: strings.TrimSpace(message.Content),
Fields: nil,
IsPrivate: channel.Type == discordgo.ChannelTypeDM,
}
// Get guild-specific prefix
guildPrefix := context.Prefix()
// Look for ping
for _, mentionedUser := range message.Mentions {
if mentionedUser.ID == session.State.User.ID {
context.IsTargeted, context.HasMention = true, true
mentionRegex := regexp.MustCompile(fmt.Sprintf("<@!?(%s)>", session.State.User.ID))
// If message have leading mention
location := mentionRegex.FindStringIndex(context.Text)
if len(location) == 0 {
context.HasLeadingMention = true
} else if location[0] == 0 {
context.HasLeadingMention = true
}
// Remove the mention string
context.Text = mentionRegex.ReplaceAllString(context.Text, "")
break
}
}
// Command prefix included or not
if !context.IsTargeted && len(guildPrefix) > 0 {
if strings.HasPrefix(context.Text, guildPrefix) {
context.IsTargeted, context.HasPrefix = true, true
context.Text = strings.TrimPrefix(context.Text, guildPrefix)
}
}
if !context.IsPrivate {
context.Member = message.Member
}
return context
}
package multiplexer
// InvalidArgument is the message sent when the user passes an invalid argument.
const InvalidArgument = "Invalid argument."
// ErrorOccurred is the message sent when the event handler catches an error.
const ErrorOccurred = "Something went wrong and I am very confused! Please try again!"
// GuildOnly is the message sent when a guild-only command is issued in private.
const GuildOnly = "This command can only be issued from a guild."
// FeatureDisabled is the message sent when a feature requested by the user is disabled.
const FeatureDisabled = "This feature is currently disabled."
// AdminOnly is the message sent when an unprivileged user invokes an admin-only request.
const AdminOnly = "This command is only available to system administrators!"
// OperatorOnly is the message sent when an unprivileged user invokes an operator-only request.
const OperatorOnly = "This command is only available to operators!"
// PermissionDenied is the message sent when the user invokes a request without sufficient permission.
const PermissionDenied = "You are not allowed to issue this command!"
// MissingUser is the message sent when a specified user does not exist.
const MissingUser = "Specified user does not exist."
// LackingPermission is the message sent when lacking permission for an operation.
const LackingPermission = "Lacking permission to perform specified action."
// KappaColor is the primary color of the kappa.
const KappaColor = 0x3492c4
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment