Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
c1bdc2fdf6
|
|||
|
83dca1ab39
|
|||
|
2cc2f96f02
|
|||
|
9d18bef97e
|
|||
|
60f09e940a
|
|||
|
7a6f135487
|
|||
|
2e9e82d43b
|
|||
|
55d4065259
|
|||
| b89f27574f |
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.
|
||||||
49
api.go
49
api.go
@@ -7,8 +7,24 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"git.nix13.pw/scuroneko/slog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Api struct {
|
||||||
|
token string
|
||||||
|
logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAPI(token string) *Api {
|
||||||
|
l := slog.CreateLogger().Level(GetLoggerLevel()).Prefix("API")
|
||||||
|
l.AddWriter(l.CreateJsonStdoutWriter())
|
||||||
|
return &Api{token, l}
|
||||||
|
}
|
||||||
|
func (api *Api) CloseApi() error {
|
||||||
|
return api.logger.Close()
|
||||||
|
}
|
||||||
|
|
||||||
type ApiResponse[R any] struct {
|
type ApiResponse[R any] struct {
|
||||||
Ok bool `json:"ok"`
|
Ok bool `json:"ok"`
|
||||||
Description string `json:"description,omitempty"`
|
Description string `json:"description,omitempty"`
|
||||||
@@ -24,32 +40,32 @@ type TelegramRequest[R, P any] struct {
|
|||||||
func NewRequest[R, P any](method string, params P) TelegramRequest[R, P] {
|
func NewRequest[R, P any](method string, params P) TelegramRequest[R, P] {
|
||||||
return TelegramRequest[R, P]{method: method, params: params}
|
return TelegramRequest[R, P]{method: method, params: params}
|
||||||
}
|
}
|
||||||
func (r TelegramRequest[R, P]) Do(bot *Bot) (*R, error) {
|
func (r TelegramRequest[R, P]) Do(api *Api) (*R, error) {
|
||||||
var buf bytes.Buffer
|
buf := bytes.NewBuffer(nil)
|
||||||
err := json.NewEncoder(&buf).Encode(r.params)
|
err := json.NewEncoder(buf).Encode(r.params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if bot.requestLogger != nil {
|
u := fmt.Sprintf("https://api.telegram.org/bot%s/%s", api.token, r.method)
|
||||||
bot.requestLogger.Debugln(strings.ReplaceAll(fmt.Sprintf(
|
if api.logger != nil {
|
||||||
"POST https://api.telegram.org/bot%s/%s %s",
|
api.logger.Debugln(strings.ReplaceAll(fmt.Sprintf(
|
||||||
"<TOKEN>", r.method, buf.String(),
|
"POST %s %s", u, buf.String(),
|
||||||
), "\n", ""))
|
), api.token, "<TOKEN>"))
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := http.Post(fmt.Sprintf("https://api.telegram.org/bot%s/%s", bot.token, r.method), "application/json", &buf)
|
res, err := http.Post(u, "application/json", buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer req.Body.Close()
|
defer res.Body.Close()
|
||||||
data, err := io.ReadAll(req.Body)
|
data, err := io.ReadAll(res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if bot.requestLogger != nil {
|
if api.logger != nil {
|
||||||
bot.requestLogger.Debugln(fmt.Sprintf("RES %s %s", r.method, string(data)))
|
api.logger.Debugln(fmt.Sprintf("RES %s %s", r.method, string(data)))
|
||||||
}
|
}
|
||||||
|
|
||||||
response := new(ApiResponse[R])
|
response := new(ApiResponse[R])
|
||||||
@@ -65,13 +81,8 @@ func (r TelegramRequest[R, P]) Do(bot *Bot) (*R, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bot) GetFileByLink(link string) ([]byte, error) {
|
func (b *Bot) GetFileByLink(link string) ([]byte, error) {
|
||||||
c := http.DefaultClient
|
|
||||||
u := fmt.Sprintf("https://api.telegram.org/file/bot%s/%s", b.token, link)
|
u := fmt.Sprintf("https://api.telegram.org/file/bot%s/%s", b.token, link)
|
||||||
req, err := http.NewRequest("GET", u, nil)
|
res, err := http.Get(u)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res, err := c.Do(req)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
27
bot.go
27
bot.go
@@ -8,6 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.nix13.pw/scuroneko/extypes"
|
||||||
"git.nix13.pw/scuroneko/slog"
|
"git.nix13.pw/scuroneko/slog"
|
||||||
"github.com/redis/go-redis/v9"
|
"github.com/redis/go-redis/v9"
|
||||||
"github.com/vinovest/sqlx"
|
"github.com/vinovest/sqlx"
|
||||||
@@ -36,10 +37,13 @@ type Bot struct {
|
|||||||
runners []Runner
|
runners []Runner
|
||||||
|
|
||||||
dbContext *DatabaseContext
|
dbContext *DatabaseContext
|
||||||
|
api *Api
|
||||||
|
|
||||||
|
dbWriterRequested extypes.Slice[*slog.Logger]
|
||||||
|
|
||||||
updateOffset int
|
updateOffset int
|
||||||
updateTypes []string
|
updateTypes []string
|
||||||
updateQueue *Queue[*Update]
|
updateQueue *extypes.Queue[*Update]
|
||||||
}
|
}
|
||||||
|
|
||||||
type BotSettings struct {
|
type BotSettings struct {
|
||||||
@@ -73,13 +77,15 @@ func LoadPrefixesFromEnv() []string {
|
|||||||
return strings.Split(prefixesS, ";")
|
return strings.Split(prefixesS, ";")
|
||||||
}
|
}
|
||||||
func NewBot(settings *BotSettings) *Bot {
|
func NewBot(settings *BotSettings) *Bot {
|
||||||
updateQueue := CreateQueue[*Update](256)
|
updateQueue := extypes.CreateQueue[*Update](256)
|
||||||
|
api := NewAPI(settings.Token)
|
||||||
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, api: api, dbWriterRequested: make([]*slog.Logger, 0),
|
||||||
token: settings.Token,
|
token: settings.Token,
|
||||||
}
|
}
|
||||||
|
bot.dbWriterRequested = bot.dbWriterRequested.Push(api.logger)
|
||||||
|
|
||||||
if len(settings.ErrorTemplate) > 0 {
|
if len(settings.ErrorTemplate) > 0 {
|
||||||
bot.errorTemplate = settings.ErrorTemplate
|
bot.errorTemplate = settings.ErrorTemplate
|
||||||
@@ -117,6 +123,12 @@ func NewBot(settings *BotSettings) *Bot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u, err := api.GetMe()
|
||||||
|
if err != nil {
|
||||||
|
bot.logger.Fatal(err)
|
||||||
|
}
|
||||||
|
bot.logger.Infof("Authorized as %s\n", u.FirstName)
|
||||||
|
|
||||||
return bot
|
return bot
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +155,9 @@ func (b *Bot) AddDatabaseLogger(writer func(db *DatabaseContext) slog.LoggerWrit
|
|||||||
if b.requestLogger != nil {
|
if b.requestLogger != nil {
|
||||||
b.requestLogger.AddWriter(w)
|
b.requestLogger.AddWriter(w)
|
||||||
}
|
}
|
||||||
|
for _, l := range b.dbWriterRequested {
|
||||||
|
l.AddWriter(w)
|
||||||
|
}
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,9 +259,7 @@ func (b *Bot) Run() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := &MsgContext{
|
ctx := &MsgContext{Bot: b, Update: u, Api: b.api}
|
||||||
Bot: b, Update: u,
|
|
||||||
}
|
|
||||||
for _, middleware := range b.middlewares {
|
for _, middleware := range b.middlewares {
|
||||||
middleware.Execute(ctx, b.dbContext)
|
middleware.Execute(ctx, b.dbContext)
|
||||||
}
|
}
|
||||||
|
|||||||
3
go.mod
3
go.mod
@@ -3,6 +3,7 @@ module git.nix13.pw/scuroneko/laniakea
|
|||||||
go 1.25
|
go 1.25
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
git.nix13.pw/scuroneko/extypes v1.1.0
|
||||||
git.nix13.pw/scuroneko/slog v1.0.2
|
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
|
||||||
@@ -13,7 +14,7 @@ require (
|
|||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/fatih/color v1.18.0 // indirect
|
github.com/fatih/color v1.18.0 // indirect
|
||||||
github.com/klauspost/compress v1.18.3 // indirect
|
github.com/klauspost/compress v1.18.4 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/muir/sqltoken v0.2.1 // indirect
|
github.com/muir/sqltoken v0.2.1 // indirect
|
||||||
|
|||||||
6
go.sum
6
go.sum
@@ -1,5 +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/extypes v1.1.0 h1:kdAraybAqQgVhArVkVfrIi7KVEX8HgTr8mzbIZAAAqg=
|
||||||
|
git.nix13.pw/scuroneko/extypes v1.1.0/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 h1:vZyUROygxC2d5FJHUQM/30xFEHY1JT/aweDZXA4rm2g=
|
||||||
git.nix13.pw/scuroneko/slog v1.0.2/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=
|
||||||
@@ -18,8 +20,8 @@ github.com/go-sql-driver/mysql v1.9.0 h1:Y0zIbQXhQKmQgTp44Y1dp3wTXcn804QoTptLZT1
|
|||||||
github.com/go-sql-driver/mysql v1.9.0/go.mod h1:pDetrLJeA3oMujJuvXc8RJoasr589B6A9fwzD3QMrqw=
|
github.com/go-sql-driver/mysql v1.9.0/go.mod h1:pDetrLJeA3oMujJuvXc8RJoasr589B6A9fwzD3QMrqw=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw=
|
github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=
|
||||||
github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||||
|
|||||||
19
handler.go
19
handler.go
@@ -35,10 +35,25 @@ func (b *Bot) handleMessage(update *Update, ctx *MsgContext) {
|
|||||||
if !strings.HasPrefix(text, cmd) {
|
if !strings.HasPrefix(text, cmd) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
requestParts := strings.Split(text, " ")
|
||||||
|
cmdParts := strings.Split(cmd, " ")
|
||||||
|
isValid := true
|
||||||
|
for i, part := range cmdParts {
|
||||||
|
if part != requestParts[i] {
|
||||||
|
isValid = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !isValid {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
ctx.Text = strings.TrimSpace(text[len(cmd):])
|
ctx.Text = strings.TrimSpace(text[len(cmd):])
|
||||||
ctx.Args = strings.Split(ctx.Text, " ")
|
ctx.Args = strings.Split(ctx.Text, " ")
|
||||||
|
|
||||||
|
if !plugin.executeMiddlewares(ctx, b.dbContext) {
|
||||||
|
return
|
||||||
|
}
|
||||||
go plugin.Execute(cmd, ctx, b.dbContext)
|
go plugin.Execute(cmd, ctx, b.dbContext)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -65,6 +80,10 @@ func (b *Bot) handleCallback(update *Update, ctx *MsgContext) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !plugin.executeMiddlewares(ctx, b.dbContext) {
|
||||||
|
return
|
||||||
|
}
|
||||||
go plugin.ExecutePayload(data.Command, ctx, b.dbContext)
|
go plugin.ExecutePayload(data.Command, ctx, b.dbContext)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
83
keyboard.go
83
keyboard.go
@@ -3,51 +3,110 @@ package laniakea
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"git.nix13.pw/scuroneko/extypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ButtonStyleDanger KeyboardButtonStyle = "danger"
|
||||||
|
ButtonStyleSuccess KeyboardButtonStyle = "success"
|
||||||
|
ButtonStylePrimary KeyboardButtonStyle = "primary"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InlineKbButtonBuilder struct {
|
||||||
|
text string
|
||||||
|
iconCustomEmojiID string
|
||||||
|
style KeyboardButtonStyle
|
||||||
|
url string
|
||||||
|
callbackData string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInlineKbButton(text string) InlineKbButtonBuilder {
|
||||||
|
return InlineKbButtonBuilder{text: text}
|
||||||
|
}
|
||||||
|
func (b InlineKbButtonBuilder) SetIconCustomEmojiId(id string) InlineKbButtonBuilder {
|
||||||
|
b.iconCustomEmojiID = id
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
func (b InlineKbButtonBuilder) SetStyle(style KeyboardButtonStyle) InlineKbButtonBuilder {
|
||||||
|
b.style = style
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
func (b InlineKbButtonBuilder) SetUrl(url string) InlineKbButtonBuilder {
|
||||||
|
b.url = url
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
func (b InlineKbButtonBuilder) SetCallbackData(cmd string, args ...any) InlineKbButtonBuilder {
|
||||||
|
b.callbackData = NewCallbackData(cmd, args...).ToJson()
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b InlineKbButtonBuilder) build() InlineKeyboardButton {
|
||||||
|
return InlineKeyboardButton{
|
||||||
|
Text: b.text,
|
||||||
|
URL: b.url,
|
||||||
|
Style: b.style,
|
||||||
|
IconCustomEmojiID: b.iconCustomEmojiID,
|
||||||
|
CallbackData: b.callbackData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type InlineKeyboard struct {
|
type InlineKeyboard struct {
|
||||||
CurrentLine []InlineKeyboardButton
|
CurrentLine extypes.Slice[InlineKeyboardButton]
|
||||||
Lines [][]InlineKeyboardButton
|
Lines [][]InlineKeyboardButton
|
||||||
maxRow int
|
maxRow int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewInlineKeyboard(maxRow int) *InlineKeyboard {
|
func NewInlineKeyboard(maxRow int) *InlineKeyboard {
|
||||||
return &InlineKeyboard{
|
return &InlineKeyboard{
|
||||||
CurrentLine: make([]InlineKeyboardButton, 0),
|
CurrentLine: make(extypes.Slice[InlineKeyboardButton], 0),
|
||||||
Lines: make([][]InlineKeyboardButton, 0),
|
Lines: make([][]InlineKeyboardButton, 0),
|
||||||
maxRow: maxRow,
|
maxRow: maxRow,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in *InlineKeyboard) append(button InlineKeyboardButton) *InlineKeyboard {
|
func (in *InlineKeyboard) append(button InlineKeyboardButton) *InlineKeyboard {
|
||||||
if len(in.CurrentLine) == in.maxRow {
|
if in.CurrentLine.Len() == in.maxRow {
|
||||||
in.AddLine()
|
in.AddLine()
|
||||||
}
|
}
|
||||||
in.CurrentLine = append(in.CurrentLine, button)
|
in.CurrentLine = in.CurrentLine.Push(button)
|
||||||
return in
|
return in
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in *InlineKeyboard) AddUrlButton(text, url string) *InlineKeyboard {
|
func (in *InlineKeyboard) AddUrlButton(text, url string) *InlineKeyboard {
|
||||||
return in.append(InlineKeyboardButton{Text: text, URL: url})
|
return in.append(InlineKeyboardButton{Text: text, URL: url})
|
||||||
}
|
}
|
||||||
|
func (in *InlineKeyboard) AddUrlButtonStyle(text string, style KeyboardButtonStyle, url string) *InlineKeyboard {
|
||||||
|
return in.append(InlineKeyboardButton{Text: text, Style: style, URL: url})
|
||||||
|
}
|
||||||
func (in *InlineKeyboard) AddCallbackButton(text string, cmd string, args ...any) *InlineKeyboard {
|
func (in *InlineKeyboard) AddCallbackButton(text string, cmd string, args ...any) *InlineKeyboard {
|
||||||
return in.append(InlineKeyboardButton{Text: text, CallbackData: NewCallbackData(cmd, args...).ToJson()})
|
return in.append(InlineKeyboardButton{
|
||||||
|
Text: text, CallbackData: NewCallbackData(cmd, args...).ToJson(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func (in *InlineKeyboard) AddCallbackButtonStyle(text string, style KeyboardButtonStyle, cmd string, args ...any) *InlineKeyboard {
|
||||||
|
return in.append(InlineKeyboardButton{
|
||||||
|
Text: text, Style: style,
|
||||||
|
CallbackData: NewCallbackData(cmd, args...).ToJson(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func (in *InlineKeyboard) AddButton(b InlineKbButtonBuilder) *InlineKeyboard {
|
||||||
|
return in.append(b.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in *InlineKeyboard) AddLine() *InlineKeyboard {
|
func (in *InlineKeyboard) AddLine() *InlineKeyboard {
|
||||||
if len(in.CurrentLine) == 0 {
|
if in.CurrentLine.Len() == 0 {
|
||||||
return in
|
return in
|
||||||
}
|
}
|
||||||
in.Lines = append(in.Lines, in.CurrentLine)
|
in.Lines = append(in.Lines, in.CurrentLine)
|
||||||
in.CurrentLine = make([]InlineKeyboardButton, 0)
|
in.CurrentLine = make(extypes.Slice[InlineKeyboardButton], 0)
|
||||||
return in
|
return in
|
||||||
}
|
}
|
||||||
func (in *InlineKeyboard) Get() InlineKeyboardMarkup {
|
func (in *InlineKeyboard) Get() *InlineKeyboardMarkup {
|
||||||
if len(in.CurrentLine) > 0 {
|
if in.CurrentLine.Len() > 0 {
|
||||||
in.Lines = append(in.Lines, in.CurrentLine)
|
in.Lines = append(in.Lines, in.CurrentLine)
|
||||||
}
|
}
|
||||||
return InlineKeyboardMarkup{
|
return &InlineKeyboardMarkup{InlineKeyboard: in.Lines}
|
||||||
InlineKeyboard: in.Lines,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CallbackData struct {
|
type CallbackData struct {
|
||||||
|
|||||||
299
methods.go
299
methods.go
@@ -2,7 +2,6 @@ package laniakea
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type EmptyParams struct{}
|
type EmptyParams struct{}
|
||||||
@@ -23,54 +22,166 @@ func (b *Bot) Updates() ([]*Update, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
req := NewRequest[[]*Update]("getUpdates", params)
|
req := NewRequest[[]*Update]("getUpdates", params)
|
||||||
res, err := req.Do(b)
|
res, err := req.Do(b.api)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []*Update{}, err
|
return nil, err
|
||||||
}
|
}
|
||||||
updates := *res
|
|
||||||
|
|
||||||
for _, u := range updates {
|
for _, u := range *res {
|
||||||
b.updateOffset = u.UpdateID + 1
|
b.updateOffset = u.UpdateID + 1
|
||||||
err = b.updateQueue.Enqueue(u)
|
err = b.updateQueue.Enqueue(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.debug && b.requestLogger != nil {
|
if b.requestLogger != nil {
|
||||||
j, err := json.Marshal(u)
|
j, err := json.Marshal(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.logger.Error(err)
|
b.logger.Error(err)
|
||||||
}
|
}
|
||||||
b.requestLogger.Debugln(fmt.Sprintf("UPDATE %s", j))
|
b.requestLogger.Debugf("UPDATE %s\n", j)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return updates, err
|
return *res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bot) GetMe() (*User, error) {
|
func (api *Api) GetMe() (*User, error) {
|
||||||
req := NewRequest[User, EmptyParams]("getMe", NoParams)
|
req := NewRequest[User, EmptyParams]("getMe", NoParams)
|
||||||
return req.Do(b)
|
return req.Do(api)
|
||||||
|
}
|
||||||
|
func (api *Api) LogOut() (bool, error) {
|
||||||
|
req := NewRequest[bool, EmptyParams]("logOut", NoParams)
|
||||||
|
res, err := req.Do(api)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return *res, nil
|
||||||
|
}
|
||||||
|
func (api *Api) Close() (bool, error) {
|
||||||
|
req := NewRequest[bool, EmptyParams]("close", NoParams)
|
||||||
|
res, err := req.Do(api)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return *res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type SendMessageP struct {
|
type SendMessageP struct {
|
||||||
BusinessConnectionID string `json:"business_connection_id,omitempty"`
|
BusinessConnectionID string `json:"business_connection_id,omitempty"`
|
||||||
ChatID int `json:"chat_id"`
|
ChatID int `json:"chat_id"`
|
||||||
MessageThreadID int `json:"message_thread_id,omitempty"`
|
MessageThreadID int `json:"message_thread_id,omitempty"`
|
||||||
ParseMode ParseMode `json:"parse_mode,omitempty"`
|
DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"`
|
||||||
Text string `json:"text"`
|
|
||||||
Entities []*MessageEntity `json:"entities,omitempty"`
|
Text string `json:"text"`
|
||||||
LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"`
|
ParseMode ParseMode `json:"parse_mode,omitempty"`
|
||||||
DisableNotifications bool `json:"disable_notifications,omitempty"`
|
Entities []*MessageEntity `json:"entities,omitempty"`
|
||||||
ProtectContent bool `json:"protect_content,omitempty"`
|
LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"`
|
||||||
AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"`
|
DisableNotifications bool `json:"disable_notifications,omitempty"`
|
||||||
MessageEffectID string `json:"message_effect_id,omitempty"`
|
ProtectContent bool `json:"protect_content,omitempty"`
|
||||||
ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"`
|
AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"`
|
||||||
ReplyMarkup InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
MessageEffectID string `json:"message_effect_id,omitempty"`
|
||||||
|
|
||||||
|
SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"`
|
||||||
|
ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"`
|
||||||
|
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bot) SendMessage(params *SendMessageP) (*Message, error) {
|
func (api *Api) SendMessage(params *SendMessageP) (*Message, error) {
|
||||||
req := NewRequest[Message, SendMessageP]("sendMessage", *params)
|
req := NewRequest[Message, SendMessageP]("sendMessage", *params)
|
||||||
return req.Do(b)
|
return req.Do(api)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ForwardMessageP struct {
|
||||||
|
ChatID int `json:"chat_id"`
|
||||||
|
MessageThreadID int `json:"message_thread_id,omitempty"`
|
||||||
|
DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"`
|
||||||
|
|
||||||
|
MessageID int `json:"message_id,omitempty"`
|
||||||
|
FromChatID int `json:"from_chat_id,omitempty"`
|
||||||
|
VideoStartTimestamp int `json:"video_start_timestamp,omitempty"`
|
||||||
|
DisableNotification bool `json:"disable_notification,omitempty"`
|
||||||
|
ProtectContent bool `json:"protect_content,omitempty"`
|
||||||
|
|
||||||
|
MessageEffectID string `json:"message_effect_id,omitempty"`
|
||||||
|
SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *Api) ForwardMessage(params ForwardMessageP) (*Message, error) {
|
||||||
|
req := NewRequest[Message]("forwardMessage", params)
|
||||||
|
return req.Do(api)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ForwardMessagesP struct {
|
||||||
|
ChatID int `json:"chat_id"`
|
||||||
|
MessageThreadID int `json:"message_thread_id,omitempty"`
|
||||||
|
DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"`
|
||||||
|
|
||||||
|
FromChatID int `json:"from_chat_id,omitempty"`
|
||||||
|
MessageIDs []int `json:"message_ids,omitempty"`
|
||||||
|
DisableNotification bool `json:"disable_notification,omitempty"`
|
||||||
|
ProtectContent bool `json:"protect_content,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *Api) ForwardMessages(params ForwardMessagesP) ([]int, error) {
|
||||||
|
req := NewRequest[[]int]("forwardMessages", params)
|
||||||
|
res, err := req.Do(api)
|
||||||
|
if err != nil {
|
||||||
|
return []int{}, err
|
||||||
|
}
|
||||||
|
return *res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type CopyMessageP struct {
|
||||||
|
ChatID int `json:"chat_id"`
|
||||||
|
MessageThreadID int `json:"message_thread_id,omitempty"`
|
||||||
|
DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"`
|
||||||
|
|
||||||
|
FromChatID int `json:"from_chat_id"`
|
||||||
|
MessageID int `json:"message_id"`
|
||||||
|
VideoStartTimestamp int `json:"video_start_timestamp,omitempty"`
|
||||||
|
Caption string `json:"caption,omitempty"`
|
||||||
|
ParseMode ParseMode `json:"parse_mode,omitempty"`
|
||||||
|
|
||||||
|
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||||
|
ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"`
|
||||||
|
DisableNotification bool `json:"disable_notification,omitempty"`
|
||||||
|
ProtectContent bool `json:"protect_content,omitempty"`
|
||||||
|
AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"`
|
||||||
|
MessageEffectID string `json:"message_effect_id,omitempty"`
|
||||||
|
|
||||||
|
SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"`
|
||||||
|
ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"`
|
||||||
|
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *Api) CopyMessage(params CopyMessageP) (int, error) {
|
||||||
|
req := NewRequest[int]("copyMessage", params)
|
||||||
|
res, err := req.Do(api)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return *res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type CopyMessagesP struct {
|
||||||
|
ChatID int `json:"chat_id"`
|
||||||
|
MessageThreadID int `json:"message_thread_id,omitempty"`
|
||||||
|
DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"`
|
||||||
|
|
||||||
|
FromChatID int `json:"from_chat_id,omitempty"`
|
||||||
|
MessageIDs []int `json:"message_ids,omitempty"`
|
||||||
|
DisableNotification bool `json:"disable_notification,omitempty"`
|
||||||
|
ProtectContent bool `json:"protect_content,omitempty"`
|
||||||
|
RemoveCaption bool `json:"remove_caption,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *Api) CopyMessages(params CopyMessagesP) ([]int, error) {
|
||||||
|
req := NewRequest[[]int]("copyMessages", params)
|
||||||
|
res, err := req.Do(api)
|
||||||
|
if err != nil {
|
||||||
|
return []int{}, err
|
||||||
|
}
|
||||||
|
return *res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type SendPhotoBaseP struct {
|
type SendPhotoBaseP struct {
|
||||||
@@ -89,55 +200,61 @@ type SendPhotoBaseP struct {
|
|||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||||
}
|
}
|
||||||
type SendPhotoP struct {
|
type SendPhotoP struct {
|
||||||
BusinessConnectionID string `json:"business_connection_id,omitempty"`
|
BusinessConnectionID string `json:"business_connection_id,omitempty"`
|
||||||
ChatID int `json:"chat_id"`
|
ChatID int `json:"chat_id"`
|
||||||
MessageThreadID int `json:"message_thread_id,omitempty"`
|
MessageThreadID int `json:"message_thread_id,omitempty"`
|
||||||
ParseMode ParseMode `json:"parse_mode,omitempty"`
|
DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"`
|
||||||
Caption string `json:"caption,omitempty"`
|
|
||||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
Photo string `json:"photo"`
|
||||||
ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"`
|
Caption string `json:"caption,omitempty"`
|
||||||
HasSpoiler bool `json:"has_spoiler,omitempty"`
|
ParseMode ParseMode `json:"parse_mode,omitempty"`
|
||||||
DisableNotifications bool `json:"disable_notifications,omitempty"`
|
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||||
ProtectContent bool `json:"protect_content,omitempty"`
|
|
||||||
AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"`
|
ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"`
|
||||||
MessageEffectID string `json:"message_effect_id,omitempty"`
|
HasSpoiler bool `json:"has_spoiler,omitempty"`
|
||||||
ReplyMarkup InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
DisableNotifications bool `json:"disable_notifications,omitempty"`
|
||||||
Photo string `json:"photo"`
|
ProtectContent bool `json:"protect_content,omitempty"`
|
||||||
|
AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"`
|
||||||
|
MessageEffectID string `json:"message_effect_id,omitempty"`
|
||||||
|
|
||||||
|
SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"`
|
||||||
|
ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"`
|
||||||
|
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bot) SendPhoto(params *SendPhotoP) (*Message, error) {
|
func (api *Api) SendPhoto(params *SendPhotoP) (*Message, error) {
|
||||||
req := NewRequest[Message]("sendPhoto", params)
|
req := NewRequest[Message]("sendPhoto", params)
|
||||||
return req.Do(b)
|
return req.Do(api)
|
||||||
}
|
}
|
||||||
|
|
||||||
type EditMessageTextP struct {
|
type EditMessageTextP struct {
|
||||||
BusinessConnectionID string `json:"business_connection_id,omitempty"`
|
BusinessConnectionID string `json:"business_connection_id,omitempty"`
|
||||||
ChatID int `json:"chat_id,omitempty"`
|
ChatID int `json:"chat_id,omitempty"`
|
||||||
MessageID int `json:"message_id,omitempty"`
|
MessageID int `json:"message_id,omitempty"`
|
||||||
InlineMessageID string `json:"inline_message_id,omitempty"`
|
InlineMessageID string `json:"inline_message_id,omitempty"`
|
||||||
Text string `json:"text"`
|
Text string `json:"text"`
|
||||||
ParseMode ParseMode `json:"parse_mode,omitempty"`
|
ParseMode ParseMode `json:"parse_mode,omitempty"`
|
||||||
ReplyMarkup InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bot) EditMessageText(params *EditMessageTextP) (*Message, error) {
|
func (api *Api) EditMessageText(params *EditMessageTextP) (*Message, error) {
|
||||||
req := NewRequest[Message]("editMessageText", params)
|
req := NewRequest[Message]("editMessageText", params)
|
||||||
return req.Do(b)
|
return req.Do(api)
|
||||||
}
|
}
|
||||||
|
|
||||||
type EditMessageCaptionP struct {
|
type EditMessageCaptionP struct {
|
||||||
BusinessConnectionID string `json:"business_connection_id,omitempty"`
|
BusinessConnectionID string `json:"business_connection_id,omitempty"`
|
||||||
ChatID int `json:"chat_id,omitempty"`
|
ChatID int `json:"chat_id,omitempty"`
|
||||||
MessageID int `json:"message_id,omitempty"`
|
MessageID int `json:"message_id,omitempty"`
|
||||||
InlineMessageID string `json:"inline_message_id,omitempty"`
|
InlineMessageID string `json:"inline_message_id,omitempty"`
|
||||||
Caption string `json:"caption"`
|
Caption string `json:"caption"`
|
||||||
ParseMode ParseMode `json:"parse_mode,omitempty"`
|
ParseMode ParseMode `json:"parse_mode,omitempty"`
|
||||||
ReplyMarkup InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bot) EditMessageCaption(params *EditMessageCaptionP) (*Message, error) {
|
func (api *Api) EditMessageCaption(params *EditMessageCaptionP) (*Message, error) {
|
||||||
req := NewRequest[Message]("editMessageCaption", params)
|
req := NewRequest[Message]("editMessageCaption", params)
|
||||||
return req.Do(b)
|
return req.Do(api)
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeleteMessageP struct {
|
type DeleteMessageP struct {
|
||||||
@@ -145,9 +262,9 @@ type DeleteMessageP struct {
|
|||||||
MessageID int `json:"message_id"`
|
MessageID int `json:"message_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bot) DeleteMessage(params *DeleteMessageP) (bool, error) {
|
func (api *Api) DeleteMessage(params *DeleteMessageP) (bool, error) {
|
||||||
req := NewRequest[bool]("deleteMessage", params)
|
req := NewRequest[bool]("deleteMessage", params)
|
||||||
ok, err := req.Do(b)
|
ok, err := req.Do(api)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@@ -162,9 +279,9 @@ type AnswerCallbackQueryP struct {
|
|||||||
CacheTime int `json:"cache_time,omitempty"`
|
CacheTime int `json:"cache_time,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bot) AnswerCallbackQuery(params *AnswerCallbackQueryP) (bool, error) {
|
func (api *Api) AnswerCallbackQuery(params *AnswerCallbackQueryP) (bool, error) {
|
||||||
req := NewRequest[bool]("answerCallbackQuery", params)
|
req := NewRequest[bool]("answerCallbackQuery", params)
|
||||||
ok, err := req.Do(b)
|
ok, err := req.Do(api)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@@ -175,9 +292,9 @@ type GetFileP struct {
|
|||||||
FileId string `json:"file_id"`
|
FileId string `json:"file_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bot) GetFile(params *GetFileP) (*File, error) {
|
func (api *Api) GetFile(params *GetFileP) (*File, error) {
|
||||||
req := NewRequest[File]("getFile", params)
|
req := NewRequest[File]("getFile", params)
|
||||||
return req.Do(b)
|
return req.Do(api)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SendChatActionP struct {
|
type SendChatActionP struct {
|
||||||
@@ -187,9 +304,55 @@ type SendChatActionP struct {
|
|||||||
Action ChatActions `json:"action"`
|
Action ChatActions `json:"action"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bot) SendChatAction(params SendChatActionP) (bool, error) {
|
func (api *Api) SendChatAction(params SendChatActionP) (bool, error) {
|
||||||
req := NewRequest[bool]("sendChatAction", params)
|
req := NewRequest[bool]("sendChatAction", params)
|
||||||
res, err := req.Do(b)
|
res, err := req.Do(api)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
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 (api *Api) SetMessageReactionEmoji(params SetMessageReactionEmojiP) (bool, error) {
|
||||||
|
req := NewRequest[bool]("setMessageReaction", params)
|
||||||
|
res, err := req.Do(api)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return *res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type SetMessageReactionCustomEmojiP struct {
|
||||||
|
SetMessageReactionP
|
||||||
|
Reaction []ReactionTypeCustomEmoji `json:"reaction"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *Api) SetMessageReactionCustom(params SetMessageReactionCustomEmojiP) (bool, error) {
|
||||||
|
req := NewRequest[bool]("setMessageReaction", params)
|
||||||
|
res, err := req.Do(api)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return *res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type SetMessageReactionPaidP struct {
|
||||||
|
SetMessageReactionP
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *Api) SetMessageReactionPaid(params SetMessageReactionPaidP) (bool, error) {
|
||||||
|
req := NewRequest[bool]("setMessageReaction", params)
|
||||||
|
res, err := req.Do(api)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ package laniakea
|
|||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
type MsgContext struct {
|
type MsgContext struct {
|
||||||
Bot *Bot
|
Bot *Bot
|
||||||
|
Api *Api
|
||||||
|
|
||||||
Msg *Message
|
Msg *Message
|
||||||
Update *Update
|
Update *Update
|
||||||
From *User
|
From *User
|
||||||
@@ -33,9 +35,9 @@ func (ctx *MsgContext) edit(messageId int, text string, keyboard *InlineKeyboard
|
|||||||
if keyboard != nil {
|
if keyboard != nil {
|
||||||
params.ReplyMarkup = keyboard.Get()
|
params.ReplyMarkup = keyboard.Get()
|
||||||
}
|
}
|
||||||
msg, err := ctx.Bot.EditMessageText(params)
|
msg, err := ctx.Api.EditMessageText(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Bot.logger.Errorln(err)
|
ctx.Api.logger.Errorln(err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &AnswerMessage{
|
return &AnswerMessage{
|
||||||
@@ -47,7 +49,7 @@ func (m *AnswerMessage) Edit(text string) *AnswerMessage {
|
|||||||
}
|
}
|
||||||
func (ctx *MsgContext) EditCallback(text string, keyboard *InlineKeyboard) *AnswerMessage {
|
func (ctx *MsgContext) EditCallback(text string, keyboard *InlineKeyboard) *AnswerMessage {
|
||||||
if ctx.CallbackMsgId == 0 {
|
if ctx.CallbackMsgId == 0 {
|
||||||
ctx.Bot.logger.Errorln("Can't edit non-callback update message")
|
ctx.Api.logger.Errorln("Can't edit non-callback update message")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,9 +69,9 @@ func (ctx *MsgContext) editPhotoText(messageId int, text string, kb *InlineKeybo
|
|||||||
if kb != nil {
|
if kb != nil {
|
||||||
params.ReplyMarkup = kb.Get()
|
params.ReplyMarkup = kb.Get()
|
||||||
}
|
}
|
||||||
msg, err := ctx.Bot.EditMessageCaption(params)
|
msg, err := ctx.Api.EditMessageCaption(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Bot.logger.Errorln(err)
|
ctx.Api.logger.Errorln(err)
|
||||||
}
|
}
|
||||||
return &AnswerMessage{
|
return &AnswerMessage{
|
||||||
MessageID: msg.MessageID, ctx: ctx, Text: text, IsMedia: true,
|
MessageID: msg.MessageID, ctx: ctx, Text: text, IsMedia: true,
|
||||||
@@ -77,7 +79,7 @@ func (ctx *MsgContext) editPhotoText(messageId int, text string, kb *InlineKeybo
|
|||||||
}
|
}
|
||||||
func (m *AnswerMessage) EditCaption(text string) *AnswerMessage {
|
func (m *AnswerMessage) EditCaption(text string) *AnswerMessage {
|
||||||
if m.MessageID == 0 {
|
if m.MessageID == 0 {
|
||||||
m.ctx.Bot.logger.Errorln("Can't edit caption message, message id is zero")
|
m.ctx.Api.logger.Errorln("Can't edit caption message, message id is zero")
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
return m.ctx.editPhotoText(m.MessageID, text, nil)
|
return m.ctx.editPhotoText(m.MessageID, text, nil)
|
||||||
@@ -96,9 +98,9 @@ func (ctx *MsgContext) answer(text string, keyboard *InlineKeyboard) *AnswerMess
|
|||||||
params.ReplyMarkup = keyboard.Get()
|
params.ReplyMarkup = keyboard.Get()
|
||||||
}
|
}
|
||||||
|
|
||||||
msg, err := ctx.Bot.SendMessage(params)
|
msg, err := ctx.Api.SendMessage(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Bot.logger.Errorln(err)
|
ctx.Api.logger.Errorln(err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &AnswerMessage{
|
return &AnswerMessage{
|
||||||
@@ -125,9 +127,9 @@ func (ctx *MsgContext) answerPhoto(photoId, text string, kb *InlineKeyboard) *An
|
|||||||
if kb != nil {
|
if kb != nil {
|
||||||
params.ReplyMarkup = kb.Get()
|
params.ReplyMarkup = kb.Get()
|
||||||
}
|
}
|
||||||
msg, err := ctx.Bot.SendPhoto(params)
|
msg, err := ctx.Api.SendPhoto(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Bot.logger.Errorln(err)
|
ctx.Api.logger.Errorln(err)
|
||||||
return &AnswerMessage{
|
return &AnswerMessage{
|
||||||
ctx: ctx, Text: text, IsMedia: true,
|
ctx: ctx, Text: text, IsMedia: true,
|
||||||
}
|
}
|
||||||
@@ -144,12 +146,12 @@ func (ctx *MsgContext) AnswerPhotoKeyboard(photoId, text string, kb *InlineKeybo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *MsgContext) delete(messageId int) {
|
func (ctx *MsgContext) delete(messageId int) {
|
||||||
_, err := ctx.Bot.DeleteMessage(&DeleteMessageP{
|
_, err := ctx.Api.DeleteMessage(&DeleteMessageP{
|
||||||
ChatID: ctx.Msg.Chat.ID,
|
ChatID: ctx.Msg.Chat.ID,
|
||||||
MessageID: messageId,
|
MessageID: messageId,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Bot.logger.Errorln(err)
|
ctx.Api.logger.Errorln(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (m *AnswerMessage) Delete() {
|
func (m *AnswerMessage) Delete() {
|
||||||
@@ -163,12 +165,12 @@ func (ctx *MsgContext) answerCallbackQuery(url, text string, showAlert bool) {
|
|||||||
if len(ctx.CallbackQueryId) == 0 {
|
if len(ctx.CallbackQueryId) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err := ctx.Bot.AnswerCallbackQuery(&AnswerCallbackQueryP{
|
_, err := ctx.Api.AnswerCallbackQuery(&AnswerCallbackQueryP{
|
||||||
CallbackQueryID: ctx.CallbackQueryId,
|
CallbackQueryID: ctx.CallbackQueryId,
|
||||||
Text: text, ShowAlert: showAlert, URL: url,
|
Text: text, ShowAlert: showAlert, URL: url,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Bot.logger.Errorln(err)
|
ctx.Api.logger.Errorln(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (ctx *MsgContext) AnswerCbQuery() {
|
func (ctx *MsgContext) AnswerCbQuery() {
|
||||||
@@ -185,11 +187,11 @@ func (ctx *MsgContext) AnswerCbQueryUrl(u string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *MsgContext) SendAction(action ChatActions) {
|
func (ctx *MsgContext) SendAction(action ChatActions) {
|
||||||
_, err := ctx.Bot.SendChatAction(SendChatActionP{
|
_, err := ctx.Api.SendChatAction(SendChatActionP{
|
||||||
ChatID: ctx.Msg.Chat.ID, Action: action,
|
ChatID: ctx.Msg.Chat.ID, Action: action,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Bot.logger.Errorln(err)
|
ctx.Api.logger.Errorln(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,6 @@ func Encode[T any](w *multipart.Writer, req T) error {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
_, err = fw.Write([]byte(strconv.FormatBool(field.Bool())))
|
_, err = fw.Write([]byte(strconv.FormatBool(field.Bool())))
|
||||||
}
|
}
|
||||||
|
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
if field.Type().Elem().Kind() == reflect.Uint8 && !field.IsNil() {
|
if field.Type().Elem().Kind() == reflect.Uint8 && !field.IsNil() {
|
||||||
filename := fieldType.Tag.Get("filename")
|
filename := fieldType.Tag.Get("filename")
|
||||||
|
|||||||
62
plugins.go
62
plugins.go
@@ -1,6 +1,10 @@
|
|||||||
package laniakea
|
package laniakea
|
||||||
|
|
||||||
import "log"
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"git.nix13.pw/scuroneko/extypes"
|
||||||
|
)
|
||||||
|
|
||||||
type CommandExecutor func(ctx *MsgContext, dbContext *DatabaseContext)
|
type CommandExecutor func(ctx *MsgContext, dbContext *DatabaseContext)
|
||||||
|
|
||||||
@@ -9,6 +13,7 @@ type PluginBuilder struct {
|
|||||||
commands map[string]*CommandExecutor
|
commands map[string]*CommandExecutor
|
||||||
payloads map[string]*CommandExecutor
|
payloads map[string]*CommandExecutor
|
||||||
updateListener *CommandExecutor
|
updateListener *CommandExecutor
|
||||||
|
middlewares extypes.Slice[*PluginMiddleware]
|
||||||
}
|
}
|
||||||
|
|
||||||
type Plugin struct {
|
type Plugin struct {
|
||||||
@@ -16,6 +21,7 @@ type Plugin struct {
|
|||||||
Commands map[string]*CommandExecutor
|
Commands map[string]*CommandExecutor
|
||||||
Payloads map[string]*CommandExecutor
|
Payloads map[string]*CommandExecutor
|
||||||
UpdateListener *CommandExecutor
|
UpdateListener *CommandExecutor
|
||||||
|
Middlewares extypes.Slice[*PluginMiddleware]
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPlugin(name string) *PluginBuilder {
|
func NewPlugin(name string) *PluginBuilder {
|
||||||
@@ -45,15 +51,21 @@ func (p *PluginBuilder) UpdateListener(listener CommandExecutor) *PluginBuilder
|
|||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *PluginBuilder) Middleware(middleware *PluginMiddleware) *PluginBuilder {
|
||||||
|
p.middlewares = p.middlewares.Push(middleware)
|
||||||
|
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.Printf("no command or payloads for %s", p.name)
|
||||||
}
|
}
|
||||||
return 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,
|
||||||
|
Middlewares: p.middlewares,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,6 +77,15 @@ func (p *Plugin) ExecutePayload(payload string, ctx *MsgContext, dbContext *Data
|
|||||||
(*p.Payloads[payload])(ctx, dbContext)
|
(*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 {
|
type Middleware struct {
|
||||||
Name string
|
Name string
|
||||||
Executor CommandExecutor
|
Executor CommandExecutor
|
||||||
@@ -78,8 +99,8 @@ type MiddlewareBuilder struct {
|
|||||||
async bool
|
async bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMiddleware(name string) *MiddlewareBuilder {
|
func NewMiddleware(name string, executor CommandExecutor) *MiddlewareBuilder {
|
||||||
return &MiddlewareBuilder{name: name, async: false}
|
return &MiddlewareBuilder{name: name, executor: executor, order: 0, async: false}
|
||||||
}
|
}
|
||||||
func (m *MiddlewareBuilder) SetName(name string) *MiddlewareBuilder {
|
func (m *MiddlewareBuilder) SetName(name string) *MiddlewareBuilder {
|
||||||
m.name = name
|
m.name = name
|
||||||
@@ -112,3 +133,36 @@ func (m Middleware) Execute(ctx *MsgContext, db *DatabaseContext) {
|
|||||||
m.Execute(ctx, db)
|
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
|
|
||||||
}
|
|
||||||
151
slice.go
151
slice.go
@@ -1,151 +0,0 @@
|
|||||||
package laniakea
|
|
||||||
|
|
||||||
import "slices"
|
|
||||||
|
|
||||||
type Slice[T comparable] []T
|
|
||||||
|
|
||||||
func NewSliceFrom[T comparable](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]) Remove(el T) Slice[T] {
|
|
||||||
index := slices.Index(s, el)
|
|
||||||
if index == -1 {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return s.Pop(index)
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
type Set[T comparable] []T
|
|
||||||
|
|
||||||
func NewSetFrom[T comparable](slice []T) Set[T] {
|
|
||||||
s := make(Set[T], 0)
|
|
||||||
for _, v := range slice {
|
|
||||||
if slices.Index(slice, v) >= 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
s = append(s, v)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
func (s Set[T]) Len() int {
|
|
||||||
return len(s)
|
|
||||||
}
|
|
||||||
func (s Set[T]) Cap() int {
|
|
||||||
return cap(s)
|
|
||||||
}
|
|
||||||
func (s Set[T]) Get(index int) T {
|
|
||||||
return s[index]
|
|
||||||
}
|
|
||||||
func (s Set[T]) Last() T {
|
|
||||||
return s[s.Len()-1]
|
|
||||||
}
|
|
||||||
func (s Set[T]) Swap(i, j int) {
|
|
||||||
s[i], s[j] = s[j], s[i]
|
|
||||||
}
|
|
||||||
func (s Set[T]) Add(v T) Set[T] {
|
|
||||||
index := slices.Index(s, v)
|
|
||||||
if index >= 0 {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return append(s, v)
|
|
||||||
}
|
|
||||||
func (s Set[T]) Pop(index int) Set[T] {
|
|
||||||
if index == 0 {
|
|
||||||
return s[1:]
|
|
||||||
}
|
|
||||||
out := make(Set[T], s.Len()-index)
|
|
||||||
for i, e := range s {
|
|
||||||
if i == index {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
out[i] = e
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
func (s Set[T]) Remove(el T) Set[T] {
|
|
||||||
index := slices.Index(s, el)
|
|
||||||
if index == -1 {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return s.Pop(index)
|
|
||||||
}
|
|
||||||
func (s Set[T]) ToSlice() Slice[T] {
|
|
||||||
out := make(Slice[T], s.Len())
|
|
||||||
copy(out, s)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
func (s Set[T]) ToArray() []T {
|
|
||||||
out := make([]T, len(s))
|
|
||||||
copy(out, s)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
func (s Set[T]) ToAnyArray() []any {
|
|
||||||
out := make([]any, len(s))
|
|
||||||
for i, v := range s {
|
|
||||||
out[i] = v
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
53
types.go
53
types.go
@@ -1,5 +1,7 @@
|
|||||||
package laniakea
|
package laniakea
|
||||||
|
|
||||||
|
import "git.nix13.pw/scuroneko/extypes"
|
||||||
|
|
||||||
type Update struct {
|
type Update struct {
|
||||||
UpdateID int `json:"update_id"`
|
UpdateID int `json:"update_id"`
|
||||||
Message *Message `json:"message"`
|
Message *Message `json:"message"`
|
||||||
@@ -54,9 +56,9 @@ type Message struct {
|
|||||||
Chat *Chat `json:"chat,omitempty"`
|
Chat *Chat `json:"chat,omitempty"`
|
||||||
Text string `json:"text"`
|
Text string `json:"text"`
|
||||||
|
|
||||||
Photo Slice[*PhotoSize] `json:"photo,omitempty"`
|
Photo extypes.Slice[*PhotoSize] `json:"photo,omitempty"`
|
||||||
Caption string `json:"caption,omitempty"`
|
Caption string `json:"caption,omitempty"`
|
||||||
ReplyToMessage *Message `json:"reply_to_message"`
|
ReplyToMessage *Message `json:"reply_to_message"`
|
||||||
|
|
||||||
ReplyMarkup *MessageReplyMarkup `json:"reply_markup,omitempty"`
|
ReplyMarkup *MessageReplyMarkup `json:"reply_markup,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -81,13 +83,15 @@ type MessageEntity struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ReplyParameters struct {
|
type ReplyParameters struct {
|
||||||
MessageID int `json:"message_id"`
|
MessageID int `json:"message_id"`
|
||||||
ChatID int `json:"chat_id,omitempty"`
|
ChatID int `json:"chat_id,omitempty"`
|
||||||
|
|
||||||
AllowSendingWithoutReply bool `json:"allow_sending_without_reply,omitempty"`
|
AllowSendingWithoutReply bool `json:"allow_sending_without_reply,omitempty"`
|
||||||
Quote string `json:"quote,omitempty"`
|
Quote string `json:"quote,omitempty"`
|
||||||
QuoteParsingMode string `json:"quote_parsing_mode,omitempty"`
|
QuoteParsingMode string `json:"quote_parsing_mode,omitempty"`
|
||||||
QuoteEntities []*MessageEntity `json:"quote_entities,omitempty"`
|
QuoteEntities []*MessageEntity `json:"quote_entities,omitempty"`
|
||||||
QuotePosition int `json:"quote_postigin,omitempty"`
|
QuotePosition int `json:"quote_position,omitempty"`
|
||||||
|
ChecklistTaskID int `json:"checklist_task_id,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PhotoSize struct {
|
type PhotoSize struct {
|
||||||
@@ -106,14 +110,31 @@ type LinkPreviewOptions struct {
|
|||||||
ShowAboveText bool `json:"show_above_text,omitempty"`
|
ShowAboveText bool `json:"show_above_text,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ReplyMarkup struct {
|
||||||
|
InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard,omitempty"`
|
||||||
|
|
||||||
|
Keyboard [][]int `json:"keyboard,omitempty"`
|
||||||
|
IsPersistent bool `json:"is_persistent,omitempty"`
|
||||||
|
ResizeKeyboard bool `json:"resize_keyboard,omitempty"`
|
||||||
|
OneTimeKeyboard bool `json:"one_time_keyboard,omitempty"`
|
||||||
|
InputFieldPlaceholder string `json:"input_field_placeholder,omitempty"`
|
||||||
|
Selective bool `json:"selective,omitempty"`
|
||||||
|
|
||||||
|
RemoveKeyboard bool `json:"remove_keyboard,omitempty"`
|
||||||
|
|
||||||
|
ForceReply bool `json:"force_reply,omitempty"`
|
||||||
|
}
|
||||||
type InlineKeyboardMarkup struct {
|
type InlineKeyboardMarkup struct {
|
||||||
InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard,omitempty"`
|
InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type KeyboardButtonStyle string
|
||||||
type InlineKeyboardButton struct {
|
type InlineKeyboardButton struct {
|
||||||
Text string `json:"text"`
|
Text string `json:"text"`
|
||||||
URL string `json:"url,omitempty"`
|
URL string `json:"url,omitempty"`
|
||||||
CallbackData string `json:"callback_data,omitempty"`
|
CallbackData string `json:"callback_data,omitempty"`
|
||||||
|
Style KeyboardButtonStyle `json:"style,omitempty"`
|
||||||
|
IconCustomEmojiID string `json:"icon_custom_emoji_id,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReplyKeyboardMarkup struct {
|
type ReplyKeyboardMarkup struct {
|
||||||
@@ -192,3 +213,17 @@ const (
|
|||||||
ChatActionFindLocation ChatActions = "find_location"
|
ChatActionFindLocation ChatActions = "find_location"
|
||||||
ChatActionUploadVideoNone ChatActions = "upload_video_none"
|
ChatActionUploadVideoNone ChatActions = "upload_video_none"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type SuggestedPostPrice struct {
|
||||||
|
Currency string `json:"currency"`
|
||||||
|
Amount int `json:"amount"`
|
||||||
|
}
|
||||||
|
type SuggestedPostInfo struct {
|
||||||
|
State string `json:"state"` //State of the suggested post. Currently, it can be one of “pending”, “approved”, “declined”.
|
||||||
|
Price SuggestedPostPrice `json:"price"`
|
||||||
|
SendDate int `json:"send_date"`
|
||||||
|
}
|
||||||
|
type SuggestedPostParameters struct {
|
||||||
|
Price SuggestedPostPrice `json:"price"`
|
||||||
|
SendDate int `json:"send_date"`
|
||||||
|
}
|
||||||
|
|||||||
24
uploader.go
24
uploader.go
@@ -8,14 +8,22 @@ import (
|
|||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"git.nix13.pw/scuroneko/slog"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Uploader struct {
|
type Uploader struct {
|
||||||
bot *Bot
|
api *Api
|
||||||
|
logger *slog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUploader(bot *Bot) *Uploader {
|
func NewUploader(api *Api) *Uploader {
|
||||||
return &Uploader{bot: bot}
|
logger := slog.CreateLogger().Level(GetLoggerLevel()).Prefix("UPLOADER")
|
||||||
|
logger.AddWriter(logger.CreateJsonStdoutWriter())
|
||||||
|
return &Uploader{api, logger}
|
||||||
|
}
|
||||||
|
func (u *Uploader) Close() error {
|
||||||
|
return u.logger.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
type UploaderFileType string
|
type UploaderFileType string
|
||||||
@@ -56,8 +64,8 @@ func NewUploaderRequest[R, P any](method string, file UploaderFile, params P) Up
|
|||||||
return UploaderRequest[R, P]{method, file, params}
|
return UploaderRequest[R, P]{method, file, params}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u UploaderRequest[R, P]) Do(bot *Bot) (*R, error) {
|
func (u UploaderRequest[R, P]) Do(up *Uploader) (*R, error) {
|
||||||
url := fmt.Sprintf("https://api.telegram.org/bot%s/%s", bot.token, u.method)
|
url := fmt.Sprintf("https://api.telegram.org/bot%s/%s", up.api.token, u.method)
|
||||||
|
|
||||||
buf := bytes.NewBuffer(nil)
|
buf := bytes.NewBuffer(nil)
|
||||||
w := multipart.NewWriter(buf)
|
w := multipart.NewWriter(buf)
|
||||||
@@ -87,7 +95,7 @@ func (u UploaderRequest[R, P]) Do(bot *Bot) (*R, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
req.Header.Set("Content-Type", w.FormDataContentType())
|
req.Header.Set("Content-Type", w.FormDataContentType())
|
||||||
bot.logger.Debugln("UPLOADER REQ", u.method)
|
up.logger.Debugln("UPLOADER REQ", u.method)
|
||||||
res, err := http.DefaultClient.Do(req)
|
res, err := http.DefaultClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -98,7 +106,7 @@ func (u UploaderRequest[R, P]) Do(bot *Bot) (*R, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
bot.logger.Debugln("UPLOADER RES", u.method, string(body))
|
up.logger.Debugln("UPLOADER RES", u.method, string(body))
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
return nil, fmt.Errorf("[%d] %s", res.StatusCode, string(body))
|
return nil, fmt.Errorf("[%d] %s", res.StatusCode, string(body))
|
||||||
}
|
}
|
||||||
@@ -116,7 +124,7 @@ func (u UploaderRequest[R, P]) Do(bot *Bot) (*R, error) {
|
|||||||
|
|
||||||
func (u *Uploader) UploadPhoto(file UploaderFile, params SendPhotoBaseP) (*Message, error) {
|
func (u *Uploader) UploadPhoto(file UploaderFile, params SendPhotoBaseP) (*Message, error) {
|
||||||
req := NewUploaderRequest[Message]("sendPhoto", file, params)
|
req := NewUploaderRequest[Message]("sendPhoto", file, params)
|
||||||
return req.Do(u.bot)
|
return req.Do(u)
|
||||||
}
|
}
|
||||||
|
|
||||||
func uploaderTypeByExt(filename string) UploaderFileType {
|
func uploaderTypeByExt(filename string) UploaderFileType {
|
||||||
|
|||||||
11
utils.go
11
utils.go
@@ -3,9 +3,20 @@ package laniakea
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"git.nix13.pw/scuroneko/slog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func GetLoggerLevel() slog.LogLevel {
|
||||||
|
level := slog.FATAL
|
||||||
|
if os.Getenv("DEBUG") == "true" {
|
||||||
|
level = slog.DEBUG
|
||||||
|
}
|
||||||
|
return level
|
||||||
|
}
|
||||||
|
|
||||||
// MapToStruct unsafe function
|
// MapToStruct unsafe function
|
||||||
func MapToStruct(m map[string]any, s any) error {
|
func MapToStruct(m map[string]any, s any) error {
|
||||||
data, err := json.Marshal(m)
|
data, err := json.Marshal(m)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package laniakea
|
package laniakea
|
||||||
|
|
||||||
const (
|
const (
|
||||||
VersionString = "0.3.8"
|
VersionString = "0.4.3"
|
||||||
VersionMajor = 0
|
VersionMajor = 0
|
||||||
VersionMinor = 3
|
VersionMinor = 4
|
||||||
VersionPatch = 8
|
VersionPatch = 3
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user