Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 90e2f38c18 | |||
| 0921d306fd | |||
| 6970c37c6b |
12
bot.go
12
bot.go
@@ -30,8 +30,8 @@ type Bot struct {
|
|||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
requestLogger *slog.Logger
|
requestLogger *slog.Logger
|
||||||
|
|
||||||
plugins []*Plugin
|
plugins []Plugin
|
||||||
middlewares []*Middleware
|
middlewares []Middleware
|
||||||
prefixes []string
|
prefixes []string
|
||||||
runners []Runner
|
runners []Runner
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ func LoadPrefixesFromEnv() []string {
|
|||||||
func NewBot(settings *BotSettings) *Bot {
|
func NewBot(settings *BotSettings) *Bot {
|
||||||
updateQueue := CreateQueue[*Update](256)
|
updateQueue := CreateQueue[*Update](256)
|
||||||
bot := &Bot{
|
bot := &Bot{
|
||||||
updateOffset: 0, plugins: make([]*Plugin, 0), debug: settings.Debug, errorTemplate: "%s",
|
updateOffset: 0, plugins: make([]Plugin, 0), debug: settings.Debug, errorTemplate: "%s",
|
||||||
prefixes: settings.Prefixes, updateTypes: make([]string, 0), runners: make([]Runner, 0),
|
prefixes: settings.Prefixes, updateTypes: make([]string, 0), runners: make([]Runner, 0),
|
||||||
updateQueue: updateQueue,
|
updateQueue: updateQueue,
|
||||||
token: settings.Token,
|
token: settings.Token,
|
||||||
@@ -171,20 +171,20 @@ func (b *Bot) Debug(debug bool) *Bot {
|
|||||||
b.debug = debug
|
b.debug = debug
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
func (b *Bot) AddPlugins(plugin ...*Plugin) *Bot {
|
func (b *Bot) AddPlugins(plugin ...Plugin) *Bot {
|
||||||
b.plugins = append(b.plugins, plugin...)
|
b.plugins = append(b.plugins, plugin...)
|
||||||
for _, p := range plugin {
|
for _, p := range plugin {
|
||||||
b.logger.Debugln(fmt.Sprintf("plugins with name \"%s\" registered", p.Name))
|
b.logger.Debugln(fmt.Sprintf("plugins with name \"%s\" registered", p.Name))
|
||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
func (b *Bot) AddMiddleware(middleware ...*Middleware) *Bot {
|
func (b *Bot) AddMiddleware(middleware ...Middleware) *Bot {
|
||||||
b.middlewares = append(b.middlewares, middleware...)
|
b.middlewares = append(b.middlewares, middleware...)
|
||||||
for _, m := range middleware {
|
for _, m := range middleware {
|
||||||
b.logger.Debugln(fmt.Sprintf("middleware with name \"%s\" registered", m.Name))
|
b.logger.Debugln(fmt.Sprintf("middleware with name \"%s\" registered", m.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(&b.middlewares, func(i, j int) bool {
|
sort.Slice(b.middlewares, func(i, j int) bool {
|
||||||
first := b.middlewares[i]
|
first := b.middlewares[i]
|
||||||
second := b.middlewares[j]
|
second := b.middlewares[j]
|
||||||
if first.Order == second.Order {
|
if first.Order == second.Order {
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -3,7 +3,7 @@ module git.nix13.pw/scuroneko/laniakea
|
|||||||
go 1.25
|
go 1.25
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.nix13.pw/scuroneko/slog v1.0.0
|
git.nix13.pw/scuroneko/slog v1.0.2
|
||||||
github.com/redis/go-redis/v9 v9.17.3
|
github.com/redis/go-redis/v9 v9.17.3
|
||||||
github.com/vinovest/sqlx v1.7.1
|
github.com/vinovest/sqlx v1.7.1
|
||||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -1,7 +1,7 @@
|
|||||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
git.nix13.pw/scuroneko/slog v1.0.0 h1:PI0YePrmCopjrljUfwCtBIEwNYB+PBgDzPcCXbetpcE=
|
git.nix13.pw/scuroneko/slog v1.0.2 h1:vZyUROygxC2d5FJHUQM/30xFEHY1JT/aweDZXA4rm2g=
|
||||||
git.nix13.pw/scuroneko/slog v1.0.0/go.mod h1:3Qm2wzkR5KjwOponMfG7TcGSDjmYaFqRAmLvSPTuWJI=
|
git.nix13.pw/scuroneko/slog v1.0.2/go.mod h1:3Qm2wzkR5KjwOponMfG7TcGSDjmYaFqRAmLvSPTuWJI=
|
||||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ func (b *Bot) handleCallback(update *Update, ctx *MsgContext) {
|
|||||||
ctx.From = update.CallbackQuery.From
|
ctx.From = update.CallbackQuery.From
|
||||||
ctx.Msg = update.CallbackQuery.Message
|
ctx.Msg = update.CallbackQuery.Message
|
||||||
ctx.CallbackMsgId = update.CallbackQuery.Message.MessageID
|
ctx.CallbackMsgId = update.CallbackQuery.Message.MessageID
|
||||||
|
ctx.CallbackQueryId = update.CallbackQuery.ID
|
||||||
ctx.Args = data.Args
|
ctx.Args = data.Args
|
||||||
|
|
||||||
for _, plugin := range b.plugins {
|
for _, plugin := range b.plugins {
|
||||||
|
|||||||
27
methods.go
27
methods.go
@@ -130,7 +130,28 @@ type DeleteMessageP struct {
|
|||||||
MessageID int `json:"message_id"`
|
MessageID int `json:"message_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bot) DeleteMessage(params *DeleteMessageP) (*Message, error) {
|
func (b *Bot) DeleteMessage(params *DeleteMessageP) (bool, error) {
|
||||||
req := NewRequest[Message]("deleteMessage", params)
|
req := NewRequest[bool]("deleteMessage", params)
|
||||||
return req.Do(b)
|
ok, err := req.Do(b)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return *ok, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type AnswerCallbackQueryP struct {
|
||||||
|
CallbackQueryID string `json:"callback_query_id"`
|
||||||
|
Text string `json:"text,omitempty"`
|
||||||
|
ShowAlert bool `json:"show_alert,omitempty"`
|
||||||
|
URL string `json:"url,omitempty"`
|
||||||
|
CacheTime int `json:"cache_time,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bot) AnswerCallbackQuery(params *AnswerCallbackQueryP) (bool, error) {
|
||||||
|
req := NewRequest[bool]("answerCallbackQuery", params)
|
||||||
|
ok, err := req.Do(b)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return *ok, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ type MsgContext struct {
|
|||||||
Update *Update
|
Update *Update
|
||||||
From *User
|
From *User
|
||||||
CallbackMsgId int
|
CallbackMsgId int
|
||||||
|
CallbackQueryId string
|
||||||
FromID int
|
FromID int
|
||||||
Prefix string
|
Prefix string
|
||||||
Text string
|
Text string
|
||||||
@@ -151,14 +152,41 @@ func (ctx *MsgContext) CallbackDelete() {
|
|||||||
ctx.delete(ctx.CallbackMsgId)
|
ctx.delete(ctx.CallbackMsgId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *MsgContext) Error(err error) {
|
func (ctx *MsgContext) answerCallbackQuery(url, text string, showAlert bool) {
|
||||||
_, sendErr := ctx.Bot.SendMessage(&SendMessageP{
|
if len(ctx.CallbackQueryId) == 0 {
|
||||||
ChatID: ctx.Msg.Chat.ID,
|
return
|
||||||
Text: fmt.Sprintf(ctx.Bot.errorTemplate, EscapeMarkdown(err.Error())),
|
}
|
||||||
|
_, err := ctx.Bot.AnswerCallbackQuery(&AnswerCallbackQueryP{
|
||||||
|
CallbackQueryID: ctx.CallbackQueryId,
|
||||||
|
Text: text, ShowAlert: showAlert, URL: url,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
ctx.Bot.logger.Errorln(err)
|
ctx.Bot.logger.Errorln(err)
|
||||||
|
|
||||||
if sendErr != nil {
|
|
||||||
ctx.Bot.logger.Errorln(sendErr)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func (ctx *MsgContext) AnswerCbQuery() {
|
||||||
|
ctx.answerCallbackQuery("", "", false)
|
||||||
|
}
|
||||||
|
func (ctx *MsgContext) AnswerCbQueryText(text string) {
|
||||||
|
ctx.answerCallbackQuery("", text, false)
|
||||||
|
}
|
||||||
|
func (ctx *MsgContext) AnswerCbQueryAlert(text string) {
|
||||||
|
ctx.answerCallbackQuery("", text, true)
|
||||||
|
}
|
||||||
|
func (ctx *MsgContext) AnswerCbQueryUrl(u string) {
|
||||||
|
ctx.answerCallbackQuery(u, "", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *MsgContext) error(err error) {
|
||||||
|
text := fmt.Sprintf(ctx.Bot.errorTemplate, EscapeMarkdown(err.Error()))
|
||||||
|
|
||||||
|
if ctx.CallbackQueryId != "" {
|
||||||
|
ctx.answerCallbackQuery("", text, false)
|
||||||
|
} else {
|
||||||
|
ctx.answer(text, nil)
|
||||||
|
}
|
||||||
|
ctx.Bot.logger.Errorln(err)
|
||||||
|
}
|
||||||
|
func (ctx *MsgContext) Error(err error) {
|
||||||
|
ctx.error(err)
|
||||||
|
}
|
||||||
|
|||||||
22
plugins.go
22
plugins.go
@@ -45,17 +45,16 @@ func (p *PluginBuilder) UpdateListener(listener CommandExecutor) *PluginBuilder
|
|||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PluginBuilder) Build() *Plugin {
|
func (p *PluginBuilder) Build() Plugin {
|
||||||
if len(p.commands) == 0 && len(p.payloads) == 0 {
|
if len(p.commands) == 0 && len(p.payloads) == 0 {
|
||||||
log.Println("no command or payloads")
|
log.Println("no command or payloads")
|
||||||
}
|
}
|
||||||
plugin := &Plugin{
|
return Plugin{
|
||||||
Name: p.name,
|
Name: p.name,
|
||||||
Commands: p.commands,
|
Commands: p.commands,
|
||||||
Payloads: p.payloads,
|
Payloads: p.payloads,
|
||||||
UpdateListener: p.updateListener,
|
UpdateListener: p.updateListener,
|
||||||
}
|
}
|
||||||
return plugin
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) Execute(cmd string, ctx *MsgContext, dbContext *DatabaseContext) {
|
func (p *Plugin) Execute(cmd string, ctx *MsgContext, dbContext *DatabaseContext) {
|
||||||
@@ -68,13 +67,13 @@ func (p *Plugin) ExecutePayload(payload string, ctx *MsgContext, dbContext *Data
|
|||||||
|
|
||||||
type Middleware struct {
|
type Middleware struct {
|
||||||
Name string
|
Name string
|
||||||
Executor *CommandExecutor
|
Executor CommandExecutor
|
||||||
Order int
|
Order int
|
||||||
Async bool
|
Async bool
|
||||||
}
|
}
|
||||||
type MiddlewareBuilder struct {
|
type MiddlewareBuilder struct {
|
||||||
name string
|
name string
|
||||||
executor *CommandExecutor
|
executor CommandExecutor
|
||||||
order int
|
order int
|
||||||
async bool
|
async bool
|
||||||
}
|
}
|
||||||
@@ -87,7 +86,7 @@ func (m *MiddlewareBuilder) SetName(name string) *MiddlewareBuilder {
|
|||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
func (m *MiddlewareBuilder) SetExecutor(executor CommandExecutor) *MiddlewareBuilder {
|
func (m *MiddlewareBuilder) SetExecutor(executor CommandExecutor) *MiddlewareBuilder {
|
||||||
m.executor = &executor
|
m.executor = executor
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
func (m *MiddlewareBuilder) SetOrder(order int) *MiddlewareBuilder {
|
func (m *MiddlewareBuilder) SetOrder(order int) *MiddlewareBuilder {
|
||||||
@@ -98,19 +97,18 @@ func (m *MiddlewareBuilder) SetAsync(async bool) *MiddlewareBuilder {
|
|||||||
m.async = async
|
m.async = async
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
func (m *MiddlewareBuilder) Build() *Middleware {
|
func (m *MiddlewareBuilder) Build() Middleware {
|
||||||
return &Middleware{
|
return Middleware{
|
||||||
Name: m.name,
|
Name: m.name,
|
||||||
Executor: m.executor,
|
Executor: m.executor,
|
||||||
Order: m.order,
|
Order: m.order,
|
||||||
Async: m.async,
|
Async: m.async,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (m *Middleware) Execute(ctx *MsgContext, db *DatabaseContext) {
|
func (m Middleware) Execute(ctx *MsgContext, db *DatabaseContext) {
|
||||||
exec := *m.Executor
|
|
||||||
if m.Async {
|
if m.Async {
|
||||||
go exec(ctx, db)
|
go m.Executor(ctx, db)
|
||||||
} else {
|
} else {
|
||||||
exec(ctx, db)
|
m.Execute(ctx, db)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
54
utils.go
54
utils.go
@@ -73,57 +73,3 @@ func EscapeMarkdownV2(s string) string {
|
|||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUnclosedTag(markdown string) string {
|
|
||||||
// order is important!
|
|
||||||
var tags = []string{
|
|
||||||
"```",
|
|
||||||
"`",
|
|
||||||
"*",
|
|
||||||
"_",
|
|
||||||
}
|
|
||||||
var currentTag = ""
|
|
||||||
|
|
||||||
markdownRunes := []rune(markdown)
|
|
||||||
|
|
||||||
var i = 0
|
|
||||||
outer:
|
|
||||||
for i < len(markdownRunes) {
|
|
||||||
// skip escaped characters (only outside tags)
|
|
||||||
if markdownRunes[i] == '\\' && currentTag == "" {
|
|
||||||
i += 2
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if currentTag != "" {
|
|
||||||
if strings.HasPrefix(string(markdownRunes[i:]), currentTag) {
|
|
||||||
// turn a tag off
|
|
||||||
i += len(currentTag)
|
|
||||||
currentTag = ""
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for _, tag := range tags {
|
|
||||||
if strings.HasPrefix(string(markdownRunes[i:]), tag) {
|
|
||||||
// turn a tag on
|
|
||||||
currentTag = tag
|
|
||||||
i += len(currentTag)
|
|
||||||
continue outer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentTag
|
|
||||||
}
|
|
||||||
func IsValid(markdown string) bool {
|
|
||||||
return GetUnclosedTag(markdown) == ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func FixMarkdown(markdown string) string {
|
|
||||||
tag := GetUnclosedTag(markdown)
|
|
||||||
if tag == "" {
|
|
||||||
return markdown
|
|
||||||
}
|
|
||||||
return markdown + tag
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package laniakea
|
package laniakea
|
||||||
|
|
||||||
const (
|
const (
|
||||||
VersionString = "0.3.2"
|
VersionString = "0.3.6"
|
||||||
VersionMajor = 0
|
VersionMajor = 0
|
||||||
VersionMinor = 3
|
VersionMinor = 3
|
||||||
VersionPatch = 2
|
VersionPatch = 6
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user