Fixed naming. We do not need the "Arg" thing.
This commit is contained in:
parent
94d8c38dd5
commit
3f26d2f916
9 changed files with 195 additions and 150 deletions
44
airfile
Normal file
44
airfile
Normal file
|
@ -0,0 +1,44 @@
|
|||
root = "."
|
||||
testdata_dir = "testdata"
|
||||
tmp_dir = "tmp"
|
||||
|
||||
[build]
|
||||
args_bin = []
|
||||
bin = "./exe/test.exe"
|
||||
cmd = "go build -o ./exe/ ./cmd/..."
|
||||
delay = 0
|
||||
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
|
||||
exclude_file = []
|
||||
exclude_regex = ["_test.go"]
|
||||
exclude_unchanged = false
|
||||
follow_symlink = false
|
||||
full_bin = ""
|
||||
include_dir = []
|
||||
include_ext = ["go", "tpl", "tmpl", "html"]
|
||||
include_file = []
|
||||
kill_delay = "0s"
|
||||
log = "build-errors.log"
|
||||
poll = false
|
||||
poll_interval = 0
|
||||
rerun = false
|
||||
rerun_delay = 500
|
||||
send_interrupt = false
|
||||
stop_on_error = true
|
||||
|
||||
[color]
|
||||
app = ""
|
||||
build = "yellow"
|
||||
main = "magenta"
|
||||
runner = "green"
|
||||
watcher = "cyan"
|
||||
|
||||
[log]
|
||||
main_only = false
|
||||
time = false
|
||||
|
||||
[misc]
|
||||
clean_on_exit = false
|
||||
|
||||
[screen]
|
||||
clear_on_rebuild = false
|
||||
keep_scroll = true
|
|
@ -17,12 +17,12 @@ var (
|
|||
ScreenChange("start")
|
||||
|
||||
incDecKeyboard = tx.NewKeyboard("").Row(
|
||||
tx.NewButton("+").ActionFunc(func(c *tx.A) {
|
||||
tx.NewButton("+").ActionFunc(func(c *tx.Context) {
|
||||
d := c.V.(*UserData)
|
||||
d.Counter++
|
||||
c.Sendf("%d", d.Counter)
|
||||
}),
|
||||
tx.NewButton("-").ActionFunc(func(c *tx.A) {
|
||||
tx.NewButton("-").ActionFunc(func(c *tx.Context) {
|
||||
d := c.V.(*UserData)
|
||||
d.Counter--
|
||||
c.Sendf("%d", d.Counter)
|
||||
|
@ -46,10 +46,11 @@ var (
|
|||
Row(
|
||||
tx.NewButton("Send location").
|
||||
WithSendLocation(true).
|
||||
ActionFunc(func(c *tx.A) {
|
||||
ActionFunc(func(c *tx.Context) {
|
||||
var err error
|
||||
if c.U.Message.Location != nil {
|
||||
l := c.U.Message.Location
|
||||
u := c.Update
|
||||
if u.Message.Location != nil {
|
||||
l := u.Message.Location
|
||||
err = c.Sendf(
|
||||
"Longitude: %f\n"+
|
||||
"Latitude: %f\n"+
|
||||
|
@ -77,7 +78,7 @@ var (
|
|||
)
|
||||
|
||||
var beh = tx.NewBehaviour().
|
||||
WithInitFunc(func(c *tx.A) {
|
||||
WithInitFunc(func(c *tx.Context) {
|
||||
// The session initialization.
|
||||
c.V = &UserData{}
|
||||
c.ChangeScreen("start")
|
||||
|
@ -108,7 +109,7 @@ var beh = tx.NewBehaviour().
|
|||
).
|
||||
WithKeyboard(incDecKeyboard).
|
||||
// The function will be called when reaching the screen.
|
||||
ActionFunc(func(c *tx.A) {
|
||||
ActionFunc(func(c *tx.Context) {
|
||||
d := c.V.(*UserData)
|
||||
c.Sendf("Current counter value = %d", d.Counter)
|
||||
}),
|
||||
|
@ -130,7 +131,7 @@ var beh = tx.NewBehaviour().
|
|||
tx.NewKeyboard("").Row(
|
||||
tx.NewButton("Check").
|
||||
WithData("check").
|
||||
ActionFunc(func(a *tx.A) {
|
||||
ActionFunc(func(a *tx.Context) {
|
||||
d := a.V.(*UserData)
|
||||
a.Sendf("Counter = %d", d.Counter)
|
||||
}),
|
||||
|
@ -139,12 +140,12 @@ var beh = tx.NewBehaviour().
|
|||
).WithCommands(
|
||||
tx.NewCommand("hello").
|
||||
Desc("sends the 'Hello, World!' message back").
|
||||
ActionFunc(func(c *tx.A) {
|
||||
ActionFunc(func(c *tx.Context) {
|
||||
c.Send("Hello, World!")
|
||||
}),
|
||||
tx.NewCommand("read").
|
||||
Desc("reads a string and sends it back").
|
||||
ActionFunc(func(c *tx.A) {
|
||||
ActionFunc(func(c *tx.Context) {
|
||||
c.Send("Type some text:")
|
||||
msg, err := c.ReadTextMessage()
|
||||
if err != nil {
|
||||
|
@ -155,7 +156,7 @@ var beh = tx.NewBehaviour().
|
|||
)
|
||||
|
||||
func mutateMessage(fn func(string) string) tx.ActionFunc {
|
||||
return func(c *tx.A) {
|
||||
return func(c *tx.Context) {
|
||||
for {
|
||||
msg, err := c.ReadTextMessage()
|
||||
if err == tx.NotAvailableErr {
|
||||
|
@ -173,15 +174,15 @@ func mutateMessage(fn func(string) string) tx.ActionFunc {
|
|||
}
|
||||
|
||||
var gBeh = tx.NewGroupBehaviour().
|
||||
InitFunc(func(a *tx.GA) {
|
||||
InitFunc(func(c *tx.GC) {
|
||||
}).
|
||||
WithCommands(
|
||||
tx.NewGroupCommand("hello").ActionFunc(func(a *tx.GA) {
|
||||
a.Send("Hello, World!")
|
||||
tx.NewGroupCommand("hello").ActionFunc(func(c *tx.GC) {
|
||||
c.Send("Hello, World!")
|
||||
}),
|
||||
tx.NewGroupCommand("mycounter").ActionFunc(func(a *tx.GA) {
|
||||
d := a.GetSessionValue().(*UserData)
|
||||
a.Sendf("Your counter value is %d", d.Counter)
|
||||
tx.NewGroupCommand("mycounter").ActionFunc(func(c *tx.GC) {
|
||||
d := c.GetSessionValue().(*UserData)
|
||||
c.Sendf("Your counter value is %d", d.Counter)
|
||||
}),
|
||||
)
|
||||
|
||||
|
|
3
mkfile
3
mkfile
|
@ -1,5 +1,8 @@
|
|||
all: build
|
||||
|
||||
run-air:V:
|
||||
air -c airfile
|
||||
|
||||
build:V:
|
||||
go build -o exe/ ./cmd/...
|
||||
|
||||
|
|
100
src/tx/action.go
100
src/tx/action.go
|
@ -22,106 +22,16 @@ func newAction(a Action) *action {
|
|||
}
|
||||
}
|
||||
|
||||
func (a *action) Act(arg *A) {
|
||||
func (a *action) Act(c *Context) {
|
||||
if a.Action != nil {
|
||||
a.Action.Act(arg)
|
||||
a.Action.Act(c)
|
||||
}
|
||||
}
|
||||
|
||||
// Customized actions for the bot.
|
||||
type Action interface {
|
||||
Act(*Arg)
|
||||
}
|
||||
|
||||
// Customized actions for the
|
||||
type GroupAction interface {
|
||||
Act(*GroupArg)
|
||||
}
|
||||
|
||||
type ActionFunc func(*Arg)
|
||||
|
||||
func (af ActionFunc) Act(a *Arg) {
|
||||
af(a)
|
||||
}
|
||||
|
||||
type GroupActionFunc func(*GroupArg)
|
||||
|
||||
func (af GroupActionFunc) Act(a *GroupArg) {
|
||||
af(a)
|
||||
}
|
||||
|
||||
// The type implements changing screen to the underlying ScreenId
|
||||
type ScreenChange ScreenId
|
||||
|
||||
func (sc ScreenChange) Act(c *Arg) {
|
||||
if !c.B.behaviour.ScreenExist(ScreenId(sc)) {
|
||||
panic(ScreenNotExistErr)
|
||||
}
|
||||
err := c.ChangeScreen(ScreenId(sc))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// The argument for handling.
|
||||
type Arg struct {
|
||||
// Current context.
|
||||
*Context
|
||||
// The update that made the action to be called.
|
||||
U *Update
|
||||
}
|
||||
type A = Arg
|
||||
|
||||
// Changes screen of user to the Id one.
|
||||
func (c *Arg) ChangeScreen(screenId ScreenId) error {
|
||||
if !c.B.behaviour.ScreenExist(screenId) {
|
||||
return ScreenNotExistErr
|
||||
}
|
||||
|
||||
// Stop the reading by sending the nil,
|
||||
// since we change the screen and
|
||||
// current goroutine needs to be stopped.
|
||||
if c.readingUpdate {
|
||||
c.updates <- nil
|
||||
}
|
||||
|
||||
// Getting the screen and changing to
|
||||
// then executing its action.
|
||||
screen := c.B.behaviour.Screens[screenId]
|
||||
c.prevScreen = c.curScreen
|
||||
c.curScreen = screen
|
||||
screen.Render(c.Context)
|
||||
if screen.Action != nil {
|
||||
c.run(screen.Action, c.U)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// The argument for handling in group behaviour.
|
||||
type GroupArg struct {
|
||||
*GroupContext
|
||||
*Update
|
||||
}
|
||||
type GA = GroupArg
|
||||
|
||||
func (a *GA) SentFromSid() SessionId {
|
||||
return SessionId(a.SentFrom().ID)
|
||||
}
|
||||
|
||||
func (a *GA) GetSessionValue() any {
|
||||
v, _ := a.B.GetSessionValueBySid(a.SentFromSid())
|
||||
return v
|
||||
}
|
||||
|
||||
// The argument for handling in channenl behaviours.
|
||||
type ChannelArg struct {
|
||||
type ChannelContext struct {
|
||||
}
|
||||
type CA = ChannelArg
|
||||
type CC = ChannelContext
|
||||
type ChannelAction struct {
|
||||
Act (*ChannelArg)
|
||||
}
|
||||
|
||||
type JsonTyper interface {
|
||||
JsonType() string
|
||||
Act (*ChannelContext)
|
||||
}
|
||||
|
|
|
@ -128,13 +128,12 @@ func (bot *Bot) handlePrivate(updates chan *Update) {
|
|||
_, chnOk = chans[sid]
|
||||
// Making the bot ignore anything except "start"
|
||||
// before the session started
|
||||
if u.Message.IsCommand() &&
|
||||
(!sessionOk) {
|
||||
if u.Message.IsCommand() && !sessionOk {
|
||||
cmdName := CommandName(u.Message.Command())
|
||||
if cmdName == "start" {
|
||||
session := bot.sessions[sid]
|
||||
ctx := &Context{
|
||||
B: bot,
|
||||
ctx := &context{
|
||||
Bot: bot,
|
||||
Session: session,
|
||||
updates: make(chan *Update),
|
||||
}
|
||||
|
@ -166,8 +165,8 @@ func (bot *Bot) handleGroup(updates chan *Update) {
|
|||
if _, ok := bot.groupSessions[sid]; !ok {
|
||||
bot.groupSessions.Add(sid)
|
||||
session := bot.groupSessions[sid]
|
||||
ctx := &GroupContext{
|
||||
B: bot,
|
||||
ctx := &groupContext{
|
||||
Bot: bot,
|
||||
GroupSession: session,
|
||||
updates: make(chan *Update),
|
||||
}
|
||||
|
|
|
@ -6,11 +6,9 @@ import (
|
|||
apix "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
)
|
||||
|
||||
// The type represents way to interact with user in
|
||||
// handling functions. Is provided to Act() function always.
|
||||
type Context struct {
|
||||
type context struct {
|
||||
*Session
|
||||
B *Bot
|
||||
*Bot
|
||||
updates chan *Update
|
||||
// Is true if currently reading the Update.
|
||||
readingUpdate bool
|
||||
|
@ -18,11 +16,13 @@ type Context struct {
|
|||
curScreen, prevScreen *Screen
|
||||
}
|
||||
|
||||
// The type represents way to interact with user in
|
||||
// handling functions. Is provided to Act() function always.
|
||||
|
||||
// Goroutie function to handle each user.
|
||||
func (c *Context) handleUpdateChan(updates chan *Update) {
|
||||
func (c *context) handleUpdateChan(updates chan *Update) {
|
||||
var act Action
|
||||
bot := c.B
|
||||
beh := bot.behaviour
|
||||
beh := c.behaviour
|
||||
|
||||
if beh.Init != nil {
|
||||
c.run(beh.Init, nil)
|
||||
|
@ -73,7 +73,7 @@ func (c *Context) handleUpdateChan(updates chan *Update) {
|
|||
cb := apix.NewCallback(u.CallbackQuery.ID, u.CallbackQuery.Data)
|
||||
data := u.CallbackQuery.Data
|
||||
|
||||
_, err := bot.Request(cb)
|
||||
_, err := c.Request(cb)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -103,15 +103,15 @@ func (c *Context) handleUpdateChan(updates chan *Update) {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *Context) run(a Action, u *Update) {
|
||||
go a.Act(&A{
|
||||
Context: c,
|
||||
U: u,
|
||||
func (c *context) run(a Action, u *Update) {
|
||||
go a.Act(&Context{
|
||||
context: c,
|
||||
Update: u,
|
||||
})
|
||||
}
|
||||
|
||||
// Returns the next update ignoring current screen.
|
||||
func (c *Context) ReadUpdate() (*Update, error) {
|
||||
func (c *context) ReadUpdate() (*Update, error) {
|
||||
c.readingUpdate = true
|
||||
u := <-c.updates
|
||||
c.readingUpdate = false
|
||||
|
@ -123,7 +123,7 @@ func (c *Context) ReadUpdate() (*Update, error) {
|
|||
}
|
||||
|
||||
// Returns the next text message that the user sends.
|
||||
func (c *Context) ReadTextMessage() (string, error) {
|
||||
func (c *context) ReadTextMessage() (string, error) {
|
||||
u, err := c.ReadUpdate()
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -136,34 +136,34 @@ func (c *Context) ReadTextMessage() (string, error) {
|
|||
}
|
||||
|
||||
// Sends to the user specified text.
|
||||
func (c *Context) Send(v ...any) error {
|
||||
func (c *context) Send(v ...any) error {
|
||||
msg := apix.NewMessage(c.Id.ToTelegram(), fmt.Sprint(v...))
|
||||
_, err := c.B.Send(msg)
|
||||
_, err := c.Bot.Send(msg)
|
||||
return err
|
||||
}
|
||||
|
||||
// Sends the formatted with fmt.Sprintf message to the user.
|
||||
func (c *Context) Sendf(format string, v ...any) error {
|
||||
func (c *context) Sendf(format string, v ...any) error {
|
||||
return c.Send(fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// Context for interaction inside groups.
|
||||
type GroupContext struct {
|
||||
type groupContext struct {
|
||||
*GroupSession
|
||||
B *Bot
|
||||
*Bot
|
||||
updates chan *Update
|
||||
}
|
||||
|
||||
func (c *GroupContext) run(a GroupAction, u *Update) {
|
||||
go a.Act(&GA{
|
||||
GroupContext: c,
|
||||
func (c *groupContext) run(a GroupAction, u *Update) {
|
||||
go a.Act(&GroupContext{
|
||||
groupContext: c,
|
||||
Update: u,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *GroupContext) handleUpdateChan(updates chan *Update) {
|
||||
func (c *groupContext) handleUpdateChan(updates chan *Update) {
|
||||
var act GroupAction
|
||||
beh := c.B.groupBehaviour
|
||||
beh := c.groupBehaviour
|
||||
for u := range updates {
|
||||
if u.Message != nil {
|
||||
msg := u.Message
|
||||
|
@ -172,7 +172,7 @@ func (c *GroupContext) handleUpdateChan(updates chan *Update) {
|
|||
|
||||
// Skipping the commands sent not to us.
|
||||
atName := msg.CommandWithAt()[len(cmdName)+1:]
|
||||
if c.B.Me.UserName != atName {
|
||||
if c.Bot.Me.UserName != atName {
|
||||
continue
|
||||
}
|
||||
cmd, ok := beh.Commands[cmdName]
|
||||
|
@ -189,13 +189,13 @@ func (c *GroupContext) handleUpdateChan(updates chan *Update) {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *GroupContext) Sendf(format string, v ...any) error {
|
||||
func (c *groupContext) Sendf(format string, v ...any) error {
|
||||
return c.Send(fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// Sends into the chat specified values converted to strings.
|
||||
func (c *GroupContext) Send(v ...any) error {
|
||||
func (c *groupContext) Send(v ...any) error {
|
||||
msg := apix.NewMessage(c.Id.ToTelegram(), fmt.Sprint(v...))
|
||||
_, err := c.B.Send(msg)
|
||||
_, err := c.Bot.Send(msg)
|
||||
return err
|
||||
}
|
||||
|
|
29
src/tx/group.go
Normal file
29
src/tx/group.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
package tx
|
||||
|
||||
// Customized actions for the group behaviour.
|
||||
type GroupAction interface {
|
||||
Act(*GroupContext)
|
||||
}
|
||||
|
||||
// The handler function type.
|
||||
type GroupActionFunc func(*GroupContext)
|
||||
|
||||
func (af GroupActionFunc) Act(a *GroupContext) {
|
||||
af(a)
|
||||
}
|
||||
|
||||
type GC = GroupContext
|
||||
|
||||
func (c *GroupContext) SentFromSid() SessionId {
|
||||
return SessionId(c.SentFrom().ID)
|
||||
}
|
||||
|
||||
func (a *GroupContext) GetSessionValue() any {
|
||||
v, _ := a.Bot.GetSessionValueBySid(a.SentFromSid())
|
||||
return v
|
||||
}
|
||||
|
||||
type GroupContext struct {
|
||||
*groupContext
|
||||
*Update
|
||||
}
|
59
src/tx/private.go
Normal file
59
src/tx/private.go
Normal file
|
@ -0,0 +1,59 @@
|
|||
package tx
|
||||
|
||||
// Interface to interact with the user.
|
||||
type Context struct {
|
||||
*context
|
||||
*Update
|
||||
}
|
||||
|
||||
// Customized actions for the bot.
|
||||
type Action interface {
|
||||
Act(*Context)
|
||||
}
|
||||
|
||||
type ActionFunc func(*Context)
|
||||
|
||||
func (af ActionFunc) Act(c *Context) {
|
||||
af(c)
|
||||
}
|
||||
|
||||
// The type implements changing screen to the underlying ScreenId
|
||||
type ScreenChange ScreenId
|
||||
|
||||
func (sc ScreenChange) Act(c *Context) {
|
||||
if !c.behaviour.ScreenExist(ScreenId(sc)) {
|
||||
panic(ScreenNotExistErr)
|
||||
}
|
||||
err := c.ChangeScreen(ScreenId(sc))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
type C = Context
|
||||
|
||||
// Changes screen of user to the Id one.
|
||||
func (c *Context) ChangeScreen(screenId ScreenId) error {
|
||||
if !c.behaviour.ScreenExist(screenId) {
|
||||
return ScreenNotExistErr
|
||||
}
|
||||
|
||||
// Stop the reading by sending the nil,
|
||||
// since we change the screen and
|
||||
// current goroutine needs to be stopped.
|
||||
if c.readingUpdate {
|
||||
c.updates <- nil
|
||||
}
|
||||
|
||||
// Getting the screen and changing to
|
||||
// then executing its action.
|
||||
screen := c.behaviour.Screens[screenId]
|
||||
c.prevScreen = c.curScreen
|
||||
c.curScreen = screen
|
||||
screen.Render(c.context)
|
||||
if screen.Action != nil {
|
||||
c.run(screen.Action, c.Update)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -62,7 +62,7 @@ func (s *Screen) ActionFunc(a ActionFunc) *Screen {
|
|||
}
|
||||
|
||||
// Renders output of the screen only to the side of the user.
|
||||
func (s *Screen) Render(c *Context) error {
|
||||
func (s *Screen) Render(c *context) error {
|
||||
id := c.Id.ToTelegram()
|
||||
kbd := s.Keyboard
|
||||
iKbd := s.InlineKeyboard
|
||||
|
@ -87,13 +87,13 @@ func (s *Screen) Render(c *Context) error {
|
|||
msg.ReplyMarkup = iKbd.toTelegramInline()
|
||||
} else if kbd != nil {
|
||||
msg.ReplyMarkup = kbd.toTelegramReply()
|
||||
if _, err := c.B.Send(msg); err != nil {
|
||||
if _, err := c.Bot.Send(msg); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
msg.ReplyMarkup = apix.NewRemoveKeyboard(true)
|
||||
if _, err := c.B.Send(msg); err != nil {
|
||||
if _, err := c.Bot.Send(msg); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -121,7 +121,7 @@ func (s *Screen) Render(c *Context) error {
|
|||
|
||||
for _, m := range ch {
|
||||
if m != nil {
|
||||
if _, err := c.B.Send(m); err != nil {
|
||||
if _, err := c.Bot.Send(m); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue