9 Commits

Author SHA1 Message Date
434638a61d small fix; v0.6.1 2026-02-18 11:46:53 +03:00
c2909b4cfb small fix; v0.6.1 2026-02-18 11:46:48 +03:00
746847cf61 l10n and bot command auto generation; v0.6.0 2026-02-18 11:39:27 +03:00
b2bda02c0f l10n and bot command auto generation; v0.6.0 2026-02-18 11:39:20 +03:00
bb51a0ecb1 l10n and cmd generator WIP 2026-02-17 22:44:23 +03:00
4527dd661a small change 2026-02-12 13:59:35 +03:00
4129b8e688 some cleanup 2026-02-12 13:50:02 +03:00
12883f428e Merge branch 'dev' of nix13.pw:ScuroNeko/Laniakea into dev 2026-02-12 13:49:06 +03:00
f29ef979bf bump extypes 2026-02-12 13:48:47 +03:00
24 changed files with 633 additions and 565 deletions

90
bot.go
View File

@@ -2,7 +2,6 @@ package laniakea
import ( import (
"fmt" "fmt"
"log"
"os" "os"
"sort" "sort"
"strings" "strings"
@@ -16,34 +15,6 @@ import (
"go.mongodb.org/mongo-driver/v2/mongo" "go.mongodb.org/mongo-driver/v2/mongo"
) )
type Bot struct {
token string
debug bool
errorTemplate string
logger *slog.Logger
RequestLogger *slog.Logger
plugins []Plugin
middlewares []Middleware
prefixes []string
runners []Runner
dbContext *DatabaseContext
api *tgapi.Api
dbWriterRequested extypes.Slice[*slog.Logger]
updateOffset int
updateTypes []tgapi.UpdateType
updateQueue *extypes.Queue[*tgapi.Update]
}
func (b *Bot) GetUpdateOffset() int { return b.updateOffset }
func (b *Bot) SetUpdateOffset(offset int) { b.updateOffset = offset }
func (b *Bot) GetUpdateTypes() []tgapi.UpdateType { return b.updateTypes }
func (b *Bot) GetQueue() *extypes.Queue[*tgapi.Update] { return b.updateQueue }
type BotSettings struct { type BotSettings struct {
Token string Token string
Debug bool Debug bool
@@ -70,10 +41,35 @@ func LoadSettingsFromEnv() *BotSettings {
func LoadPrefixesFromEnv() []string { func LoadPrefixesFromEnv() []string {
prefixesS, exists := os.LookupEnv("PREFIXES") prefixesS, exists := os.LookupEnv("PREFIXES")
if !exists { if !exists {
return []string{"!"} return []string{"/"}
} }
return strings.Split(prefixesS, ";") return strings.Split(prefixesS, ";")
} }
type Bot struct {
token string
debug bool
errorTemplate string
logger *slog.Logger
RequestLogger *slog.Logger
plugins []Plugin
middlewares []Middleware
prefixes []string
runners []Runner
dbContext *DatabaseContext
api *tgapi.API
l10n L10n
dbWriterRequested extypes.Slice[*slog.Logger]
updateOffset int
updateTypes []tgapi.UpdateType
updateQueue *extypes.Queue[*tgapi.Update]
}
func NewBot(settings *BotSettings) *Bot { func NewBot(settings *BotSettings) *Bot {
updateQueue := extypes.CreateQueue[*tgapi.Update](256) updateQueue := extypes.CreateQueue[*tgapi.Update](256)
api := tgapi.NewAPI(settings.Token) api := tgapi.NewAPI(settings.Token)
@@ -81,7 +77,7 @@ func NewBot(settings *BotSettings) *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([]tgapi.UpdateType, 0), runners: make([]Runner, 0), prefixes: settings.Prefixes, updateTypes: make([]tgapi.UpdateType, 0), runners: make([]Runner, 0),
updateQueue: updateQueue, api: api, dbWriterRequested: make([]*slog.Logger, 0), updateQueue: updateQueue, api: api, dbWriterRequested: make([]*slog.Logger, 0),
token: settings.Token, token: settings.Token, l10n: L10n{},
} }
bot.dbWriterRequested = bot.dbWriterRequested.Push(api.Logger) bot.dbWriterRequested = bot.dbWriterRequested.Push(api.Logger)
@@ -130,17 +126,20 @@ func NewBot(settings *BotSettings) *Bot {
return bot return bot
} }
func (b *Bot) Close() { func (b *Bot) Close() error {
err := b.logger.Close() err := b.logger.Close()
if err != nil { if err != nil {
log.Println(err) return err
} }
err = b.RequestLogger.Close() err = b.RequestLogger.Close()
if err != nil { return err
log.Println(err)
}
} }
func (b *Bot) GetUpdateOffset() int { return b.updateOffset }
func (b *Bot) SetUpdateOffset(offset int) { b.updateOffset = offset }
func (b *Bot) GetUpdateTypes() []tgapi.UpdateType { return b.updateTypes }
func (b *Bot) GetQueue() *extypes.Queue[*tgapi.Update] { return b.updateQueue }
type DatabaseContext struct { type DatabaseContext struct {
PostgresSQL *sqlx.DB PostgresSQL *sqlx.DB
MongoDB *mongo.Client MongoDB *mongo.Client
@@ -184,9 +183,9 @@ 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...)
for _, p := range plugin { for _, p := range plugin {
b.plugins = append(b.plugins, *p)
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
@@ -194,16 +193,16 @@ func (b *Bot) AddPlugins(plugin ...Plugin) *Bot {
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 {
return first.Name < second.Name return first.name < second.name
} }
return first.Order < second.Order return first.order < second.order
}) })
return b return b
@@ -213,6 +212,13 @@ func (b *Bot) AddRunner(runner Runner) *Bot {
b.logger.Debugln(fmt.Sprintf("runner with name \"%s\" registered", runner.Name)) b.logger.Debugln(fmt.Sprintf("runner with name \"%s\" registered", runner.Name))
return b return b
} }
func (b *Bot) AddL10n(l L10n) *Bot {
b.l10n = l
return b
}
func (b *Bot) L10n(lang, key string) string {
return b.l10n.Translate(lang, key)
}
func (b *Bot) Logger() *slog.Logger { func (b *Bot) Logger() *slog.Logger {
return b.logger return b.logger
} }

62
cmd_generator.go Normal file
View File

@@ -0,0 +1,62 @@
package laniakea
import (
"fmt"
"strings"
"git.nix13.pw/scuroneko/laniakea/tgapi"
)
func generateBotCommand(cmd Command) tgapi.BotCommand {
desc := cmd.command
if len(cmd.description) > 0 {
desc = cmd.description
}
var descArgs []string
for _, a := range cmd.args {
if a.required {
descArgs = append(descArgs, fmt.Sprintf("%s", a.text))
} else {
descArgs = append(descArgs, fmt.Sprintf("[%s]", a.text))
}
}
desc = fmt.Sprintf("%s. Usage: /%s %s", desc, cmd.command, strings.Join(descArgs, " "))
return tgapi.BotCommand{Command: cmd.command, Description: desc}
}
func generateBotCommandForPlugin(pl Plugin) []tgapi.BotCommand {
commands := make([]tgapi.BotCommand, 0)
for _, cmd := range pl.Commands {
if cmd.skipAutoCmd {
continue
}
commands = append(commands, generateBotCommand(cmd))
}
return commands
}
func (b *Bot) AutoGenerateCommands() error {
_, err := b.api.DeleteMyCommands(tgapi.DeleteMyCommandsP{})
if err != nil {
return err
}
commands := make([]tgapi.BotCommand, 0)
for _, pl := range b.plugins {
commands = append(commands, generateBotCommandForPlugin(pl)...)
}
privateChatsScope := &tgapi.BotCommandScope{Type: tgapi.BotCommandScopePrivateType}
groupChatsScope := &tgapi.BotCommandScope{Type: tgapi.BotCommandScopeGroupType}
chatAdminsScope := &tgapi.BotCommandScope{Type: tgapi.BotCommandScopeAllChatAdministratorsType}
_, err = b.api.SetMyCommands(tgapi.SetMyCommandsP{Commands: commands, Scope: privateChatsScope})
if err != nil {
return err
}
_, err = b.api.SetMyCommands(tgapi.SetMyCommandsP{Commands: commands, Scope: groupChatsScope})
if err != nil {
return err
}
_, err = b.api.SetMyCommands(tgapi.SetMyCommandsP{Commands: commands, Scope: chatAdminsScope})
return err
}

7
go.mod
View File

@@ -1,11 +1,11 @@
module git.nix13.pw/scuroneko/laniakea module git.nix13.pw/scuroneko/laniakea
go 1.25 go 1.26
require ( require (
git.nix13.pw/scuroneko/extypes v1.1.0 git.nix13.pw/scuroneko/extypes v1.2.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.18.0
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
) )
@@ -23,6 +23,7 @@ require (
github.com/xdg-go/scram v1.2.0 // indirect github.com/xdg-go/scram v1.2.0 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.uber.org/atomic v1.11.0 // indirect
golang.org/x/crypto v0.48.0 // indirect golang.org/x/crypto v0.48.0 // indirect
golang.org/x/sync v0.19.0 // indirect golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.41.0 // indirect golang.org/x/sys v0.41.0 // indirect

22
go.sum
View File

@@ -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/extypes v1.1.0 h1:kdAraybAqQgVhArVkVfrIi7KVEX8HgTr8mzbIZAAAqg= git.nix13.pw/scuroneko/extypes v1.2.0 h1:2n2hD6KsMAted+6MGhAyeWyli2Qzc9G2y+pQNB7C1dM=
git.nix13.pw/scuroneko/extypes v1.1.0/go.mod h1:uZVs8Yo3RrYAG9dMad6qR6lsYY67t+459D9c65QAYAw= git.nix13.pw/scuroneko/extypes v1.2.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=
@@ -22,6 +22,8 @@ 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.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=
github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
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=
@@ -32,14 +34,12 @@ github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwp
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/muir/list v1.2.1 h1:lmF8fz2B1WbXkzHr/Eh0oWPJArDBzWqIifOwbA4gWSo= github.com/muir/list v1.2.1 h1:lmF8fz2B1WbXkzHr/Eh0oWPJArDBzWqIifOwbA4gWSo=
github.com/muir/list v1.2.1/go.mod h1:v0l2f997MxCohQlD7PTejJqyYKwFVz/i3mTpDl4LAf0= github.com/muir/list v1.2.1/go.mod h1:v0l2f997MxCohQlD7PTejJqyYKwFVz/i3mTpDl4LAf0=
github.com/muir/sqltoken v0.2.1 h1:19KvJrCj9aOMfU921hjnizWPlQmPTe+tb36zupOY2FA=
github.com/muir/sqltoken v0.2.1/go.mod h1:sSlj5M0VqQ4OuedmxwWs1TmzzRXaH3DLf5ukzg6meIo=
github.com/muir/sqltoken v0.3.0 h1:3xbcqr80f3IA4OlwkOpdIHC4DTu6gsi1TwMqgYL4Dpg= github.com/muir/sqltoken v0.3.0 h1:3xbcqr80f3IA4OlwkOpdIHC4DTu6gsi1TwMqgYL4Dpg=
github.com/muir/sqltoken v0.3.0/go.mod h1:+OSmbGI22QcVZ6DCzlHT8EAzEq/mqtqedtPP91Le+3A= github.com/muir/sqltoken v0.3.0/go.mod h1:+OSmbGI22QcVZ6DCzlHT8EAzEq/mqtqedtPP91Le+3A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/v9 v9.17.3 h1:fN29NdNrE17KttK5Ndf20buqfDZwGNgoUr9qjl1DQx4= github.com/redis/go-redis/v9 v9.18.0 h1:pMkxYPkEbMPwRdenAzUNyFNrDgHx9U+DrBabWNfSRQs=
github.com/redis/go-redis/v9 v9.17.3/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370= github.com/redis/go-redis/v9 v9.18.0/go.mod h1:k3ufPphLU5YXwNTUcCRXGxUoF1fqxnhFQmscfkCoDA0=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/vinovest/sqlx v1.7.1 h1:kdq4v0N9kRLpytWGSWOw4aulOGdQPmIoMR6Y+cTBxow= github.com/vinovest/sqlx v1.7.1 h1:kdq4v0N9kRLpytWGSWOw4aulOGdQPmIoMR6Y+cTBxow=
@@ -53,12 +53,14 @@ github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gi
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM= github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE= go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE=
go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0= go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@@ -75,8 +77,6 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -85,8 +85,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@@ -1,6 +1,7 @@
package laniakea package laniakea
import ( import (
"encoding/base64"
"encoding/json" "encoding/json"
"strings" "strings"
@@ -45,7 +46,6 @@ func (b *Bot) handleMessage(update *tgapi.Update, ctx *MsgContext) {
text = strings.TrimSpace(text[len(prefix):]) text = strings.TrimSpace(text[len(prefix):])
for _, plugin := range b.plugins { for _, plugin := range b.plugins {
// Check every command
for cmd := range plugin.Commands { for cmd := range plugin.Commands {
if !strings.HasPrefix(text, cmd) { if !strings.HasPrefix(text, cmd) {
continue continue
@@ -59,17 +59,22 @@ func (b *Bot) handleMessage(update *tgapi.Update, ctx *MsgContext) {
break break
} }
} }
if !isValid { if !isValid {
continue continue
} }
ctx.Text = strings.TrimSpace(text[len(cmd):]) ctx.Text = strings.TrimSpace(text[len(cmd):])
if ctx.Text == "" {
ctx.Args = []string{}
} else {
ctx.Args = strings.Split(ctx.Text, " ") ctx.Args = strings.Split(ctx.Text, " ")
}
if !plugin.executeMiddlewares(ctx, b.dbContext) { if !plugin.executeMiddlewares(ctx, b.dbContext) {
return return
} }
go plugin.Execute(cmd, ctx, b.dbContext) go plugin.executeCmd(cmd, ctx, b.dbContext)
return return
} }
} }
@@ -99,7 +104,7 @@ func (b *Bot) handleCallback(update *tgapi.Update, ctx *MsgContext) {
if !plugin.executeMiddlewares(ctx, b.dbContext) { if !plugin.executeMiddlewares(ctx, b.dbContext) {
return return
} }
go plugin.ExecutePayload(data.Command, ctx, b.dbContext) go plugin.executePayload(data.Command, ctx, b.dbContext)
return return
} }
} }
@@ -112,3 +117,32 @@ func (b *Bot) checkPrefixes(text string) (string, bool) {
} }
return "", false return "", false
} }
func encodeJsonPayload(d CallbackData) (string, error) {
b, err := json.Marshal(d)
if err != nil {
return "", err
}
return string(b), nil
}
func decodeJsonPayload(s string) (CallbackData, error) {
var data CallbackData
err := json.Unmarshal([]byte(s), &data)
return data, err
}
func encodeBase64Payload(d CallbackData) (string, error) {
data, err := encodeJsonPayload(d)
if err != nil {
return "", err
}
dst := make([]byte, base64.StdEncoding.EncodedLen(len([]byte(data))))
base64.StdEncoding.Encode(dst, []byte(data))
return string(dst), nil
}
func decodeBase64Payload(s string) (CallbackData, error) {
b, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return CallbackData{}, err
}
return decodeJsonPayload(string(b))
}

27
l10n.go Normal file
View File

@@ -0,0 +1,27 @@
package laniakea
// DictEntry {key:{ru:123,en:123}}
type DictEntry map[string]string
type L10n struct {
entries map[string]DictEntry
fallbackLang string
}
func NewL10n(fallbackLanguage string) *L10n {
return &L10n{make(map[string]DictEntry), fallbackLanguage}
}
func (l *L10n) AddDictEntry(key string, value DictEntry) *L10n {
l.entries[key] = value
return l
}
func (l *L10n) GetFallbackLanguage() string {
return l.fallbackLang
}
func (l *L10n) Translate(lang, key string) string {
s, ok := l.entries[key]
if !ok {
return key
}
return s[lang]
}

View File

@@ -9,7 +9,7 @@ import (
type MsgContext struct { type MsgContext struct {
Bot *Bot Bot *Bot
Api *tgapi.Api Api *tgapi.API
Msg *tgapi.Message Msg *tgapi.Message
Update tgapi.Update Update tgapi.Update
@@ -26,7 +26,6 @@ type AnswerMessage struct {
MessageID int MessageID int
Text string Text string
IsMedia bool IsMedia bool
Keyboard *InlineKeyboard
ctx *MsgContext ctx *MsgContext
} }
@@ -213,3 +212,11 @@ func (ctx *MsgContext) error(err error) {
func (ctx *MsgContext) Error(err error) { func (ctx *MsgContext) Error(err error) {
ctx.error(err) ctx.error(err)
} }
func (ctx *MsgContext) Translate(key string) string {
if ctx.From == nil {
return key
}
lang := Val(ctx.From.LanguageCode, ctx.Bot.l10n.GetFallbackLanguage())
return ctx.Bot.L10n(lang, key)
}

View File

@@ -1,72 +1,142 @@
package laniakea package laniakea
import ( import (
"log" "errors"
"regexp"
"git.nix13.pw/scuroneko/extypes" "git.nix13.pw/scuroneko/extypes"
) )
type CommandExecutor func(ctx *MsgContext, dbContext *DatabaseContext) const (
CommandValueStringType CommandValueType = "string"
CommandValueIntType CommandValueType = "int"
CommandValueBoolType CommandValueType = "bool"
CommandValueAnyType CommandValueType = "any"
)
type PluginBuilder struct { var (
name string CommandRegexInt = regexp.MustCompile("\\d+")
commands map[string]CommandExecutor CommandRegexString = regexp.MustCompile(".+")
payloads map[string]CommandExecutor )
middlewares extypes.Slice[*PluginMiddleware]
var (
ErrCmdArgCountMismatch = errors.New("command arg count mismatch")
ErrCmdArgRegexpMismatch = errors.New("command arg regexp mismatch")
)
type CommandValueType string
type CommandArg struct {
valueType CommandValueType
text string
regex *regexp.Regexp
required bool
}
func NewCommandArg(text string, valueType CommandValueType) *CommandArg {
regex := CommandRegexString
switch valueType {
case CommandValueIntType:
regex = CommandRegexInt
}
return &CommandArg{valueType, text, regex, false}
}
func (c *CommandArg) SetRequired() *CommandArg {
c.required = true
return c
}
type CommandExecutor func(ctx *MsgContext, dbContext *DatabaseContext)
type Command struct {
command string
description string
exec CommandExecutor
args extypes.Slice[CommandArg]
middlewares extypes.Slice[Middleware]
skipAutoCmd bool
}
func NewCommand(exec CommandExecutor, command string, args ...CommandArg) *Command {
return &Command{command, "", exec, args, make(extypes.Slice[Middleware], 0), false}
}
func (c *Command) Use(m Middleware) *Command {
c.middlewares = c.middlewares.Push(m)
return c
}
func (c *Command) SetDescription(desc string) *Command {
c.description = desc
return c
}
func (c *Command) SkipCommandAutoGen() *Command {
c.skipAutoCmd = true
return c
}
func (c *Command) validateArgs(args []string) error {
cmdArgs := c.args.Filter(func(e CommandArg) bool { return !e.required })
if len(args) < cmdArgs.Len() {
return ErrCmdArgCountMismatch
}
for i, arg := range args {
if i >= c.args.Len() {
break
}
cmdArg := c.args.Get(i)
if cmdArg.regex == nil {
continue
}
if !cmdArg.regex.MatchString(arg) {
return ErrCmdArgRegexpMismatch
}
}
return nil
} }
type Plugin struct { type Plugin struct {
Name string Name string
Commands map[string]CommandExecutor Commands map[string]Command
Payloads map[string]CommandExecutor Payloads map[string]Command
Middlewares extypes.Slice[*PluginMiddleware] Middlewares extypes.Slice[Middleware]
} }
func NewPlugin(name string) *PluginBuilder { func NewPlugin(name string) *Plugin {
return &PluginBuilder{ return &Plugin{
name: name, name, map[string]Command{},
commands: make(map[string]CommandExecutor), map[string]Command{}, extypes.Slice[Middleware]{},
payloads: make(map[string]CommandExecutor),
} }
} }
func (p *PluginBuilder) Command(f CommandExecutor, cmd ...string) *PluginBuilder { func (p *Plugin) AddCommand(command *Command) *Plugin {
for _, c := range cmd { p.Commands[command.command] = *command
p.commands[c] = f return p
} }
func (p *Plugin) NewCommand(exec CommandExecutor, command string, args ...CommandArg) *Command {
return NewCommand(exec, command, args...)
}
func (p *Plugin) AddPayload(command *Command) *Plugin {
p.Payloads[command.command] = *command
return p
}
func (p *Plugin) AddMiddleware(middleware Middleware) *Plugin {
p.Middlewares = p.Middlewares.Push(middleware)
return p return p
} }
func (p *PluginBuilder) Payload(f CommandExecutor, payloads ...string) *PluginBuilder { func (p *Plugin) executeCmd(cmd string, ctx *MsgContext, dbContext *DatabaseContext) {
for _, payload := range payloads { command := p.Commands[cmd]
p.payloads[payload] = f if err := command.validateArgs(ctx.Args); err != nil {
ctx.error(err)
return
} }
return p command.exec(ctx, dbContext)
} }
func (p *Plugin) executePayload(payload string, ctx *MsgContext, dbContext *DatabaseContext) {
func (p *PluginBuilder) AddMiddleware(middleware *PluginMiddleware) *PluginBuilder { pl := p.Payloads[payload]
p.middlewares = p.middlewares.Push(middleware) if err := pl.validateArgs(ctx.Args); err != nil {
return p ctx.error(err)
return
} }
pl.exec(ctx, dbContext)
func (p *PluginBuilder) Build() Plugin {
if len(p.commands) == 0 && len(p.payloads) == 0 {
log.Printf("no command or payloads for %s", p.name)
} }
return Plugin{
p.name, p.commands,
p.payloads, p.middlewares,
}
}
func (p *Plugin) Execute(cmd string, ctx *MsgContext, dbContext *DatabaseContext) {
(p.Commands[cmd])(ctx, dbContext)
}
func (p *Plugin) ExecutePayload(payload string, ctx *MsgContext, dbContext *DatabaseContext) {
(p.Payloads[payload])(ctx, dbContext)
}
func (p *Plugin) executeMiddlewares(ctx *MsgContext, db *DatabaseContext) bool { func (p *Plugin) executeMiddlewares(ctx *MsgContext, db *DatabaseContext) bool {
for _, m := range p.Middlewares { for _, m := range p.Middlewares {
if !m.Execute(ctx, db) { if !m.Execute(ctx, db) {
@@ -76,72 +146,29 @@ func (p *Plugin) executeMiddlewares(ctx *MsgContext, db *DatabaseContext) bool {
return true return true
} }
type Middleware struct { type MiddlewareExecutor func(ctx *MsgContext, db *DatabaseContext) bool
Name string
Executor CommandExecutor
Order int
Async bool
}
type MiddlewareBuilder struct {
name string
executor CommandExecutor
order int
async bool
}
func NewMiddleware(name string, executor CommandExecutor) *MiddlewareBuilder { // Middleware
return &MiddlewareBuilder{name: name, executor: executor, order: 0, async: false}
}
func (m *MiddlewareBuilder) SetOrder(order int) *MiddlewareBuilder {
m.order = order
return m
}
func (m *MiddlewareBuilder) SetAsync(async bool) *MiddlewareBuilder {
m.async = async
return m
}
func (m *MiddlewareBuilder) Build() Middleware {
return Middleware{
Name: m.name,
Executor: m.executor,
Order: m.order,
Async: m.async,
}
}
func (m Middleware) Execute(ctx *MsgContext, db *DatabaseContext) {
if m.Async {
go m.Executor(ctx, db)
} else {
m.Execute(ctx, db)
}
}
type PluginMiddlewareExecutor func(ctx *MsgContext, db *DatabaseContext) bool
// PluginMiddleware
// When async, returned value ignored // When async, returned value ignored
type PluginMiddleware struct { type Middleware struct {
executor PluginMiddlewareExecutor name string
executor MiddlewareExecutor
order int order int
async bool async bool
} }
func NewPluginMiddleware(executor PluginMiddlewareExecutor) *PluginMiddleware { func NewMiddleware(name string, executor MiddlewareExecutor) *Middleware {
return &PluginMiddleware{ return &Middleware{name, executor, 0, false}
executor: executor,
order: 0,
async: false,
} }
} func (m *Middleware) SetOrder(order int) *Middleware {
func (m *PluginMiddleware) SetOrder(order int) *PluginMiddleware {
m.order = order m.order = order
return m return m
} }
func (m *PluginMiddleware) SetAsync(async bool) *PluginMiddleware { func (m *Middleware) SetAsync(async bool) *Middleware {
m.async = async m.async = async
return m return m
} }
func (m *PluginMiddleware) Execute(ctx *MsgContext, db *DatabaseContext) bool { func (m *Middleware) Execute(ctx *MsgContext, db *DatabaseContext) bool {
if m.async { if m.async {
go m.executor(ctx, db) go m.executor(ctx, db)
return true return true

View File

@@ -7,26 +7,25 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"strings"
"time" "time"
"git.nix13.pw/scuroneko/laniakea/utils" "git.nix13.pw/scuroneko/laniakea/utils"
"git.nix13.pw/scuroneko/slog" "git.nix13.pw/scuroneko/slog"
) )
type Api struct { type API struct {
token string token string
client *http.Client client *http.Client
Logger *slog.Logger Logger *slog.Logger
} }
func NewAPI(token string) *Api { func NewAPI(token string) *API {
l := slog.CreateLogger().Level(utils.GetLoggerLevel()).Prefix("API") l := slog.CreateLogger().Level(utils.GetLoggerLevel()).Prefix("API")
l.AddWriter(l.CreateJsonStdoutWriter()) l.AddWriter(l.CreateJsonStdoutWriter())
client := &http.Client{Timeout: time.Second * 45} client := &http.Client{Timeout: time.Second * 45}
return &Api{token, client, l} return &API{token, client, l}
} }
func (api *Api) CloseApi() error { func (api *API) CloseApi() error {
return api.Logger.Close() return api.Logger.Close()
} }
@@ -45,7 +44,7 @@ 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]) DoWithContext(ctx context.Context, api *Api) (R, error) { func (r TelegramRequest[R, P]) DoWithContext(ctx context.Context, api *API) (R, error) {
var zero R var zero R
data, err := json.Marshal(r.params) data, err := json.Marshal(r.params)
if err != nil { if err != nil {
@@ -54,12 +53,6 @@ func (r TelegramRequest[R, P]) DoWithContext(ctx context.Context, api *Api) (R,
buf := bytes.NewBuffer(data) buf := bytes.NewBuffer(data)
u := fmt.Sprintf("https://api.telegram.org/bot%s/%s", api.token, r.method) u := fmt.Sprintf("https://api.telegram.org/bot%s/%s", api.token, r.method)
if api.Logger != nil {
api.Logger.Debugln(strings.ReplaceAll(fmt.Sprintf(
"POST %s %s", u, buf.String(),
), api.token, "<TOKEN>"))
}
req, err := http.NewRequestWithContext(ctx, "POST", u, buf) req, err := http.NewRequestWithContext(ctx, "POST", u, buf)
if err != nil { if err != nil {
return zero, err return zero, err
@@ -68,23 +61,21 @@ func (r TelegramRequest[R, P]) DoWithContext(ctx context.Context, api *Api) (R,
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("User-Agent", fmt.Sprintf("Laniakea/%s", utils.VersionString)) req.Header.Set("User-Agent", fmt.Sprintf("Laniakea/%s", utils.VersionString))
api.Logger.Debugln("REQ", r.method, buf.String())
res, err := api.client.Do(req) res, err := api.client.Do(req)
if err != nil { if err != nil {
return zero, err return zero, err
} }
defer res.Body.Close() defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return zero, fmt.Errorf("unexpected status code: %d", res.StatusCode)
}
reader := io.LimitReader(res.Body, 10<<20) reader := io.LimitReader(res.Body, 10<<20)
data, err = io.ReadAll(reader) data, err = io.ReadAll(reader)
if err != nil { if err != nil {
return zero, err return zero, err
} }
api.Logger.Debugln("RES", r.method, string(data))
if api.Logger != nil { if res.StatusCode != http.StatusOK {
api.Logger.Debugln(fmt.Sprintf("RES %s %s", r.method, string(data))) return zero, fmt.Errorf("unexpected status code: %d", res.StatusCode)
} }
var resp ApiResponse[R] var resp ApiResponse[R]
@@ -92,14 +83,13 @@ func (r TelegramRequest[R, P]) DoWithContext(ctx context.Context, api *Api) (R,
if err != nil { if err != nil {
return zero, err return zero, err
} }
if !resp.Ok { if !resp.Ok {
return zero, fmt.Errorf("[%d] %s", resp.ErrorCode, resp.Description) return zero, fmt.Errorf("[%d] %s", resp.ErrorCode, resp.Description)
} }
return resp.Result, nil return resp.Result, nil
} }
func (r TelegramRequest[R, P]) Do(api *Api) (R, error) { func (r TelegramRequest[R, P]) Do(api *API) (R, error) {
ctx := context.Background() ctx := context.Background()
return r.DoWithContext(ctx, api) return r.DoWithContext(ctx, api)
} }

View File

@@ -23,7 +23,7 @@ type SendPhotoP struct {
ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"`
} }
func (api *Api) 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(api) return req.Do(api)
} }
@@ -52,7 +52,7 @@ type SendAudioP struct {
ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"`
} }
func (api *Api) SendAudio(params SendAudioP) (Message, error) { func (api *API) SendAudio(params SendAudioP) (Message, error) {
req := NewRequest[Message]("sendAudio", params) req := NewRequest[Message]("sendAudio", params)
return req.Do(api) return req.Do(api)
} }
@@ -78,7 +78,7 @@ type SendDocumentP struct {
ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"`
} }
func (api *Api) SendDocument(params SendDocumentP) (Message, error) { func (api *API) SendDocument(params SendDocumentP) (Message, error) {
req := NewRequest[Message]("sendDocument", params) req := NewRequest[Message]("sendDocument", params)
return req.Do(api) return req.Do(api)
} }
@@ -113,7 +113,7 @@ type SendVideoP struct {
ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"`
} }
func (api *Api) SendVideo(params SendVideoP) (Message, error) { func (api *API) SendVideo(params SendVideoP) (Message, error) {
req := NewRequest[Message]("sendVideo", params) req := NewRequest[Message]("sendVideo", params)
return req.Do(api) return req.Do(api)
} }
@@ -144,7 +144,7 @@ type SendAnimationP struct {
ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"`
} }
func (api *Api) SendAnimation(params SendAnimationP) (Message, error) { func (api *API) SendAnimation(params SendAnimationP) (Message, error) {
req := NewRequest[Message]("sendAnimation", params) req := NewRequest[Message]("sendAnimation", params)
return req.Do(api) return req.Do(api)
} }
@@ -170,7 +170,7 @@ type SendVoiceP struct {
ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"`
} }
func (api *Api) SendVoice(params *SendVoiceP) (Message, error) { func (api *API) SendVoice(params *SendVoiceP) (Message, error) {
req := NewRequest[Message]("sendVoice", params) req := NewRequest[Message]("sendVoice", params)
return req.Do(api) return req.Do(api)
} }
@@ -194,7 +194,7 @@ type SendVideoNoteP struct {
ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"`
} }
func (api *Api) SendVideoNote(params SendVideoNoteP) (Message, error) { func (api *API) SendVideoNote(params SendVideoNoteP) (Message, error) {
req := NewRequest[Message]("sendVideoNote", params) req := NewRequest[Message]("sendVideoNote", params)
return req.Do(api) return req.Do(api)
} }
@@ -221,7 +221,7 @@ type SendPaidMediaP struct {
ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"`
} }
func (api *Api) SendPaidMedia(params SendPaidMediaP) (Message, error) { func (api *API) SendPaidMedia(params SendPaidMediaP) (Message, error) {
req := NewRequest[Message]("sendPaidMedia", params) req := NewRequest[Message]("sendPaidMedia", params)
return req.Do(api) return req.Do(api)
} }
@@ -240,7 +240,7 @@ type SendMediaGroupP struct {
ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"`
} }
func (api *Api) SendMediaGroup(params SendMediaGroupP) (Message, error) { func (api *API) SendMediaGroup(params SendMediaGroupP) (Message, error) {
req := NewRequest[Message]("sendMediaGroup", params) req := NewRequest[Message]("sendMediaGroup", params)
return req.Do(api) return req.Do(api)
} }

View File

@@ -6,7 +6,7 @@ type SetMyCommandsP struct {
Language string `json:"language_code,omitempty"` Language string `json:"language_code,omitempty"`
} }
func (api *Api) SetMyCommands(params SetMyCommandsP) (bool, error) { func (api *API) SetMyCommands(params SetMyCommandsP) (bool, error) {
req := NewRequest[bool]("setMyCommands", params) req := NewRequest[bool]("setMyCommands", params)
return req.Do(api) return req.Do(api)
} }
@@ -16,7 +16,7 @@ type DeleteMyCommandsP struct {
Language string `json:"language_code,omitempty"` Language string `json:"language_code,omitempty"`
} }
func (api *Api) DeleteMyCommands(params DeleteMyCommandsP) (bool, error) { func (api *API) DeleteMyCommands(params DeleteMyCommandsP) (bool, error) {
req := NewRequest[bool]("deleteMyCommands", params) req := NewRequest[bool]("deleteMyCommands", params)
return req.Do(api) return req.Do(api)
} }
@@ -26,7 +26,7 @@ type GetMyCommands struct {
Language string `json:"language_code,omitempty"` Language string `json:"language_code,omitempty"`
} }
func (api *Api) GetMyCommands(params GetMyCommands) ([]BotCommand, error) { func (api *API) GetMyCommands(params GetMyCommands) ([]BotCommand, error) {
req := NewRequest[[]BotCommand]("getMyCommands", params) req := NewRequest[[]BotCommand]("getMyCommands", params)
return req.Do(api) return req.Do(api)
} }
@@ -36,7 +36,7 @@ type SetMyName struct {
Language string `json:"language_code,omitempty"` Language string `json:"language_code,omitempty"`
} }
func (api *Api) SetMyName(params SetMyName) (bool, error) { func (api *API) SetMyName(params SetMyName) (bool, error) {
req := NewRequest[bool]("setMyName", params) req := NewRequest[bool]("setMyName", params)
return req.Do(api) return req.Do(api)
} }
@@ -45,7 +45,7 @@ type GetMyName struct {
Language string `json:"language_code,omitempty"` Language string `json:"language_code,omitempty"`
} }
func (api *Api) GetMyName(params GetMyName) (BotName, error) { func (api *API) GetMyName(params GetMyName) (BotName, error) {
req := NewRequest[BotName]("getMyName", params) req := NewRequest[BotName]("getMyName", params)
return req.Do(api) return req.Do(api)
} }
@@ -55,7 +55,7 @@ type SetMyDescription struct {
Language string `json:"language_code,omitempty"` Language string `json:"language_code,omitempty"`
} }
func (api *Api) SetMyDescription(params SetMyDescription) (bool, error) { func (api *API) SetMyDescription(params SetMyDescription) (bool, error) {
req := NewRequest[bool]("setMyDescription", params) req := NewRequest[bool]("setMyDescription", params)
return req.Do(api) return req.Do(api)
} }
@@ -64,7 +64,7 @@ type GetMyDescription struct {
Language string `json:"language_code,omitempty"` Language string `json:"language_code,omitempty"`
} }
func (api *Api) GetMyDescription(params GetMyDescription) (BotDescription, error) { func (api *API) GetMyDescription(params GetMyDescription) (BotDescription, error) {
req := NewRequest[BotDescription]("getMyDescription", params) req := NewRequest[BotDescription]("getMyDescription", params)
return req.Do(api) return req.Do(api)
} }
@@ -74,7 +74,7 @@ type SetMyShortDescription struct {
Language string `json:"language_code,omitempty"` Language string `json:"language_code,omitempty"`
} }
func (api *Api) SetMyShortDescription(params SetMyShortDescription) (bool, error) { func (api *API) SetMyShortDescription(params SetMyShortDescription) (bool, error) {
req := NewRequest[bool]("setMyShortDescription", params) req := NewRequest[bool]("setMyShortDescription", params)
return req.Do(api) return req.Do(api)
} }
@@ -83,7 +83,7 @@ type GetMyShortDescription struct {
Language string `json:"language_code,omitempty"` Language string `json:"language_code,omitempty"`
} }
func (api *Api) GetMyShortDescription(params GetMyShortDescription) (BotShortDescription, error) { func (api *API) GetMyShortDescription(params GetMyShortDescription) (BotShortDescription, error) {
req := NewRequest[BotShortDescription]("getMyShortDescription", params) req := NewRequest[BotShortDescription]("getMyShortDescription", params)
return req.Do(api) return req.Do(api)
} }
@@ -92,11 +92,11 @@ type SetMyProfilePhotoP struct {
Photo InputProfilePhoto `json:"photo"` Photo InputProfilePhoto `json:"photo"`
} }
func (api *Api) SetMyProfilePhoto(params SetMyProfilePhotoP) (bool, error) { func (api *API) SetMyProfilePhoto(params SetMyProfilePhotoP) (bool, error) {
req := NewRequest[bool]("setMyProfilePhoto", params) req := NewRequest[bool]("setMyProfilePhoto", params)
return req.Do(api) return req.Do(api)
} }
func (api *Api) RemoveMyProfilePhoto() (bool, error) { func (api *API) RemoveMyProfilePhoto() (bool, error) {
req := NewRequest[bool]("removeMyProfilePhoto", NoParams) req := NewRequest[bool]("removeMyProfilePhoto", NoParams)
return req.Do(api) return req.Do(api)
} }
@@ -106,7 +106,7 @@ type SetChatMenuButtonP struct {
MenuButton MenuButtonType `json:"menu_button"` MenuButton MenuButtonType `json:"menu_button"`
} }
func (api *Api) SetChatMenuButton(params SetChatMenuButtonP) (bool, error) { func (api *API) SetChatMenuButton(params SetChatMenuButtonP) (bool, error) {
req := NewRequest[bool]("setChatMenuButton", params) req := NewRequest[bool]("setChatMenuButton", params)
return req.Do(api) return req.Do(api)
} }
@@ -115,7 +115,7 @@ type GetChatMenuButtonP struct {
ChatID int `json:"chat_id"` ChatID int `json:"chat_id"`
} }
func (api *Api) GetChatMenuButton(params GetChatMenuButtonP) (BaseMenuButton, error) { func (api *API) GetChatMenuButton(params GetChatMenuButtonP) (BaseMenuButton, error) {
req := NewRequest[BaseMenuButton]("getChatMenuButton", params) req := NewRequest[BaseMenuButton]("getChatMenuButton", params)
return req.Do(api) return req.Do(api)
} }
@@ -125,7 +125,7 @@ type SetMyDefaultAdministratorRightsP struct {
ForChannels bool `json:"for_channels"` ForChannels bool `json:"for_channels"`
} }
func (api *Api) SetMyDefaultAdministratorRights(params SetMyDefaultAdministratorRightsP) (bool, error) { func (api *API) SetMyDefaultAdministratorRights(params SetMyDefaultAdministratorRightsP) (bool, error) {
req := NewRequest[bool]("setMyDefaultAdministratorRights", params) req := NewRequest[bool]("setMyDefaultAdministratorRights", params)
return req.Do(api) return req.Do(api)
} }
@@ -134,12 +134,12 @@ type GetMyDefaultAdministratorRightsP struct {
ForChannels bool `json:"for_channels"` ForChannels bool `json:"for_channels"`
} }
func (api *Api) GetMyDefaultAdministratorRights(params GetMyDefaultAdministratorRightsP) (ChatAdministratorRights, error) { func (api *API) GetMyDefaultAdministratorRights(params GetMyDefaultAdministratorRightsP) (ChatAdministratorRights, error) {
req := NewRequest[ChatAdministratorRights]("getMyDefaultAdministratorRights", params) req := NewRequest[ChatAdministratorRights]("getMyDefaultAdministratorRights", params)
return req.Do(api) return req.Do(api)
} }
func (api *Api) GetAvailableGifts() (Gifts, error) { func (api *API) GetAvailableGifts() (Gifts, error) {
req := NewRequest[Gifts]("getAvailableGifts", NoParams) req := NewRequest[Gifts]("getAvailableGifts", NoParams)
return req.Do(api) return req.Do(api)
} }
@@ -154,7 +154,7 @@ type SendGiftP struct {
TextEntities []MessageEntity `json:"text_entities,omitempty"` TextEntities []MessageEntity `json:"text_entities,omitempty"`
} }
func (api *Api) SendGift(params SendGiftP) (bool, error) { func (api *API) SendGift(params SendGiftP) (bool, error) {
req := NewRequest[bool]("sendGift", params) req := NewRequest[bool]("sendGift", params)
return req.Do(api) return req.Do(api)
} }
@@ -168,7 +168,7 @@ type GiftPremiumSubscriptionP struct {
TextEntities []MessageEntity `json:"text_entities,omitempty"` TextEntities []MessageEntity `json:"text_entities,omitempty"`
} }
func (api *Api) GiftPremiumSubscription(params GiftPremiumSubscriptionP) (bool, error) { func (api *API) GiftPremiumSubscription(params GiftPremiumSubscriptionP) (bool, error) {
req := NewRequest[bool]("giftPremiumSubscription", params) req := NewRequest[bool]("giftPremiumSubscription", params)
return req.Do(api) return req.Do(api)
} }

View File

@@ -9,7 +9,7 @@ type BotCommandScopeType string
const ( const (
BotCommandScopeDefaultType BotCommandScopeType = "default" BotCommandScopeDefaultType BotCommandScopeType = "default"
BotCommandScopePrivateType BotCommandScopeType = "all_private_chats" BotCommandScopePrivateType BotCommandScopeType = "all_private_chats"
BotCommandScopeGroupType BotCommandScopeType = "all_groups_chats" BotCommandScopeGroupType BotCommandScopeType = "all_group_chats"
BotCommandScopeAllChatAdministratorsType BotCommandScopeType = "all_chat_administrators" BotCommandScopeAllChatAdministratorsType BotCommandScopeType = "all_chat_administrators"
BotCommandScopeChatType BotCommandScopeType = "chat" BotCommandScopeChatType BotCommandScopeType = "chat"
BotCommandScopeChatAdministratorsType BotCommandScopeType = "chat_administrators" BotCommandScopeChatAdministratorsType BotCommandScopeType = "chat_administrators"

View File

@@ -5,7 +5,7 @@ type VerifyUserP struct {
CustomDescription string `json:"custom_description,omitempty"` CustomDescription string `json:"custom_description,omitempty"`
} }
func (api *Api) VerifyUser(params VerifyUserP) (bool, error) { func (api *API) VerifyUser(params VerifyUserP) (bool, error) {
req := NewRequest[bool]("verifyUser", params) req := NewRequest[bool]("verifyUser", params)
return req.Do(api) return req.Do(api)
} }
@@ -15,7 +15,7 @@ type VerifyChatP struct {
CustomDescription string `json:"custom_description,omitempty"` CustomDescription string `json:"custom_description,omitempty"`
} }
func (api *Api) VerifyChat(params VerifyChatP) (bool, error) { func (api *API) VerifyChat(params VerifyChatP) (bool, error) {
req := NewRequest[bool]("verifyChat", params) req := NewRequest[bool]("verifyChat", params)
return req.Do(api) return req.Do(api)
} }
@@ -24,7 +24,7 @@ type RemoveUserVerificationP struct {
UserID int `json:"user_id"` UserID int `json:"user_id"`
} }
func (api *Api) RemoveUserVerification(params RemoveUserVerificationP) (bool, error) { func (api *API) RemoveUserVerification(params RemoveUserVerificationP) (bool, error) {
req := NewRequest[bool]("removeUserVerification", params) req := NewRequest[bool]("removeUserVerification", params)
return req.Do(api) return req.Do(api)
} }
@@ -33,7 +33,7 @@ type RemoveChatVerificationP struct {
ChatID int `json:"chat_id"` ChatID int `json:"chat_id"`
} }
func (api *Api) RemoveChatVerification(params RemoveChatVerificationP) (bool, error) { func (api *API) RemoveChatVerification(params RemoveChatVerificationP) (bool, error) {
req := NewRequest[bool]("removeChatVerification", params) req := NewRequest[bool]("removeChatVerification", params)
return req.Do(api) return req.Do(api)
} }
@@ -44,7 +44,7 @@ type ReadBusinessMessageP struct {
MessageID int `json:"message_id"` MessageID int `json:"message_id"`
} }
func (api *Api) ReadBusinessMessage(params ReadBusinessMessageP) (bool, error) { func (api *API) ReadBusinessMessage(params ReadBusinessMessageP) (bool, error) {
req := NewRequest[bool]("readBusinessMessage", params) req := NewRequest[bool]("readBusinessMessage", params)
return req.Do(api) return req.Do(api)
} }
@@ -54,7 +54,7 @@ type DeleteBusinessMessageP struct {
MessageIDs []int `json:"message_ids"` MessageIDs []int `json:"message_ids"`
} }
func (api *Api) DeleteBusinessMessage(params DeleteBusinessMessageP) (bool, error) { func (api *API) DeleteBusinessMessage(params DeleteBusinessMessageP) (bool, error) {
req := NewRequest[bool]("deleteBusinessMessage", params) req := NewRequest[bool]("deleteBusinessMessage", params)
return req.Do(api) return req.Do(api)
} }
@@ -65,7 +65,7 @@ type SetBusinessAccountNameP struct {
LastName string `json:"last_name,omitempty"` LastName string `json:"last_name,omitempty"`
} }
func (api *Api) SetBusinessAccountName(params SetBusinessAccountNameP) (bool, error) { func (api *API) SetBusinessAccountName(params SetBusinessAccountNameP) (bool, error) {
req := NewRequest[bool]("setBusinessAccountName", params) req := NewRequest[bool]("setBusinessAccountName", params)
return req.Do(api) return req.Do(api)
} }
@@ -75,7 +75,7 @@ type SetBusinessAccountUsernameP struct {
Username string `json:"username,omitempty"` Username string `json:"username,omitempty"`
} }
func (api *Api) SetBusinessAccountUsername(params SetBusinessAccountUsernameP) (bool, error) { func (api *API) SetBusinessAccountUsername(params SetBusinessAccountUsernameP) (bool, error) {
req := NewRequest[bool]("setBusinessAccountUsername", params) req := NewRequest[bool]("setBusinessAccountUsername", params)
return req.Do(api) return req.Do(api)
} }
@@ -85,7 +85,7 @@ type SetBusinessAccountBioP struct {
Bio string `json:"bio,omitempty"` Bio string `json:"bio,omitempty"`
} }
func (api *Api) SetBusinessAccountBio(params SetBusinessAccountBioP) (bool, error) { func (api *API) SetBusinessAccountBio(params SetBusinessAccountBioP) (bool, error) {
req := NewRequest[bool]("setBusinessAccountBio", params) req := NewRequest[bool]("setBusinessAccountBio", params)
return req.Do(api) return req.Do(api)
} }
@@ -96,7 +96,7 @@ type SetBusinessAccountProfilePhoto struct {
IsPublic bool `json:"is_public,omitempty"` IsPublic bool `json:"is_public,omitempty"`
} }
func (api *Api) SetBusinessAccountProfilePhoto(params SetBusinessAccountProfilePhoto) (bool, error) { func (api *API) SetBusinessAccountProfilePhoto(params SetBusinessAccountProfilePhoto) (bool, error) {
req := NewRequest[bool]("setBusinessAccountProfilePhoto", params) req := NewRequest[bool]("setBusinessAccountProfilePhoto", params)
return req.Do(api) return req.Do(api)
} }
@@ -106,7 +106,7 @@ type RemoveBusinessAccountProfilePhotoP struct {
IsPublic bool `json:"is_public,omitempty"` IsPublic bool `json:"is_public,omitempty"`
} }
func (api *Api) RemoveBusinessAccountProfilePhoto(params RemoveBusinessAccountProfilePhotoP) (bool, error) { func (api *API) RemoveBusinessAccountProfilePhoto(params RemoveBusinessAccountProfilePhotoP) (bool, error) {
req := NewRequest[bool]("removeBusinessAccountProfilePhoto", params) req := NewRequest[bool]("removeBusinessAccountProfilePhoto", params)
return req.Do(api) return req.Do(api)
} }
@@ -117,7 +117,7 @@ type SetBusinessAccountGiftSettingsP struct {
AcceptedGiftTypes AcceptedGiftTypes `json:"accepted_gift_types"` AcceptedGiftTypes AcceptedGiftTypes `json:"accepted_gift_types"`
} }
func (api *Api) SetBusinessAccountGiftSettings(params SetBusinessAccountGiftSettingsP) (bool, error) { func (api *API) SetBusinessAccountGiftSettings(params SetBusinessAccountGiftSettingsP) (bool, error) {
req := NewRequest[bool]("setBusinessAccountGiftSettings", params) req := NewRequest[bool]("setBusinessAccountGiftSettings", params)
return req.Do(api) return req.Do(api)
} }
@@ -126,7 +126,7 @@ type GetBusinessAccountStarBalanceP struct {
BusinessConnectionID string `json:"business_connection_id"` BusinessConnectionID string `json:"business_connection_id"`
} }
func (api *Api) GetBusinessAccountStarBalance(params GetBusinessAccountStarBalanceP) (StarAmount, error) { func (api *API) GetBusinessAccountStarBalance(params GetBusinessAccountStarBalanceP) (StarAmount, error) {
req := NewRequest[StarAmount]("getBusinessAccountGiftSettings", params) req := NewRequest[StarAmount]("getBusinessAccountGiftSettings", params)
return req.Do(api) return req.Do(api)
} }
@@ -136,7 +136,7 @@ type TransferBusinessAccountStartP struct {
StarCount int `json:"star_count"` StarCount int `json:"star_count"`
} }
func (api *Api) TransferBusinessAccountStart(params TransferBusinessAccountStartP) (bool, error) { func (api *API) TransferBusinessAccountStart(params TransferBusinessAccountStartP) (bool, error) {
req := NewRequest[bool]("transferBusinessAccountStart", params) req := NewRequest[bool]("transferBusinessAccountStart", params)
return req.Do(api) return req.Do(api)
} }
@@ -155,7 +155,7 @@ type GetBusinessAccountGiftsP struct {
Limit int `json:"limit,omitempty"` Limit int `json:"limit,omitempty"`
} }
func (api *Api) GetBusinessAccountGifts(params GetBusinessAccountGiftsP) (OwnedGifts, error) { func (api *API) GetBusinessAccountGifts(params GetBusinessAccountGiftsP) (OwnedGifts, error) {
req := NewRequest[OwnedGifts]("getBusinessAccountGifts", params) req := NewRequest[OwnedGifts]("getBusinessAccountGifts", params)
return req.Do(api) return req.Do(api)
} }
@@ -165,7 +165,7 @@ type ConvertGiftToStarsP struct {
OwnedGiftID string `json:"owned_gift_id"` OwnedGiftID string `json:"owned_gift_id"`
} }
func (api *Api) ConvertGiftToStars(params ConvertGiftToStarsP) (bool, error) { func (api *API) ConvertGiftToStars(params ConvertGiftToStarsP) (bool, error) {
req := NewRequest[bool]("convertGiftToStars", params) req := NewRequest[bool]("convertGiftToStars", params)
return req.Do(api) return req.Do(api)
} }
@@ -177,7 +177,7 @@ type UpgradeGiftP struct {
StarCount int `json:"star_count,omitempty"` StarCount int `json:"star_count,omitempty"`
} }
func (api *Api) UpgradeGift(params UpgradeGiftP) (bool, error) { func (api *API) UpgradeGift(params UpgradeGiftP) (bool, error) {
req := NewRequest[bool]("upgradeGift", params) req := NewRequest[bool]("upgradeGift", params)
return req.Do(api) return req.Do(api)
} }
@@ -189,7 +189,7 @@ type TransferGiftP struct {
StarCount int `json:"star_count,omitempty"` StarCount int `json:"star_count,omitempty"`
} }
func (api *Api) TransferGift(params TransferGiftP) (bool, error) { func (api *API) TransferGift(params TransferGiftP) (bool, error) {
req := NewRequest[bool]("transferGift", params) req := NewRequest[bool]("transferGift", params)
return req.Do(api) return req.Do(api)
} }
@@ -208,11 +208,11 @@ type PostStoryP struct {
ProtectContent bool `json:"protect_content,omitempty"` ProtectContent bool `json:"protect_content,omitempty"`
} }
func (api *Api) PostStoryPhoto(params PostStoryP) (Story, error) { func (api *API) PostStoryPhoto(params PostStoryP) (Story, error) {
req := NewRequest[Story]("postStory", params) req := NewRequest[Story]("postStory", params)
return req.Do(api) return req.Do(api)
} }
func (api *Api) PostStoryVideo(params PostStoryP) (Story, error) { func (api *API) PostStoryVideo(params PostStoryP) (Story, error) {
req := NewRequest[Story]("postStory", params) req := NewRequest[Story]("postStory", params)
return req.Do(api) return req.Do(api)
} }
@@ -226,7 +226,7 @@ type RepostStoryP struct {
ProtectContent bool `json:"protect_content,omitempty"` ProtectContent bool `json:"protect_content,omitempty"`
} }
func (api *Api) RepostStory(params RepostStoryP) (Story, error) { func (api *API) RepostStory(params RepostStoryP) (Story, error) {
req := NewRequest[Story]("repostStory", params) req := NewRequest[Story]("repostStory", params)
return req.Do(api) return req.Do(api)
} }
@@ -242,7 +242,7 @@ type EditStoryP struct {
Areas []StoryArea `json:"areas,omitempty"` Areas []StoryArea `json:"areas,omitempty"`
} }
func (api *Api) EditStory(params EditStoryP) (Story, error) { func (api *API) EditStory(params EditStoryP) (Story, error) {
req := NewRequest[Story]("editStory", params) req := NewRequest[Story]("editStory", params)
return req.Do(api) return req.Do(api)
} }
@@ -252,7 +252,7 @@ type DeleteStoryP struct {
StoryID int `json:"story_id"` StoryID int `json:"story_id"`
} }
func (api *Api) DeleteStory(params DeleteStoryP) (bool, error) { func (api *API) DeleteStory(params DeleteStoryP) (bool, error) {
req := NewRequest[bool]("deleteStory", params) req := NewRequest[bool]("deleteStory", params)
return req.Do(api) return req.Do(api)
} }

View File

@@ -7,7 +7,7 @@ type BanChatMemberP struct {
RevokeMessages bool `json:"revoke_messages,omitempty"` RevokeMessages bool `json:"revoke_messages,omitempty"`
} }
func (api *Api) BanChatMember(params BanChatMemberP) (bool, error) { func (api *API) BanChatMember(params BanChatMemberP) (bool, error) {
req := NewRequest[bool]("banChatMember", params) req := NewRequest[bool]("banChatMember", params)
return req.Do(api) return req.Do(api)
} }
@@ -18,7 +18,7 @@ type UnbanChatMemberP struct {
OnlyIfBanned bool `json:"only_if_banned"` OnlyIfBanned bool `json:"only_if_banned"`
} }
func (api *Api) UnbanChatMember(params UnbanChatMemberP) (bool, error) { func (api *API) UnbanChatMember(params UnbanChatMemberP) (bool, error) {
req := NewRequest[bool]("unbanChatMember", params) req := NewRequest[bool]("unbanChatMember", params)
return req.Do(api) return req.Do(api)
} }
@@ -31,7 +31,7 @@ type RestrictChatMemberP struct {
UntilDate int `json:"until_date,omitempty"` UntilDate int `json:"until_date,omitempty"`
} }
func (api *Api) RestrictChatMember(params RestrictChatMemberP) (bool, error) { func (api *API) RestrictChatMember(params RestrictChatMemberP) (bool, error) {
req := NewRequest[bool]("restrictChatMember", params) req := NewRequest[bool]("restrictChatMember", params)
return req.Do(api) return req.Do(api)
} }
@@ -58,7 +58,7 @@ type PromoteChatMember struct {
CanManageDirectMessages bool `json:"can_manage_direct_messages,omitempty"` CanManageDirectMessages bool `json:"can_manage_direct_messages,omitempty"`
} }
func (api *Api) PromoteChatMember(params PromoteChatMember) (bool, error) { func (api *API) PromoteChatMember(params PromoteChatMember) (bool, error) {
req := NewRequest[bool]("promoteChatMember", params) req := NewRequest[bool]("promoteChatMember", params)
return req.Do(api) return req.Do(api)
} }
@@ -69,7 +69,7 @@ type SetChatAdministratorCustomTitleP struct {
CustomTitle string `json:"custom_title"` CustomTitle string `json:"custom_title"`
} }
func (api *Api) SetChatAdministratorCustomTitle(params SetChatAdministratorCustomTitleP) (bool, error) { func (api *API) SetChatAdministratorCustomTitle(params SetChatAdministratorCustomTitleP) (bool, error) {
req := NewRequest[bool]("setChatAdministratorCustomTitle", params) req := NewRequest[bool]("setChatAdministratorCustomTitle", params)
return req.Do(api) return req.Do(api)
} }
@@ -79,7 +79,7 @@ type BanChatSenderChatP struct {
SenderChatID int `json:"sender_chat_id"` SenderChatID int `json:"sender_chat_id"`
} }
func (api *Api) BanChatSenderChat(params BanChatSenderChatP) (bool, error) { func (api *API) BanChatSenderChat(params BanChatSenderChatP) (bool, error) {
req := NewRequest[bool]("banChatSenderChat", params) req := NewRequest[bool]("banChatSenderChat", params)
return req.Do(api) return req.Do(api)
} }
@@ -89,7 +89,7 @@ type UnbanChatSenderChatP struct {
SenderChatID int `json:"sender_chat_id"` SenderChatID int `json:"sender_chat_id"`
} }
func (api *Api) UnbanChatSenderChat(params BanChatSenderChatP) (bool, error) { func (api *API) UnbanChatSenderChat(params BanChatSenderChatP) (bool, error) {
req := NewRequest[bool]("unbanChatSenderChat", params) req := NewRequest[bool]("unbanChatSenderChat", params)
return req.Do(api) return req.Do(api)
} }
@@ -100,7 +100,7 @@ type SetChatPermissionsP struct {
UseIndependentChatPermissions bool `json:"use_independent_chat_permissions,omitempty"` UseIndependentChatPermissions bool `json:"use_independent_chat_permissions,omitempty"`
} }
func (api *Api) SetChatPermissions(params SetChatPermissionsP) (bool, error) { func (api *API) SetChatPermissions(params SetChatPermissionsP) (bool, error) {
req := NewRequest[bool]("setChatPermissions", params) req := NewRequest[bool]("setChatPermissions", params)
return req.Do(api) return req.Do(api)
} }
@@ -109,7 +109,7 @@ type ExportChatInviteLinkP struct {
ChatID int `json:"chat_id"` ChatID int `json:"chat_id"`
} }
func (api *Api) ExportChatInviteLink(params ExportChatInviteLinkP) (string, error) { func (api *API) ExportChatInviteLink(params ExportChatInviteLinkP) (string, error) {
req := NewRequest[string]("exportChatInviteLink", params) req := NewRequest[string]("exportChatInviteLink", params)
return req.Do(api) return req.Do(api)
} }
@@ -122,7 +122,7 @@ type CreateChatInviteLinkP struct {
CreatesJoinRequest int `json:"creates_join_request,omitempty"` CreatesJoinRequest int `json:"creates_join_request,omitempty"`
} }
func (api *Api) CreateChatInviteLink(params CreateChatInviteLinkP) (ChatInviteLink, error) { func (api *API) CreateChatInviteLink(params CreateChatInviteLinkP) (ChatInviteLink, error) {
req := NewRequest[ChatInviteLink]("createChatInviteLink", params) req := NewRequest[ChatInviteLink]("createChatInviteLink", params)
return req.Do(api) return req.Do(api)
} }
@@ -137,7 +137,7 @@ type EditChatInviteLinkP struct {
CreatesJoinRequest int `json:"creates_join_request,omitempty"` CreatesJoinRequest int `json:"creates_join_request,omitempty"`
} }
func (api *Api) EditChatInviteLink(params EditChatInviteLinkP) (ChatInviteLink, error) { func (api *API) EditChatInviteLink(params EditChatInviteLinkP) (ChatInviteLink, error) {
req := NewRequest[ChatInviteLink]("editChatInviteLink", params) req := NewRequest[ChatInviteLink]("editChatInviteLink", params)
return req.Do(api) return req.Do(api)
} }
@@ -149,7 +149,7 @@ type CreateChatSubscriptionInviteLinkP struct {
SubscriptionPrice int `json:"subscription_price,omitempty"` SubscriptionPrice int `json:"subscription_price,omitempty"`
} }
func (api *Api) CreateChatSubscriptionInviteLink(params CreateChatSubscriptionInviteLinkP) (ChatInviteLink, error) { func (api *API) CreateChatSubscriptionInviteLink(params CreateChatSubscriptionInviteLinkP) (ChatInviteLink, error) {
req := NewRequest[ChatInviteLink]("createChatSubscriptionInviteLink", params) req := NewRequest[ChatInviteLink]("createChatSubscriptionInviteLink", params)
return req.Do(api) return req.Do(api)
} }
@@ -160,7 +160,7 @@ type EditChatSubscriptionInviteLinkP struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
} }
func (api *Api) EditChatSubscriptionInviteLink(params EditChatSubscriptionInviteLinkP) (ChatInviteLink, error) { func (api *API) EditChatSubscriptionInviteLink(params EditChatSubscriptionInviteLinkP) (ChatInviteLink, error) {
req := NewRequest[ChatInviteLink]("editChatSubscriptionInviteLink", params) req := NewRequest[ChatInviteLink]("editChatSubscriptionInviteLink", params)
return req.Do(api) return req.Do(api)
} }
@@ -170,7 +170,7 @@ type RevokeChatInviteLinkP struct {
InviteLink string `json:"invite_link"` InviteLink string `json:"invite_link"`
} }
func (api *Api) RevokeChatInviteLink(params RevokeChatInviteLinkP) (ChatInviteLink, error) { func (api *API) RevokeChatInviteLink(params RevokeChatInviteLinkP) (ChatInviteLink, error) {
req := NewRequest[ChatInviteLink]("revokeChatInviteLink", params) req := NewRequest[ChatInviteLink]("revokeChatInviteLink", params)
return req.Do(api) return req.Do(api)
} }
@@ -180,7 +180,7 @@ type ApproveChatJoinRequestP struct {
UserID int `json:"user_id"` UserID int `json:"user_id"`
} }
func (api *Api) ApproveChatJoinRequest(params ApproveChatJoinRequestP) (bool, error) { func (api *API) ApproveChatJoinRequest(params ApproveChatJoinRequestP) (bool, error) {
req := NewRequest[bool]("approveChatJoinRequest", params) req := NewRequest[bool]("approveChatJoinRequest", params)
return req.Do(api) return req.Do(api)
} }
@@ -190,12 +190,12 @@ type DeclineChatJoinRequestP struct {
UserID int `json:"user_id"` UserID int `json:"user_id"`
} }
func (api *Api) DeclineChatJoinRequest(params DeclineChatJoinRequestP) (bool, error) { func (api *API) DeclineChatJoinRequest(params DeclineChatJoinRequestP) (bool, error) {
req := NewRequest[bool]("declineChatJoinRequest", params) req := NewRequest[bool]("declineChatJoinRequest", params)
return req.Do(api) return req.Do(api)
} }
func (api *Api) SetChatPhoto() { func (api *API) SetChatPhoto() {
uploader := NewUploader(api) uploader := NewUploader(api)
defer uploader.Close() defer uploader.Close()
} }
@@ -204,7 +204,7 @@ type DeleteChatPhotoP struct {
ChatID int `json:"chat_id"` ChatID int `json:"chat_id"`
} }
func (api *Api) DeleteChatPhoto(params DeleteChatPhotoP) (bool, error) { func (api *API) DeleteChatPhoto(params DeleteChatPhotoP) (bool, error) {
req := NewRequest[bool]("deleteChatPhoto", params) req := NewRequest[bool]("deleteChatPhoto", params)
return req.Do(api) return req.Do(api)
} }
@@ -214,7 +214,7 @@ type SetChatTitleP struct {
Title string `json:"title"` Title string `json:"title"`
} }
func (api *Api) SetChatTitle(params SetChatTitleP) (bool, error) { func (api *API) SetChatTitle(params SetChatTitleP) (bool, error) {
req := NewRequest[bool]("setChatTitle", params) req := NewRequest[bool]("setChatTitle", params)
return req.Do(api) return req.Do(api)
} }
@@ -224,7 +224,7 @@ type SetChatDescriptionP struct {
Description string `json:"description"` Description string `json:"description"`
} }
func (api *Api) SetChatDescription(params SetChatDescriptionP) (bool, error) { func (api *API) SetChatDescription(params SetChatDescriptionP) (bool, error) {
req := NewRequest[bool]("setChatDescription", params) req := NewRequest[bool]("setChatDescription", params)
return req.Do(api) return req.Do(api)
} }
@@ -236,7 +236,7 @@ type PinChatMessageP struct {
DisableNotification bool `json:"disable_notification,omitempty"` DisableNotification bool `json:"disable_notification,omitempty"`
} }
func (api *Api) PinChatMessage(params PinChatMessageP) (bool, error) { func (api *API) PinChatMessage(params PinChatMessageP) (bool, error) {
req := NewRequest[bool]("pinChatMessage", params) req := NewRequest[bool]("pinChatMessage", params)
return req.Do(api) return req.Do(api)
} }
@@ -247,7 +247,7 @@ type UnpinChatMessageP struct {
MessageID int `json:"message_id"` MessageID int `json:"message_id"`
} }
func (api *Api) UnpinChatMessage(params UnpinChatMessageP) (bool, error) { func (api *API) UnpinChatMessage(params UnpinChatMessageP) (bool, error) {
req := NewRequest[bool]("unpinChatMessage", params) req := NewRequest[bool]("unpinChatMessage", params)
return req.Do(api) return req.Do(api)
} }
@@ -256,7 +256,7 @@ type UnpinAllChatMessagesP struct {
ChatID int `json:"chat_id"` ChatID int `json:"chat_id"`
} }
func (api *Api) UnpinAllChatMessages(params UnpinAllChatMessagesP) (bool, error) { func (api *API) UnpinAllChatMessages(params UnpinAllChatMessagesP) (bool, error) {
req := NewRequest[bool]("unpinAllChatMessages", params) req := NewRequest[bool]("unpinAllChatMessages", params)
return req.Do(api) return req.Do(api)
} }
@@ -265,7 +265,7 @@ type LeaveChatP struct {
ChatID int `json:"chat_id"` ChatID int `json:"chat_id"`
} }
func (api *Api) LeaveChat(params LeaveChatP) (bool, error) { func (api *API) LeaveChat(params LeaveChatP) (bool, error) {
req := NewRequest[bool]("leaveChatP", params) req := NewRequest[bool]("leaveChatP", params)
return req.Do(api) return req.Do(api)
} }
@@ -274,7 +274,7 @@ type GetChatP struct {
ChatID int `json:"chat_id"` ChatID int `json:"chat_id"`
} }
func (api *Api) GetChatP(params GetChatP) (ChatFullInfo, error) { func (api *API) GetChatP(params GetChatP) (ChatFullInfo, error) {
req := NewRequest[ChatFullInfo]("getChatP", params) req := NewRequest[ChatFullInfo]("getChatP", params)
return req.Do(api) return req.Do(api)
} }
@@ -283,7 +283,7 @@ type GetChatAdministratorsP struct {
ChatID int `json:"chat_id"` ChatID int `json:"chat_id"`
} }
func (api *Api) GetChatAdministrators(params GetChatAdministratorsP) ([]ChatMember, error) { func (api *API) GetChatAdministrators(params GetChatAdministratorsP) ([]ChatMember, error) {
req := NewRequest[[]ChatMember]("getChatAdministrators", params) req := NewRequest[[]ChatMember]("getChatAdministrators", params)
return req.Do(api) return req.Do(api)
} }
@@ -292,7 +292,7 @@ type GetChatMembersCountP struct {
ChatID int `json:"chat_id"` ChatID int `json:"chat_id"`
} }
func (api *Api) GetChatMemberCount(params GetChatMembersCountP) (int, error) { func (api *API) GetChatMemberCount(params GetChatMembersCountP) (int, error) {
req := NewRequest[int]("getChatMemberCount", params) req := NewRequest[int]("getChatMemberCount", params)
return req.Do(api) return req.Do(api)
} }
@@ -302,7 +302,7 @@ type GetChatMemberP struct {
UserID int `json:"user_id"` UserID int `json:"user_id"`
} }
func (api *Api) GetChatMember(params GetChatMemberP) (ChatMember, error) { func (api *API) GetChatMember(params GetChatMemberP) (ChatMember, error) {
req := NewRequest[ChatMember]("getChatMember", params) req := NewRequest[ChatMember]("getChatMember", params)
return req.Do(api) return req.Do(api)
} }
@@ -312,7 +312,7 @@ type SetChatStickerSetP struct {
StickerSetName string `json:"sticker_set_name"` StickerSetName string `json:"sticker_set_name"`
} }
func (api *Api) SetChatStickerSet(params SetChatStickerSetP) (bool, error) { func (api *API) SetChatStickerSet(params SetChatStickerSetP) (bool, error) {
req := NewRequest[bool]("setChatStickerSet", params) req := NewRequest[bool]("setChatStickerSet", params)
return req.Do(api) return req.Do(api)
} }
@@ -321,7 +321,7 @@ type DeleteChatStickerSetP struct {
ChatID int `json:"chat_id"` ChatID int `json:"chat_id"`
} }
func (api *Api) DeleteChatStickerSet(params DeleteChatStickerSetP) (bool, error) { func (api *API) DeleteChatStickerSet(params DeleteChatStickerSetP) (bool, error) {
req := NewRequest[bool]("deleteChatStickerSet", params) req := NewRequest[bool]("deleteChatStickerSet", params)
return req.Do(api) return req.Do(api)
} }
@@ -331,7 +331,7 @@ type GetUserChatBoostsP struct {
UserID int `json:"user_id"` UserID int `json:"user_id"`
} }
func (api *Api) GetUserChatBoosts(params GetUserChatBoostsP) (UserChatBoosts, error) { func (api *API) GetUserChatBoosts(params GetUserChatBoostsP) (UserChatBoosts, error) {
req := NewRequest[UserChatBoosts]("getUserChatBoosts", params) req := NewRequest[UserChatBoosts]("getUserChatBoosts", params)
return req.Do(api) return req.Do(api)
} }
@@ -350,7 +350,7 @@ type GetChatGiftsP struct {
Limit int `json:"limit,omitempty"` Limit int `json:"limit,omitempty"`
} }
func (api *Api) GetChatGifts(params GetChatGiftsP) (OwnedGifts, error) { func (api *API) GetChatGifts(params GetChatGiftsP) (OwnedGifts, error) {
req := NewRequest[OwnedGifts]("getChatGifts", params) req := NewRequest[OwnedGifts]("getChatGifts", params)
return req.Do(api) return req.Do(api)
} }

View File

@@ -5,7 +5,7 @@ type BaseForumTopicP struct {
MessageThreadID int `json:"message_thread_id"` MessageThreadID int `json:"message_thread_id"`
} }
func (api *Api) GetForumTopicIconSet() ([]Sticker, error) { func (api *API) GetForumTopicIconSet() ([]Sticker, error) {
req := NewRequest[[]Sticker]("getForumTopicIconSet", NoParams) req := NewRequest[[]Sticker]("getForumTopicIconSet", NoParams)
return req.Do(api) return req.Do(api)
} }
@@ -17,7 +17,7 @@ type CreateForumTopicP struct {
IconCustomEmojiID string `json:"icon_custom_emoji_id"` IconCustomEmojiID string `json:"icon_custom_emoji_id"`
} }
func (api *Api) CreateForumTopic(params CreateForumTopicP) (ForumTopic, error) { func (api *API) CreateForumTopic(params CreateForumTopicP) (ForumTopic, error) {
req := NewRequest[ForumTopic]("createForumTopic", params) req := NewRequest[ForumTopic]("createForumTopic", params)
return req.Do(api) return req.Do(api)
} }
@@ -28,24 +28,24 @@ type EditForumTopicP struct {
IconCustomEmojiID string `json:"icon_custom_emoji_id"` IconCustomEmojiID string `json:"icon_custom_emoji_id"`
} }
func (api *Api) EditForumTopic(params EditForumTopicP) (bool, error) { func (api *API) EditForumTopic(params EditForumTopicP) (bool, error) {
req := NewRequest[bool]("editForumTopic", params) req := NewRequest[bool]("editForumTopic", params)
return req.Do(api) return req.Do(api)
} }
func (api *Api) CloseForumTopic(params BaseForumTopicP) (bool, error) { func (api *API) CloseForumTopic(params BaseForumTopicP) (bool, error) {
req := NewRequest[bool]("closeForumTopic", params) req := NewRequest[bool]("closeForumTopic", params)
return req.Do(api) return req.Do(api)
} }
func (api *Api) ReopenForumTopic(params BaseForumTopicP) (bool, error) { func (api *API) ReopenForumTopic(params BaseForumTopicP) (bool, error) {
req := NewRequest[bool]("reopenForumTopic", params) req := NewRequest[bool]("reopenForumTopic", params)
return req.Do(api) return req.Do(api)
} }
func (api *Api) DeleteForumTopic(params BaseForumTopicP) (bool, error) { func (api *API) DeleteForumTopic(params BaseForumTopicP) (bool, error) {
req := NewRequest[bool]("deleteForumTopic", params) req := NewRequest[bool]("deleteForumTopic", params)
return req.Do(api) return req.Do(api)
} }
func (api *Api) UnpinAllForumTopicMessages(params BaseForumTopicP) (bool, error) { func (api *API) UnpinAllForumTopicMessages(params BaseForumTopicP) (bool, error) {
req := NewRequest[bool]("unpinAllForumTopicMessages", params) req := NewRequest[bool]("unpinAllForumTopicMessages", params)
return req.Do(api) return req.Do(api)
} }
@@ -59,28 +59,28 @@ type EditGeneralForumTopicP struct {
Name string `json:"name"` Name string `json:"name"`
} }
func (api *Api) EditGeneralForumTopic(params EditGeneralForumTopicP) (bool, error) { func (api *API) EditGeneralForumTopic(params EditGeneralForumTopicP) (bool, error) {
req := NewRequest[bool]("editGeneralForumTopic", params) req := NewRequest[bool]("editGeneralForumTopic", params)
return req.Do(api) return req.Do(api)
} }
func (api *Api) CloseGeneralForumTopic(params BaseGeneralForumTopicP) (bool, error) { func (api *API) CloseGeneralForumTopic(params BaseGeneralForumTopicP) (bool, error) {
req := NewRequest[bool]("closeGeneralForumTopic", params) req := NewRequest[bool]("closeGeneralForumTopic", params)
return req.Do(api) return req.Do(api)
} }
func (api *Api) ReopenGeneralForumTopic(params BaseGeneralForumTopicP) (bool, error) { func (api *API) ReopenGeneralForumTopic(params BaseGeneralForumTopicP) (bool, error) {
req := NewRequest[bool]("reopenGeneralForumTopic", params) req := NewRequest[bool]("reopenGeneralForumTopic", params)
return req.Do(api) return req.Do(api)
} }
func (api *Api) HideGeneralForumTopic(params BaseGeneralForumTopicP) (bool, error) { func (api *API) HideGeneralForumTopic(params BaseGeneralForumTopicP) (bool, error) {
req := NewRequest[bool]("hideGeneralForumTopic", params) req := NewRequest[bool]("hideGeneralForumTopic", params)
return req.Do(api) return req.Do(api)
} }
func (api *Api) UnhideGeneralForumTopic(params BaseGeneralForumTopicP) (bool, error) { func (api *API) UnhideGeneralForumTopic(params BaseGeneralForumTopicP) (bool, error) {
req := NewRequest[bool]("unhideGeneralForumTopic", params) req := NewRequest[bool]("unhideGeneralForumTopic", params)
return req.Do(api) return req.Do(api)
} }
func (api *Api) UnpinAllGeneralForumTopicMessages(params BaseGeneralForumTopicP) (bool, error) { func (api *API) UnpinAllGeneralForumTopicMessages(params BaseGeneralForumTopicP) (bool, error) {
req := NewRequest[bool]("unpinAllGeneralForumTopicMessages", params) req := NewRequest[bool]("unpinAllGeneralForumTopicMessages", params)
return req.Do(api) return req.Do(api)
} }

View File

@@ -20,7 +20,7 @@ type SendMessageP struct {
ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"`
} }
func (api *Api) 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(api) return req.Do(api)
} }
@@ -40,7 +40,7 @@ type ForwardMessageP struct {
SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"`
} }
func (api *Api) ForwardMessage(params ForwardMessageP) (Message, error) { func (api *API) ForwardMessage(params ForwardMessageP) (Message, error) {
req := NewRequest[Message]("forwardMessage", params) req := NewRequest[Message]("forwardMessage", params)
return req.Do(api) return req.Do(api)
} }
@@ -56,7 +56,7 @@ type ForwardMessagesP struct {
ProtectContent bool `json:"protect_content,omitempty"` ProtectContent bool `json:"protect_content,omitempty"`
} }
func (api *Api) ForwardMessages(params ForwardMessagesP) ([]int, error) { func (api *API) ForwardMessages(params ForwardMessagesP) ([]int, error) {
req := NewRequest[[]int]("forwardMessages", params) req := NewRequest[[]int]("forwardMessages", params)
return req.Do(api) return req.Do(api)
} }
@@ -84,7 +84,7 @@ type CopyMessageP struct {
ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"`
} }
func (api *Api) CopyMessage(params CopyMessageP) (int, error) { func (api *API) CopyMessage(params CopyMessageP) (int, error) {
req := NewRequest[int]("copyMessage", params) req := NewRequest[int]("copyMessage", params)
return req.Do(api) return req.Do(api)
} }
@@ -101,7 +101,7 @@ type CopyMessagesP struct {
RemoveCaption bool `json:"remove_caption,omitempty"` RemoveCaption bool `json:"remove_caption,omitempty"`
} }
func (api *Api) CopyMessages(params CopyMessagesP) ([]int, error) { func (api *API) CopyMessages(params CopyMessagesP) ([]int, error) {
req := NewRequest[[]int]("copyMessages", params) req := NewRequest[[]int]("copyMessages", params)
return req.Do(api) return req.Do(api)
} }
@@ -129,7 +129,7 @@ type SendLocationP struct {
ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"`
} }
func (api *Api) SendLocation(params SendLocationP) (Message, error) { func (api *API) SendLocation(params SendLocationP) (Message, error) {
req := NewRequest[Message]("sendLocation", params) req := NewRequest[Message]("sendLocation", params)
return req.Do(api) return req.Do(api)
} }
@@ -159,7 +159,7 @@ type SendVenueP struct {
ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"`
} }
func (api *Api) SendVenue(params SendVenueP) (Message, error) { func (api *API) SendVenue(params SendVenueP) (Message, error) {
req := NewRequest[Message]("sendVenue", params) req := NewRequest[Message]("sendVenue", params)
return req.Do(api) return req.Do(api)
} }
@@ -185,7 +185,7 @@ type SendContactP struct {
ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"`
} }
func (api *Api) SendContact(params SendContactP) (Message, error) { func (api *API) SendContact(params SendContactP) (Message, error) {
req := NewRequest[Message]("sendContact", params) req := NewRequest[Message]("sendContact", params)
return req.Do(api) return req.Do(api)
} }
@@ -219,7 +219,7 @@ type SendPollP struct {
ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"`
} }
func (api *Api) SendPoll(params SendPollP) (Message, error) { func (api *API) SendPoll(params SendPollP) (Message, error) {
req := NewRequest[Message]("sendPoll", params) req := NewRequest[Message]("sendPoll", params)
return req.Do(api) return req.Do(api)
} }
@@ -237,7 +237,7 @@ type SendChecklistP struct {
ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"`
} }
func (api *Api) SendChecklist(params SendChecklistP) (Message, error) { func (api *API) SendChecklist(params SendChecklistP) (Message, error) {
req := NewRequest[Message]("sendChecklist", params) req := NewRequest[Message]("sendChecklist", params)
return req.Do(api) return req.Do(api)
} }
@@ -260,7 +260,7 @@ type SendDiceP struct {
ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"`
} }
func (api *Api) SendDice(params SendDiceP) (Message, error) { func (api *API) SendDice(params SendDiceP) (Message, error) {
req := NewRequest[Message]("sendDice", params) req := NewRequest[Message]("sendDice", params)
return req.Do(api) return req.Do(api)
} }
@@ -274,7 +274,7 @@ type SendMessageDraftP struct {
Entities []MessageEntity `json:"entities,omitempty"` Entities []MessageEntity `json:"entities,omitempty"`
} }
func (api *Api) SendMessageDraft(params SendMessageDraftP) (bool, error) { func (api *API) SendMessageDraft(params SendMessageDraftP) (bool, error) {
req := NewRequest[bool]("sendMessageDraft", params) req := NewRequest[bool]("sendMessageDraft", params)
return req.Do(api) return req.Do(api)
} }
@@ -286,7 +286,7 @@ type SendChatActionP struct {
Action ChatActionType `json:"action"` Action ChatActionType `json:"action"`
} }
func (api *Api) SendChatAction(params SendChatActionP) (bool, error) { func (api *API) SendChatAction(params SendChatActionP) (bool, error) {
req := NewRequest[bool]("sendChatAction", params) req := NewRequest[bool]("sendChatAction", params)
return req.Do(api) return req.Do(api)
} }
@@ -298,7 +298,7 @@ type SetMessageReactionP struct {
IsBig bool `json:"is_big,omitempty"` IsBig bool `json:"is_big,omitempty"`
} }
func (api *Api) SetMessageReaction(params SetMessageReactionP) (bool, error) { func (api *API) SetMessageReaction(params SetMessageReactionP) (bool, error) {
req := NewRequest[bool]("setMessageReaction", params) req := NewRequest[bool]("setMessageReaction", params)
return req.Do(api) return req.Do(api)
} }
@@ -317,7 +317,7 @@ type EditMessageTextP struct {
// EditMessageText If inline message, first return will be zero-valued, and second will boolean // EditMessageText If inline message, first return will be zero-valued, and second will boolean
// Otherwise, first return will be Message, and second false // Otherwise, first return will be Message, and second false
func (api *Api) EditMessageText(params EditMessageTextP) (Message, bool, error) { func (api *API) EditMessageText(params EditMessageTextP) (Message, bool, error) {
var zero Message var zero Message
if params.InlineMessageID != "" { if params.InlineMessageID != "" {
req := NewRequest[bool]("editMessageText", params) req := NewRequest[bool]("editMessageText", params)
@@ -341,7 +341,7 @@ type EditMessageCaptionP struct {
// EditMessageCaption If inline message, first return will be zero-valued, and second will boolean // EditMessageCaption If inline message, first return will be zero-valued, and second will boolean
// Otherwise, first return will be Message, and second false // Otherwise, first return will be Message, and second false
func (api *Api) EditMessageCaption(params EditMessageCaptionP) (Message, bool, error) { func (api *API) EditMessageCaption(params EditMessageCaptionP) (Message, bool, error) {
var zero Message var zero Message
if params.InlineMessageID != "" { if params.InlineMessageID != "" {
req := NewRequest[bool]("editMessageCaption", params) req := NewRequest[bool]("editMessageCaption", params)
@@ -364,7 +364,7 @@ type EditMessageMediaP struct {
// EditMessageMedia If inline message, first return will be zero-valued, and second will boolean // EditMessageMedia If inline message, first return will be zero-valued, and second will boolean
// Otherwise, first return will be Message, and second false // Otherwise, first return will be Message, and second false
func (api *Api) EditMessageMedia(params EditMessageMediaP) (Message, bool, error) { func (api *API) EditMessageMedia(params EditMessageMediaP) (Message, bool, error) {
var zero Message var zero Message
if params.InlineMessageID != "" { if params.InlineMessageID != "" {
req := NewRequest[bool]("editMessageMedia", params) req := NewRequest[bool]("editMessageMedia", params)
@@ -393,7 +393,7 @@ type EditMessageLiveLocationP struct {
// EditMessageLiveLocation If inline message, first return will be zero-valued, and second will boolean // EditMessageLiveLocation If inline message, first return will be zero-valued, and second will boolean
// Otherwise, first return will be Message, and second false // Otherwise, first return will be Message, and second false
func (api *Api) EditMessageLiveLocation(params EditMessageLiveLocationP) (Message, bool, error) { func (api *API) EditMessageLiveLocation(params EditMessageLiveLocationP) (Message, bool, error) {
var zero Message var zero Message
if params.InlineMessageID != "" { if params.InlineMessageID != "" {
req := NewRequest[bool]("editMessageLiveLocation", params) req := NewRequest[bool]("editMessageLiveLocation", params)
@@ -415,7 +415,7 @@ type StopMessageLiveLocationP struct {
// StopMessageLiveLocation If inline message, first return will be zero-valued, and second will boolean // StopMessageLiveLocation If inline message, first return will be zero-valued, and second will boolean
// Otherwise, first return will be Message, and second false // Otherwise, first return will be Message, and second false
func (api *Api) StopMessageLiveLocation(params StopMessageLiveLocationP) (Message, bool, error) { func (api *API) StopMessageLiveLocation(params StopMessageLiveLocationP) (Message, bool, error) {
var zero Message var zero Message
if params.InlineMessageID != "" { if params.InlineMessageID != "" {
req := NewRequest[bool]("stopMessageLiveLocation", params) req := NewRequest[bool]("stopMessageLiveLocation", params)
@@ -435,7 +435,7 @@ type EditMessageChecklistP struct {
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
} }
func (api *Api) EditMessageChecklist(params EditMessageChecklistP) (Message, error) { func (api *API) EditMessageChecklist(params EditMessageChecklistP) (Message, error) {
req := NewRequest[Message]("editMessageChecklist", params) req := NewRequest[Message]("editMessageChecklist", params)
return req.Do(api) return req.Do(api)
} }
@@ -448,7 +448,7 @@ type EditMessageReplyMarkupP struct {
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
} }
func (api *Api) EditMessageReplyMarkup(params EditMessageReplyMarkupP) (Message, bool, error) { func (api *API) EditMessageReplyMarkup(params EditMessageReplyMarkupP) (Message, bool, error) {
var zero Message var zero Message
if params.InlineMessageID != "" { if params.InlineMessageID != "" {
req := NewRequest[bool]("editMessageReplyMarkup", params) req := NewRequest[bool]("editMessageReplyMarkup", params)
@@ -467,7 +467,7 @@ type StopPollP struct {
InlineMessageID string `json:"inline_message_id,omitempty"` InlineMessageID string `json:"inline_message_id,omitempty"`
} }
func (api *Api) StopPoll(params StopPollP) (Poll, error) { func (api *API) StopPoll(params StopPollP) (Poll, error) {
req := NewRequest[Poll]("stopPoll", params) req := NewRequest[Poll]("stopPoll", params)
return req.Do(api) return req.Do(api)
} }
@@ -478,7 +478,7 @@ type ApproveSuggestedPostP struct {
SendDate int `json:"send_date,omitempty"` SendDate int `json:"send_date,omitempty"`
} }
func (api *Api) ApproveSuggestedPost(params ApproveSuggestedPostP) (bool, error) { func (api *API) ApproveSuggestedPost(params ApproveSuggestedPostP) (bool, error) {
req := NewRequest[bool]("approveSuggestedPost", params) req := NewRequest[bool]("approveSuggestedPost", params)
return req.Do(api) return req.Do(api)
} }
@@ -489,7 +489,7 @@ type DeclineSuggestedPostP struct {
Comment string `json:"comment,omitempty"` Comment string `json:"comment,omitempty"`
} }
func (api *Api) DeclineSuggestedPost(params DeclineSuggestedPostP) (bool, error) { func (api *API) DeclineSuggestedPost(params DeclineSuggestedPostP) (bool, error) {
req := NewRequest[bool]("declineSuggestedPost", params) req := NewRequest[bool]("declineSuggestedPost", params)
return req.Do(api) return req.Do(api)
} }
@@ -499,7 +499,7 @@ type DeleteMessageP struct {
MessageID int `json:"message_id"` MessageID int `json:"message_id"`
} }
func (api *Api) DeleteMessage(params DeleteMessageP) (bool, error) { func (api *API) DeleteMessage(params DeleteMessageP) (bool, error) {
req := NewRequest[bool]("deleteMessage", params) req := NewRequest[bool]("deleteMessage", params)
return req.Do(api) return req.Do(api)
} }
@@ -509,7 +509,7 @@ type DeleteMessagesP struct {
MessageIDs []int `json:"message_ids"` MessageIDs []int `json:"message_ids"`
} }
func (api *Api) DeleteMessages(params DeleteMessagesP) (bool, error) { func (api *API) DeleteMessages(params DeleteMessagesP) (bool, error) {
req := NewRequest[bool]("deleteMessages", params) req := NewRequest[bool]("deleteMessages", params)
return req.Do(api) return req.Do(api)
} }
@@ -522,7 +522,7 @@ type AnswerCallbackQueryP struct {
CacheTime int `json:"cache_time,omitempty"` CacheTime int `json:"cache_time,omitempty"`
} }
func (api *Api) AnswerCallbackQuery(params AnswerCallbackQueryP) (bool, error) { func (api *API) AnswerCallbackQuery(params AnswerCallbackQueryP) (bool, error) {
req := NewRequest[bool]("answerCallbackQuery", params) req := NewRequest[bool]("answerCallbackQuery", params)
return req.Do(api) return req.Do(api)
} }

View File

@@ -19,19 +19,19 @@ type UpdateParams struct {
AllowedUpdates []UpdateType `json:"allowed_updates"` AllowedUpdates []UpdateType `json:"allowed_updates"`
} }
func (api *Api) GetMe() (User, error) { func (api *API) GetMe() (User, error) {
req := NewRequest[User, EmptyParams]("getMe", NoParams) req := NewRequest[User, EmptyParams]("getMe", NoParams)
return req.Do(api) return req.Do(api)
} }
func (api *Api) LogOut() (bool, error) { func (api *API) LogOut() (bool, error) {
req := NewRequest[bool, EmptyParams]("logOut", NoParams) req := NewRequest[bool, EmptyParams]("logOut", NoParams)
return req.Do(api) return req.Do(api)
} }
func (api *Api) Close() (bool, error) { func (api *API) Close() (bool, error) {
req := NewRequest[bool, EmptyParams]("close", NoParams) req := NewRequest[bool, EmptyParams]("close", NoParams)
return req.Do(api) return req.Do(api)
} }
func (api *Api) GetUpdates(params UpdateParams) ([]Update, error) { func (api *API) GetUpdates(params UpdateParams) ([]Update, error) {
req := NewRequest[[]Update]("getUpdates", params) req := NewRequest[[]Update]("getUpdates", params)
return req.Do(api) return req.Do(api)
} }
@@ -40,7 +40,7 @@ type GetFileP struct {
FileId string `json:"file_id"` FileId string `json:"file_id"`
} }
func (api *Api) 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(api) return req.Do(api)
} }

View File

@@ -14,7 +14,7 @@ type SendStickerP struct {
MessageEffectID string `json:"message_effect_id,omitempty"` MessageEffectID string `json:"message_effect_id,omitempty"`
} }
func (api *Api) SendSticker(params SendStickerP) (Message, error) { func (api *API) SendSticker(params SendStickerP) (Message, error) {
req := NewRequest[Message]("sendSticker", params) req := NewRequest[Message]("sendSticker", params)
return req.Do(api) return req.Do(api)
} }
@@ -23,7 +23,7 @@ type GetStickerSetP struct {
Name string `json:"name"` Name string `json:"name"`
} }
func (api *Api) GetStickerSet(params GetStickerSetP) (StickerSet, error) { func (api *API) GetStickerSet(params GetStickerSetP) (StickerSet, error) {
req := NewRequest[StickerSet]("getStickerSet", params) req := NewRequest[StickerSet]("getStickerSet", params)
return req.Do(api) return req.Do(api)
} }
@@ -32,7 +32,7 @@ type GetCustomEmojiStickersP struct {
CustomEmojiIDs []string `json:"custom_emoji_ids"` CustomEmojiIDs []string `json:"custom_emoji_ids"`
} }
func (api *Api) GetCustomEmojiStickers(params GetCustomEmojiStickersP) ([]Sticker, error) { func (api *API) GetCustomEmojiStickers(params GetCustomEmojiStickersP) ([]Sticker, error) {
req := NewRequest[[]Sticker]("getCustomEmojiStickers", params) req := NewRequest[[]Sticker]("getCustomEmojiStickers", params)
return req.Do(api) return req.Do(api)
} }
@@ -47,7 +47,7 @@ type CreateNewStickerSetP struct {
NeedsRepainting bool `json:"needs_repainting,omitempty"` NeedsRepainting bool `json:"needs_repainting,omitempty"`
} }
func (api *Api) CreateNewStickerSet(params CreateNewStickerSetP) (bool, error) { func (api *API) CreateNewStickerSet(params CreateNewStickerSetP) (bool, error) {
req := NewRequest[bool]("createNewStickerSet", params) req := NewRequest[bool]("createNewStickerSet", params)
return req.Do(api) return req.Do(api)
} }
@@ -58,7 +58,7 @@ type AddStickerToSetP struct {
Sticker InputSticker `json:"sticker"` Sticker InputSticker `json:"sticker"`
} }
func (api *Api) AddStickerToSet(params AddStickerToSetP) (bool, error) { func (api *API) AddStickerToSet(params AddStickerToSetP) (bool, error) {
req := NewRequest[bool]("addStickerToSet", params) req := NewRequest[bool]("addStickerToSet", params)
return req.Do(api) return req.Do(api)
} }
@@ -68,7 +68,7 @@ type SetStickerPositionInSetP struct {
Position int `json:"position"` Position int `json:"position"`
} }
func (api *Api) SetStickerPosition(params SetStickerPositionInSetP) (bool, error) { func (api *API) SetStickerPosition(params SetStickerPositionInSetP) (bool, error) {
req := NewRequest[bool]("setStickerPosition", params) req := NewRequest[bool]("setStickerPosition", params)
return req.Do(api) return req.Do(api)
} }
@@ -77,7 +77,7 @@ type DeleteStickerFromSetP struct {
Sticker string `json:"sticker"` Sticker string `json:"sticker"`
} }
func (api *Api) DeleteStickerFromSet(params DeleteStickerFromSetP) (bool, error) { func (api *API) DeleteStickerFromSet(params DeleteStickerFromSetP) (bool, error) {
req := NewRequest[bool]("deleteStickerFromSet", params) req := NewRequest[bool]("deleteStickerFromSet", params)
return req.Do(api) return req.Do(api)
} }
@@ -89,7 +89,7 @@ type ReplaceStickerInSetP struct {
Sticker InputSticker `json:"sticker"` Sticker InputSticker `json:"sticker"`
} }
func (api *Api) ReplaceStickerInSet(params ReplaceStickerInSetP) (bool, error) { func (api *API) ReplaceStickerInSet(params ReplaceStickerInSetP) (bool, error) {
req := NewRequest[bool]("replaceStickerInSet", params) req := NewRequest[bool]("replaceStickerInSet", params)
return req.Do(api) return req.Do(api)
} }
@@ -99,7 +99,7 @@ type SetStickerEmojiListP struct {
EmojiList []string `json:"emoji_list"` EmojiList []string `json:"emoji_list"`
} }
func (api *Api) SetStickerEmojiList(params SetStickerEmojiListP) (bool, error) { func (api *API) SetStickerEmojiList(params SetStickerEmojiListP) (bool, error) {
req := NewRequest[bool]("setStickerEmojiList", params) req := NewRequest[bool]("setStickerEmojiList", params)
return req.Do(api) return req.Do(api)
} }
@@ -109,7 +109,7 @@ type SetStickerKeywordsP struct {
Keywords []string `json:"keywords"` Keywords []string `json:"keywords"`
} }
func (api *Api) SetStickerKeywords(params SetStickerKeywordsP) (bool, error) { func (api *API) SetStickerKeywords(params SetStickerKeywordsP) (bool, error) {
req := NewRequest[bool]("setStickerKeywords", params) req := NewRequest[bool]("setStickerKeywords", params)
return req.Do(api) return req.Do(api)
} }
@@ -119,7 +119,7 @@ type SetStickerMaskPositionP struct {
MaskPosition *MaskPosition `json:"mask_position,omitempty"` MaskPosition *MaskPosition `json:"mask_position,omitempty"`
} }
func (api *Api) SetStickerMaskPosition(params SetStickerMaskPositionP) (bool, error) { func (api *API) SetStickerMaskPosition(params SetStickerMaskPositionP) (bool, error) {
req := NewRequest[bool]("setStickerMaskPosition", params) req := NewRequest[bool]("setStickerMaskPosition", params)
return req.Do(api) return req.Do(api)
} }
@@ -129,7 +129,7 @@ type SetStickerSetTitleP struct {
Title string `json:"title"` Title string `json:"title"`
} }
func (api *Api) SetStickerSetTitle(params SetStickerSetTitleP) (bool, error) { func (api *API) SetStickerSetTitle(params SetStickerSetTitleP) (bool, error) {
req := NewRequest[bool]("setStickerSetTitle", params) req := NewRequest[bool]("setStickerSetTitle", params)
return req.Do(api) return req.Do(api)
} }
@@ -141,7 +141,7 @@ type SetStickerSetThumbnailP struct {
Format InputStickerFormat `json:"format"` Format InputStickerFormat `json:"format"`
} }
func (api *Api) SetStickerSetThumbnail(params SetStickerSetThumbnailP) (bool, error) { func (api *API) SetStickerSetThumbnail(params SetStickerSetThumbnailP) (bool, error) {
req := NewRequest[bool]("setStickerSetThumbnail", params) req := NewRequest[bool]("setStickerSetThumbnail", params)
return req.Do(api) return req.Do(api)
} }
@@ -151,7 +151,7 @@ type SetCustomEmojiStickerSetThumbnailP struct {
CustomEmojiID string `json:"custom_emoji_id,omitempty"` CustomEmojiID string `json:"custom_emoji_id,omitempty"`
} }
func (api *Api) SetCustomEmojiStickerSetThumbnail(params SetStickerSetThumbnailP) (bool, error) { func (api *API) SetCustomEmojiStickerSetThumbnail(params SetStickerSetThumbnailP) (bool, error) {
req := NewRequest[bool]("setCustomEmojiStickerSetThumbnail", params) req := NewRequest[bool]("setCustomEmojiStickerSetThumbnail", params)
return req.Do(api) return req.Do(api)
} }
@@ -160,7 +160,7 @@ type DeleteStickerSetP struct {
Name string `json:"name"` Name string `json:"name"`
} }
func (api *Api) DeleteStickerSet(params DeleteStickerSetP) (bool, error) { func (api *API) DeleteStickerSet(params DeleteStickerSetP) (bool, error) {
req := NewRequest[bool]("deleteStickerSet", params) req := NewRequest[bool]("deleteStickerSet", params)
return req.Do(api) return req.Do(api)
} }

150
tgapi/uploader_api.go Normal file
View File

@@ -0,0 +1,150 @@
package tgapi
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"path/filepath"
"git.nix13.pw/scuroneko/laniakea/utils"
"git.nix13.pw/scuroneko/slog"
)
const (
UploaderPhotoType UploaderFileType = "photo"
UploaderVideoType UploaderFileType = "video"
UploaderAudioType UploaderFileType = "audio"
UploaderDocumentType UploaderFileType = "document"
UploaderVoiceType UploaderFileType = "voice"
UploaderVideoNoteType UploaderFileType = "video_note"
UploaderThumbnailType UploaderFileType = "thumbnail"
)
type UploaderFileType string
type UploaderFile struct {
filename string
data []byte
field UploaderFileType
}
func NewUploaderFile(name string, data []byte) UploaderFile {
t := uploaderTypeByExt(name)
return UploaderFile{filename: name, data: data, field: t}
}
// SetType used when auto-detect failed.
// i.e. you sending a voice message, but it detects as audio, or if you send audio with thumbnail
func (f UploaderFile) SetType(t UploaderFileType) UploaderFile {
f.field = t
return f
}
type Uploader struct {
api *API
logger *slog.Logger
}
func NewUploader(api *API) *Uploader {
logger := slog.CreateLogger().Level(utils.GetLoggerLevel()).Prefix("UPLOADER")
logger.AddWriter(logger.CreateJsonStdoutWriter())
return &Uploader{api, logger}
}
func (u *Uploader) Close() error { return u.logger.Close() }
type UploaderRequest[R, P any] struct {
method string
files []UploaderFile
params P
}
func NewUploaderRequest[R, P any](method string, params P, files ...UploaderFile) UploaderRequest[R, P] {
return UploaderRequest[R, P]{method, files, params}
}
func (u UploaderRequest[R, P]) DoWithContext(ctx context.Context, up *Uploader) (R, error) {
var zero R
url := fmt.Sprintf("https://api.telegram.org/bot%s/%s", up.api.token, u.method)
buf := bytes.NewBuffer(nil)
w := multipart.NewWriter(buf)
for _, file := range u.files {
fw, err := w.CreateFormFile(string(file.field), file.filename)
if err != nil {
_ = w.Close()
return zero, err
}
_, err = fw.Write(file.data)
if err != nil {
_ = w.Close()
return zero, err
}
}
err := utils.Encode(w, u.params)
if err != nil {
_ = w.Close()
return zero, err
}
err = w.Close()
if err != nil {
return zero, err
}
req, err := http.NewRequestWithContext(ctx, "POST", url, buf)
if err != nil {
return zero, err
}
req.Header.Set("Content-Type", w.FormDataContentType())
req.Header.Set("Accept", "application/json")
req.Header.Set("User-Agent", fmt.Sprintf("Laniakea/%s", utils.VersionString))
up.logger.Debugln("UPLOADER REQ", u.method)
res, err := up.api.client.Do(req)
if err != nil {
return zero, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return zero, fmt.Errorf("unexpected status code: %d", res.StatusCode)
}
reader := io.LimitReader(res.Body, 10<<20)
body, err := io.ReadAll(reader)
if err != nil {
return zero, err
}
up.logger.Debugln("UPLOADER RES", u.method, string(body))
var resp ApiResponse[R]
err = json.Unmarshal(body, &resp)
if err != nil {
return zero, err
}
if !resp.Ok {
return zero, fmt.Errorf("[%d] %s", resp.ErrorCode, resp.Description)
}
return resp.Result, nil
}
func (u UploaderRequest[R, P]) Do(up *Uploader) (R, error) {
return u.DoWithContext(context.Background(), up)
}
func uploaderTypeByExt(filename string) UploaderFileType {
ext := filepath.Ext(filename)
switch ext {
case ".jpg", ".jpeg", ".png", ".webp", ".bmp":
return UploaderPhotoType
case ".mp4":
return UploaderVideoType
case ".mp3", ".m4a":
return UploaderAudioType
case ".ogg":
return UploaderVoiceType
default:
return UploaderDocumentType
}
}

View File

@@ -1,139 +1,5 @@
package tgapi package tgapi
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"path/filepath"
"git.nix13.pw/scuroneko/laniakea/utils"
"git.nix13.pw/scuroneko/slog"
)
type Uploader struct {
api *Api
logger *slog.Logger
}
func NewUploader(api *Api) *Uploader {
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
const (
UploaderPhotoType UploaderFileType = "photo"
UploaderVideoType UploaderFileType = "video"
UploaderAudioType UploaderFileType = "audio"
UploaderDocumentType UploaderFileType = "document"
UploaderVoiceType UploaderFileType = "voice"
UploaderVideoNoteType UploaderFileType = "video_note"
UploaderThumbnailType UploaderFileType = "thumbnail"
)
type UploaderFile struct {
filename string
data []byte
field UploaderFileType
}
func NewUploaderFile(name string, data []byte) UploaderFile {
t := uploaderTypeByExt(name)
return UploaderFile{filename: name, data: data, field: t}
}
// SetType used when auto-detect failed. I.e. you sending a voice message, but it detects as audio, or if you send audio with thumbnail
func (f UploaderFile) SetType(t UploaderFileType) UploaderFile {
f.field = t
return f
}
type UploaderRequest[R, P any] struct {
method string
files []UploaderFile
params P
}
func NewUploaderRequest[R, P any](method string, params P, files ...UploaderFile) UploaderRequest[R, P] {
return UploaderRequest[R, P]{method, files, params}
}
func (u UploaderRequest[R, P]) DoWithContext(ctx context.Context, up *Uploader) (R, error) {
var zero R
url := fmt.Sprintf("https://api.telegram.org/bot%s/%s", up.api.token, u.method)
buf := bytes.NewBuffer(nil)
w := multipart.NewWriter(buf)
for _, file := range u.files {
fw, err := w.CreateFormFile(string(file.field), file.filename)
if err != nil {
w.Close()
return zero, err
}
_, err = fw.Write(file.data)
if err != nil {
w.Close()
return zero, err
}
}
err := utils.Encode(w, u.params)
if err != nil {
w.Close()
return zero, err
}
err = w.Close()
if err != nil {
return zero, err
}
req, err := http.NewRequestWithContext(ctx, "POST", url, buf)
if err != nil {
return zero, err
}
req.Header.Set("Content-Type", w.FormDataContentType())
req.Header.Set("User-Agent", fmt.Sprintf("Laniakea/%s", utils.VersionString))
up.logger.Debugln("UPLOADER REQ", u.method)
res, err := up.api.client.Do(req)
if err != nil {
return zero, err
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
return zero, err
}
up.logger.Debugln("UPLOADER RES", u.method, string(body))
if res.StatusCode != http.StatusOK {
return zero, fmt.Errorf("[%d] %s", res.StatusCode, string(body))
}
var response ApiResponse[R]
err = json.Unmarshal(body, &response)
if err != nil {
return zero, err
}
if !response.Ok {
return zero, fmt.Errorf("[%d] %s", response.ErrorCode, response.Description)
}
return response.Result, nil
}
func (u UploaderRequest[R, P]) Do(up *Uploader) (R, error) {
ctx := context.Background()
return u.DoWithContext(ctx, up)
}
type UploadPhotoP struct { type UploadPhotoP 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"`
@@ -330,7 +196,6 @@ func (u *Uploader) UploadVideoNote(params UploadVideoNoteP, files ...UploaderFil
return req.Do(u) return req.Do(u)
} }
// setChatPhoto https://core.telegram.org/bots/api#setchatphoto
type UploadChatPhotoP struct { type UploadChatPhotoP struct {
ChatID int `json:"chat_id"` ChatID int `json:"chat_id"`
} }
@@ -339,19 +204,3 @@ func (u *Uploader) UploadChatPhoto(params UploadChatPhotoP, photo UploaderFile)
req := NewUploaderRequest[Message]("sendChatPhoto", params, photo) req := NewUploaderRequest[Message]("sendChatPhoto", params, photo)
return req.Do(u) return req.Do(u)
} }
func uploaderTypeByExt(filename string) UploaderFileType {
ext := filepath.Ext(filename)
switch ext {
case ".jpg", ".jpeg", ".png", ".webp", ".bmp":
return UploaderPhotoType
case ".mp4":
return UploaderVideoType
case ".mp3", ".m4a":
return UploaderAudioType
case ".ogg":
return UploaderVoiceType
default:
return UploaderDocumentType
}
}

View File

@@ -6,7 +6,7 @@ type GetUserProfilePhotosP struct {
Limit int `json:"limit,omitempty"` Limit int `json:"limit,omitempty"`
} }
func (api *Api) GetUserProfilePhotos(params GetUserProfilePhotosP) (UserProfilePhotos, error) { func (api *API) GetUserProfilePhotos(params GetUserProfilePhotosP) (UserProfilePhotos, error) {
req := NewRequest[UserProfilePhotos]("getUserProfilePhotos", params) req := NewRequest[UserProfilePhotos]("getUserProfilePhotos", params)
return req.Do(api) return req.Do(api)
} }
@@ -17,7 +17,7 @@ type GetUserProfileAudiosP struct {
Limit int `json:"limit,omitempty"` Limit int `json:"limit,omitempty"`
} }
func (api *Api) GetUserProfileAudios(params GetUserProfileAudiosP) (UserProfileAudios, error) { func (api *API) GetUserProfileAudios(params GetUserProfileAudiosP) (UserProfileAudios, error) {
req := NewRequest[UserProfileAudios]("getUserProfileAudios", params) req := NewRequest[UserProfileAudios]("getUserProfileAudios", params)
return req.Do(api) return req.Do(api)
} }
@@ -28,7 +28,7 @@ type SetUserEmojiStatusP struct {
ExpirationDate int `json:"emoji_status_expiration_date,omitempty"` ExpirationDate int `json:"emoji_status_expiration_date,omitempty"`
} }
func (api *Api) SetUserEmojiStatus(params SetUserEmojiStatusP) (bool, error) { func (api *API) SetUserEmojiStatus(params SetUserEmojiStatusP) (bool, error) {
req := NewRequest[bool]("setUserEmojiStatus", params) req := NewRequest[bool]("setUserEmojiStatus", params)
return req.Do(api) return req.Do(api)
} }
@@ -45,7 +45,7 @@ type GetUserGiftsP struct {
Limit int `json:"limit,omitempty"` Limit int `json:"limit,omitempty"`
} }
func (api *Api) GetUserGifts(params GetUserGiftsP) (OwnedGifts, error) { func (api *API) GetUserGifts(params GetUserGiftsP) (OwnedGifts, error) {
req := NewRequest[OwnedGifts]("getUserGifts", params) req := NewRequest[OwnedGifts]("getUserGifts", params)
return req.Do(api) return req.Do(api)
} }

View File

@@ -1,15 +0,0 @@
package tgapi
import (
"os"
"git.nix13.pw/scuroneko/slog"
)
func GetLoggerLevel() slog.LogLevel {
level := slog.FATAL
if os.Getenv("DEBUG") == "true" {
level = slog.DEBUG
}
return level
}

View File

@@ -1,7 +1,6 @@
package utils package utils
import ( import (
"encoding/json"
"fmt" "fmt"
"os" "os"
"strings" "strings"
@@ -17,73 +16,6 @@ func GetLoggerLevel() slog.LogLevel {
return level return level
} }
func Cast[A, B any](src A) (*B, error) {
m, err := StructToMap(src)
if err != nil {
return nil, err
}
out := new(B)
err = MapToStruct(m, out)
if err != nil {
return nil, err
}
return out, nil
}
// MapToStruct unsafe function
func MapToStruct(m map[string]any, s any) error {
data, err := json.Marshal(m)
if err != nil {
return err
}
err = json.Unmarshal(data, s)
return err
}
// SliceToStruct unsafe function
func SliceToStruct(sl []any, s any) error {
data, err := json.Marshal(sl)
if err != nil {
return err
}
err = json.Unmarshal(data, s)
return err
}
// AnyToStruct unsafe function
func AnyToStruct(src, dest any) error {
data, err := json.Marshal(src)
if err != nil {
return err
}
err = json.Unmarshal(data, dest)
return err
}
func MapToJson(m map[string]any) (string, error) {
data, err := json.Marshal(m)
return string(data), err
}
func StructToMap(s any) (map[string]any, error) {
data, err := json.Marshal(s)
if err != nil {
return nil, err
}
m := make(map[string]any)
err = json.Unmarshal(data, &m)
return m, err
}
func Map[T, V any](ts []T, fn func(T) V) []V {
result := make([]V, len(ts))
for i, t := range ts {
result[i] = fn(t)
}
return result
}
func EscapeMarkdown(s string) string { func EscapeMarkdown(s string) string {
s = strings.ReplaceAll(s, "_", `\_`) s = strings.ReplaceAll(s, "_", `\_`)
s = strings.ReplaceAll(s, "*", `\*`) s = strings.ReplaceAll(s, "*", `\*`)

View File

@@ -1,8 +1,8 @@
package utils package utils
const ( const (
VersionString = "0.5.0" VersionString = "0.6.1"
VersionMajor = 0 VersionMajor = 0
VersionMinor = 5 VersionMinor = 6
VersionPatch = 0 VersionPatch = 1
) )