Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5f17b88787 | |||
|
7a6f135487
|
|||
|
2e9e82d43b
|
|||
|
55d4065259
|
|||
| b89f27574f | |||
| 689eb8a5e2 | |||
| 6d6f5738cd | |||
| fef718438a | |||
| 7f248fff62 |
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Laniakea
|
||||
|
||||
A lightweight, easy to use and performance Telegram API wrapper for bot development.
|
||||
15
bot.go
15
bot.go
@@ -8,6 +8,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.nix13.pw/scuroneko/extypes"
|
||||
"git.nix13.pw/scuroneko/slog"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"github.com/vinovest/sqlx"
|
||||
@@ -39,7 +40,7 @@ type Bot struct {
|
||||
|
||||
updateOffset int
|
||||
updateTypes []string
|
||||
updateQueue *Queue[*Update]
|
||||
updateQueue *extypes.Queue[*Update]
|
||||
}
|
||||
|
||||
type BotSettings struct {
|
||||
@@ -73,7 +74,7 @@ func LoadPrefixesFromEnv() []string {
|
||||
return strings.Split(prefixesS, ";")
|
||||
}
|
||||
func NewBot(settings *BotSettings) *Bot {
|
||||
updateQueue := CreateQueue[*Update](256)
|
||||
updateQueue := extypes.CreateQueue[*Update](256)
|
||||
bot := &Bot{
|
||||
updateOffset: 0, plugins: make([]Plugin, 0), debug: settings.Debug, errorTemplate: "%s",
|
||||
prefixes: settings.Prefixes, updateTypes: make([]string, 0), runners: make([]Runner, 0),
|
||||
@@ -117,6 +118,12 @@ func NewBot(settings *BotSettings) *Bot {
|
||||
}
|
||||
}
|
||||
|
||||
u, err := bot.GetMe()
|
||||
if err != nil {
|
||||
bot.logger.Fatal(err)
|
||||
}
|
||||
bot.logger.Infof("Authorized as %s\n", u.FirstName)
|
||||
|
||||
return bot
|
||||
}
|
||||
|
||||
@@ -244,9 +251,7 @@ func (b *Bot) Run() {
|
||||
continue
|
||||
}
|
||||
|
||||
ctx := &MsgContext{
|
||||
Bot: b, Update: u,
|
||||
}
|
||||
ctx := &MsgContext{Bot: b, Update: u}
|
||||
for _, middleware := range b.middlewares {
|
||||
middleware.Execute(ctx, b.dbContext)
|
||||
}
|
||||
|
||||
3
go.mod
3
go.mod
@@ -1,8 +1,9 @@
|
||||
module git.nix13.pw/scuroneko/laniakea
|
||||
|
||||
go 1.25
|
||||
go 1.25.6
|
||||
|
||||
require (
|
||||
git.nix13.pw/scuroneko/extypes v1.0.2
|
||||
git.nix13.pw/scuroneko/slog v1.0.2
|
||||
github.com/redis/go-redis/v9 v9.17.3
|
||||
github.com/vinovest/sqlx v1.7.1
|
||||
|
||||
2
go.sum
2
go.sum
@@ -1,5 +1,7 @@
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
git.nix13.pw/scuroneko/extypes v1.0.2 h1:Qz1InLccaB9crXY33oGrSetPHePKfQAUqW/p/iYXmJk=
|
||||
git.nix13.pw/scuroneko/extypes v1.0.2/go.mod h1:uZVs8Yo3RrYAG9dMad6qR6lsYY67t+459D9c65QAYAw=
|
||||
git.nix13.pw/scuroneko/slog v1.0.2 h1:vZyUROygxC2d5FJHUQM/30xFEHY1JT/aweDZXA4rm2g=
|
||||
git.nix13.pw/scuroneko/slog v1.0.2/go.mod h1:3Qm2wzkR5KjwOponMfG7TcGSDjmYaFqRAmLvSPTuWJI=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
|
||||
@@ -39,6 +39,9 @@ func (b *Bot) handleMessage(update *Update, ctx *MsgContext) {
|
||||
ctx.Text = strings.TrimSpace(text[len(cmd):])
|
||||
ctx.Args = strings.Split(ctx.Text, " ")
|
||||
|
||||
if !plugin.executeMiddlewares(ctx, b.dbContext) {
|
||||
return
|
||||
}
|
||||
go plugin.Execute(cmd, ctx, b.dbContext)
|
||||
return
|
||||
}
|
||||
@@ -65,6 +68,10 @@ func (b *Bot) handleCallback(update *Update, ctx *MsgContext) {
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if !plugin.executeMiddlewares(ctx, b.dbContext) {
|
||||
return
|
||||
}
|
||||
go plugin.ExecutePayload(data.Command, ctx, b.dbContext)
|
||||
return
|
||||
}
|
||||
|
||||
46
methods.go
46
methods.go
@@ -195,3 +195,49 @@ func (b *Bot) SendChatAction(params SendChatActionP) (bool, error) {
|
||||
}
|
||||
return *res, err
|
||||
}
|
||||
|
||||
type SetMessageReactionP struct {
|
||||
ChatId int `json:"chat_id"`
|
||||
MessageId int `json:"message_id"`
|
||||
IsBig bool `json:"is_big,omitempty"`
|
||||
}
|
||||
type SetMessageReactionEmojiP struct {
|
||||
SetMessageReactionP
|
||||
Reaction []ReactionTypeEmoji `json:"reaction"`
|
||||
}
|
||||
|
||||
func (b *Bot) SetMessageReactionEmoji(params SetMessageReactionEmojiP) (bool, error) {
|
||||
req := NewRequest[bool]("setMessageReaction", params)
|
||||
res, err := req.Do(b)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return *res, err
|
||||
}
|
||||
|
||||
type SetMessageReactionCustomEmojiP struct {
|
||||
SetMessageReactionP
|
||||
Reaction []ReactionTypeCustomEmoji `json:"reaction"`
|
||||
}
|
||||
|
||||
func (b *Bot) SetMessageReactionCustom(params SetMessageReactionCustomEmojiP) (bool, error) {
|
||||
req := NewRequest[bool]("setMessageReaction", params)
|
||||
res, err := req.Do(b)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return *res, err
|
||||
}
|
||||
|
||||
type SetMessageReactionPaidP struct {
|
||||
SetMessageReactionP
|
||||
}
|
||||
|
||||
func (b *Bot) SetMessageReactionPaid(params SetMessageReactionPaidP) (bool, error) {
|
||||
req := NewRequest[bool]("setMessageReaction", params)
|
||||
res, err := req.Do(b)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return *res, err
|
||||
}
|
||||
|
||||
60
plugins.go
60
plugins.go
@@ -1,6 +1,10 @@
|
||||
package laniakea
|
||||
|
||||
import "log"
|
||||
import (
|
||||
"log"
|
||||
|
||||
"git.nix13.pw/scuroneko/extypes"
|
||||
)
|
||||
|
||||
type CommandExecutor func(ctx *MsgContext, dbContext *DatabaseContext)
|
||||
|
||||
@@ -9,6 +13,7 @@ type PluginBuilder struct {
|
||||
commands map[string]*CommandExecutor
|
||||
payloads map[string]*CommandExecutor
|
||||
updateListener *CommandExecutor
|
||||
middlewares extypes.Slice[*PluginMiddleware]
|
||||
}
|
||||
|
||||
type Plugin struct {
|
||||
@@ -16,6 +21,7 @@ type Plugin struct {
|
||||
Commands map[string]*CommandExecutor
|
||||
Payloads map[string]*CommandExecutor
|
||||
UpdateListener *CommandExecutor
|
||||
Middlewares extypes.Slice[*PluginMiddleware]
|
||||
}
|
||||
|
||||
func NewPlugin(name string) *PluginBuilder {
|
||||
@@ -45,6 +51,11 @@ func (p *PluginBuilder) UpdateListener(listener CommandExecutor) *PluginBuilder
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *PluginBuilder) Middleware(middleware *PluginMiddleware) *PluginBuilder {
|
||||
p.middlewares = p.middlewares.Push(middleware)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *PluginBuilder) Build() Plugin {
|
||||
if len(p.commands) == 0 && len(p.payloads) == 0 {
|
||||
log.Println("no command or payloads")
|
||||
@@ -54,6 +65,7 @@ func (p *PluginBuilder) Build() Plugin {
|
||||
Commands: p.commands,
|
||||
Payloads: p.payloads,
|
||||
UpdateListener: p.updateListener,
|
||||
Middlewares: p.middlewares,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +77,15 @@ func (p *Plugin) ExecutePayload(payload string, ctx *MsgContext, dbContext *Data
|
||||
(*p.Payloads[payload])(ctx, dbContext)
|
||||
}
|
||||
|
||||
func (p *Plugin) executeMiddlewares(ctx *MsgContext, db *DatabaseContext) bool {
|
||||
for _, m := range p.Middlewares {
|
||||
if !m.Execute(ctx, db) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type Middleware struct {
|
||||
Name string
|
||||
Executor CommandExecutor
|
||||
@@ -78,8 +99,8 @@ type MiddlewareBuilder struct {
|
||||
async bool
|
||||
}
|
||||
|
||||
func NewMiddleware(name string) *MiddlewareBuilder {
|
||||
return &MiddlewareBuilder{name: name, async: false}
|
||||
func NewMiddleware(name string, executor CommandExecutor) *MiddlewareBuilder {
|
||||
return &MiddlewareBuilder{name: name, executor: executor, order: 0, async: false}
|
||||
}
|
||||
func (m *MiddlewareBuilder) SetName(name string) *MiddlewareBuilder {
|
||||
m.name = name
|
||||
@@ -112,3 +133,36 @@ func (m Middleware) Execute(ctx *MsgContext, db *DatabaseContext) {
|
||||
m.Execute(ctx, db)
|
||||
}
|
||||
}
|
||||
|
||||
type PluginMiddlewareExecutor func(ctx *MsgContext, db *DatabaseContext) bool
|
||||
|
||||
// PluginMiddleware
|
||||
// When async, returned value ignored
|
||||
type PluginMiddleware struct {
|
||||
executor PluginMiddlewareExecutor
|
||||
order int
|
||||
async bool
|
||||
}
|
||||
|
||||
func NewPluginMiddleware(executor PluginMiddlewareExecutor) *PluginMiddleware {
|
||||
return &PluginMiddleware{
|
||||
executor: executor,
|
||||
order: 0,
|
||||
async: false,
|
||||
}
|
||||
}
|
||||
func (m *PluginMiddleware) SetOrder(order int) *PluginMiddleware {
|
||||
m.order = order
|
||||
return m
|
||||
}
|
||||
func (m *PluginMiddleware) SetAsync(async bool) *PluginMiddleware {
|
||||
m.async = async
|
||||
return m
|
||||
}
|
||||
func (m *PluginMiddleware) Execute(ctx *MsgContext, db *DatabaseContext) bool {
|
||||
if m.async {
|
||||
go m.executor(ctx, db)
|
||||
return true
|
||||
}
|
||||
return m.executor(ctx, db)
|
||||
}
|
||||
|
||||
71
queue.go
71
queue.go
@@ -1,71 +0,0 @@
|
||||
package laniakea
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var QueueFullErr = errors.New("queue full")
|
||||
|
||||
type Queue[T any] struct {
|
||||
size uint64
|
||||
mu sync.RWMutex
|
||||
queue []T
|
||||
}
|
||||
|
||||
func CreateQueue[T any](size uint64) *Queue[T] {
|
||||
return &Queue[T]{
|
||||
queue: make([]T, 0),
|
||||
size: size,
|
||||
}
|
||||
}
|
||||
|
||||
func (q *Queue[T]) Enqueue(el T) error {
|
||||
if q.IsFull() {
|
||||
return QueueFullErr
|
||||
}
|
||||
q.queue = append(q.queue, el)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *Queue[T]) Peak() T {
|
||||
q.mu.RLock()
|
||||
defer q.mu.RUnlock()
|
||||
return q.queue[0]
|
||||
}
|
||||
|
||||
func (q *Queue[T]) IsEmpty() bool {
|
||||
return q.Length() == 0
|
||||
}
|
||||
|
||||
func (q *Queue[T]) IsFull() bool {
|
||||
return q.Length() == q.size
|
||||
}
|
||||
|
||||
func (q *Queue[T]) Length() uint64 {
|
||||
q.mu.RLock()
|
||||
defer q.mu.RUnlock()
|
||||
return uint64(len(q.queue))
|
||||
}
|
||||
|
||||
func (q *Queue[T]) Dequeue() T {
|
||||
q.mu.RLock()
|
||||
el := q.queue[0]
|
||||
q.mu.RUnlock()
|
||||
|
||||
if q.Length() == 1 {
|
||||
q.mu.Lock()
|
||||
q.queue = make([]T, 0)
|
||||
q.mu.Unlock()
|
||||
return el
|
||||
}
|
||||
|
||||
q.mu.Lock()
|
||||
q.queue = q.queue[1:]
|
||||
q.mu.Unlock()
|
||||
return el
|
||||
}
|
||||
|
||||
func (q *Queue[T]) Raw() []T {
|
||||
return q.queue
|
||||
}
|
||||
70
slice.go
70
slice.go
@@ -1,70 +0,0 @@
|
||||
package laniakea
|
||||
|
||||
type Slice[T any] []T
|
||||
|
||||
func NewSliceFrom[T any](slice []T) Slice[T] {
|
||||
s := make(Slice[T], len(slice))
|
||||
copy(s[:], slice)
|
||||
return s
|
||||
}
|
||||
func (s Slice[T]) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
func (s Slice[T]) Cap() int {
|
||||
return cap(s)
|
||||
}
|
||||
func (s Slice[T]) Get(index int) T {
|
||||
return s[index]
|
||||
}
|
||||
func (s Slice[T]) Last() T {
|
||||
return s.Get(s.Len() - 1)
|
||||
}
|
||||
func (s Slice[T]) Swap(i, j int) Slice[T] {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
return s
|
||||
}
|
||||
func (s Slice[T]) Filter(f func(e T) bool) Slice[T] {
|
||||
out := make(Slice[T], 0)
|
||||
for _, v := range s {
|
||||
if f(v) {
|
||||
out = append(out, v)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
func (s Slice[T]) Map(f func(e T) T) Slice[T] {
|
||||
out := make(Slice[T], s.Len())
|
||||
for i, v := range s {
|
||||
out[i] = f(v)
|
||||
}
|
||||
return out
|
||||
}
|
||||
func (s Slice[T]) Pop(index int) Slice[T] {
|
||||
if index == 0 {
|
||||
return s[1:]
|
||||
}
|
||||
out := make(Slice[T], s.Len()-index)
|
||||
for i, e := range s {
|
||||
if i == index {
|
||||
continue
|
||||
}
|
||||
out[i] = e
|
||||
}
|
||||
return out
|
||||
}
|
||||
func (s Slice[T]) Push(e T) Slice[T] {
|
||||
return append(s, e)
|
||||
}
|
||||
|
||||
func (s Slice[T]) ToArray() []T {
|
||||
out := make([]T, len(s))
|
||||
copy(out, s)
|
||||
return out
|
||||
}
|
||||
func (s Slice[T]) ToAnyArray() []any {
|
||||
out := make([]any, len(s))
|
||||
for i, v := range s {
|
||||
out[i] = v
|
||||
}
|
||||
return out
|
||||
}
|
||||
4
types.go
4
types.go
@@ -1,5 +1,7 @@
|
||||
package laniakea
|
||||
|
||||
import "git.nix13.pw/scuroneko/extypes"
|
||||
|
||||
type Update struct {
|
||||
UpdateID int `json:"update_id"`
|
||||
Message *Message `json:"message"`
|
||||
@@ -54,7 +56,7 @@ type Message struct {
|
||||
Chat *Chat `json:"chat,omitempty"`
|
||||
Text string `json:"text"`
|
||||
|
||||
Photo Slice[*PhotoSize] `json:"photo,omitempty"`
|
||||
Photo extypes.Slice[*PhotoSize] `json:"photo,omitempty"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ReplyToMessage *Message `json:"reply_to_message"`
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package laniakea
|
||||
|
||||
const (
|
||||
VersionString = "0.3.7"
|
||||
VersionString = "0.3.9"
|
||||
VersionMajor = 0
|
||||
VersionMinor = 3
|
||||
VersionPatch = 7
|
||||
VersionPatch = 9
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user