Fixed naming. We do not need the "Arg" thing.

This commit is contained in:
Andrey Parhomenko 2023-08-18 13:46:10 +03:00
parent 94d8c38dd5
commit 3f26d2f916
9 changed files with 195 additions and 150 deletions

44
airfile Normal file
View 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

View file

@ -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
View file

@ -1,5 +1,8 @@
all: build
run-air:V:
air -c airfile
build:V:
go build -o exe/ ./cmd/...

View file

@ -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)
}

View file

@ -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),
}

View file

@ -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
View 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
View 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
}

View file

@ -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
}
}