Documentation ¶
Overview ¶
Package session provides a session managment.
What is the session? ¶
The session of a chat is a persistent storage with user defined structure. As example, you can store user input in the multi-step form, counters, etc.
Where data is stored? ¶
By default, the data is stored in memory (see StoreMemory). It's not good, because it's not persistent and you can lose data if the bot is restarted. You can use any provided storage, see StoreMemory and StoreFile for built-in stores. Or you can use your own storage by implementing Store interface.
How it works? ¶
See [Manager.Wrapper] for details about middleware logic.
Index ¶
- func KeyFuncChat(update *tgb.Update) string
- type KeyFunc
- type Manager
- func (manager *Manager[T]) Filter(fn func(*T) bool) tgb.Filter
- func (manager *Manager[T]) Get(ctx context.Context) *T
- func (manager *Manager[T]) Reset(session *T)
- func (manager *Manager[T]) SetEqualFunc(fn func(T, T) bool)
- func (manager *Manager[T]) Setup(opt ManagerOption, opts ...ManagerOption)
- func (manager *Manager[T]) Wrap(next tgb.Handler) tgb.Handler
- type ManagerOption
- type Store
- type StoreFile
- type StoreFileOption
- type StoreMemory
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func KeyFuncChat ¶
KeyFuncChat generate a key from update chat id.
Types ¶
type Manager ¶
type Manager[T comparable] struct { // contains filtered or unexported fields }
Manager provides a persistent data storage for bot. You can use it to store chat-specific data persistently.
func NewManager ¶
func NewManager[T comparable](initial T, opts ...ManagerOption) *Manager[T]
NewManager creates a new session manager with session initial value. Settings of the manager can be changed by passing ManagerOption functions.
Options can be passed later with Manager.Setup method. It is useful if you want to define Manager globally and init with e.g. store later.
Example ¶
package main import ( "context" "fmt" "github.com/mr-linch/go-tg/examples" "github.com/mr-linch/go-tg/tgb" "github.com/mr-linch/go-tg/tgb/session" ) func main() { type Session struct { MessagesCount int } sessionManager := session.NewManager(Session{}) targetCount := 5 router := tgb.NewRouter(). Use(sessionManager). Message(func(ctx context.Context, mu *tgb.MessageUpdate) error { session := sessionManager.Get(ctx) session.MessagesCount++ left := targetCount - session.MessagesCount if left == 0 { return mu.Answer("🏆 You are done!").DoVoid(ctx) } else { return mu.Answer(fmt.Sprintf("Keep going, left %d", left)).DoVoid(ctx) } }) examples.Run(router) }
Output:
func (*Manager[T]) Filter ¶
Filter creates a github.com/mr-linch/go-tg/tgb.Filter based on Session data.
Example:
isStepName := manager.Filter(func(session *Session) bool { return session.Step == "name" })
This filter can be used in github.com/mr-linch/go-tg/tgb.Router handler registration method:
router.Message(func(ctx context.Context, mu *tgb.MessageUpdate) error { // ... }, isStepName)
Example ¶
type Step int8 const ( StepInit Step = iota StepName StepEmail StepPhone ) type Session struct { Step Step Name string Email string Phone string } sessionManager := session.NewManager(Session{}) isStepEqual := func(step Step) tgb.Filter { return sessionManager.Filter(func(s *Session) bool { return s.Step == step }) } router := tgb.NewRouter(). Use(sessionManager). Message(func(ctx context.Context, mu *tgb.MessageUpdate) error { sessionManager.Get(ctx).Step = StepName return mu.Answer("(1/3) What is your name?").DoVoid(ctx) }, isStepEqual(StepInit)). Message(func(ctx context.Context, mu *tgb.MessageUpdate) error { session := sessionManager.Get(ctx) session.Name = mu.Text session.Step = StepEmail return mu.Answer("(2/3) What is your email?").DoVoid(ctx) }, isStepEqual(StepName)). Message(func(ctx context.Context, mu *tgb.MessageUpdate) error { session := sessionManager.Get(ctx) session.Email = mu.Text session.Step = StepPhone return mu.Answer("3/3) What is your phone?").DoVoid(ctx) }, isStepEqual(StepEmail)). Message(func(ctx context.Context, mu *tgb.MessageUpdate) error { session := sessionManager.Get(ctx) session.Phone = mu.Text v, err := json.MarshalIndent(session, "", " ") if err != nil { return err } sessionManager.Reset(session) return mu.Answer(tg.HTML.Line( tg.HTML.Bold("Your session:"), tg.HTML.Code(string(v)), )).ParseMode(tg.HTML).DoVoid(ctx) }, isStepEqual(StepPhone)) examples.Run(router)
Output:
func (*Manager[T]) Get ¶
Get returns Session from context.Context. If session doesn't exist, it returns nil.
func (*Manager[T]) Reset ¶
func (manager *Manager[T]) Reset(session *T)
Reset resets session value to initial value.
If session value equals to initial value, it will be removed from Store.
func (*Manager[T]) SetEqualFunc ¶ added in v0.5.0
SetEqualFunc sets a function that compares two sessions. By default, it uses [==].
func (*Manager[T]) Setup ¶
func (manager *Manager[T]) Setup(opt ManagerOption, opts ...ManagerOption)
Setup it is late initialization method.
func (*Manager[T]) Wrap ¶
Wrap allow use manager as github.com/mr-linch/go-tg/tgb.Middleware.
This middleware do following:
- fetch session data from Store or create new one if it doesn't exist.
- put session data to context.Context
- call handler (note: if chain returns error, return an error and do not save changes)
- update session data in Store if it was changed (delete if session value equals initial)
type ManagerOption ¶
type ManagerOption func(managerSettings)
ManagerOption is a function that sets options for a session manager.
func WithEncoding ¶
func WithEncoding( encode func(v any) ([]byte, error), decode func(data []byte, v any) error, ) ManagerOption
WithEncoding sets a encoding for sessions. By default, it uses json.Marshal and json.Unmarshal.
func WithKeyFunc ¶
func WithKeyFunc(keyFunc KeyFunc) ManagerOption
WithKeyFunc sets a key function for a get session. By default, it uses KeyFuncChat.
func WithStore ¶
func WithStore(storage Store) ManagerOption
WithStore sets a storage for sessions. By default, it uses StoreMemory.
type Store ¶
type Store interface { // Set saves a session session data. Set(ctx context.Context, key string, value []byte) error // Get returns a session data. // If the session data is not found, returns nil and nil. Get(ctx context.Context, key string) ([]byte, error) // Del deletes a session data. Del(ctx context.Context, key string) error }
Store define interface for session persistance. All stores should have read, write and delete methods. See StoreMemory for example.
type StoreFile ¶ added in v0.4.0
type StoreFile struct {
// contains filtered or unexported fields
}
StoreFile is a session store that stores sessions in files.
func NewStoreFile ¶ added in v0.4.0
func NewStoreFile(dir string, opts ...StoreFileOption) *StoreFile
NewStoreFile creates a new StoreFile.
type StoreFileOption ¶ added in v0.4.0
type StoreFileOption func(*StoreFile)
StoreFileOption is a function that can be passed to NewStoreFile to customize the behavior of the store.
func WithStoreFilePerm ¶ added in v0.4.0
func WithStoreFilePerm(perms os.FileMode) StoreFileOption
WithStoreFilePerm sets the permissions of the files created by the store.
func WithStoreFileTransform ¶ added in v0.4.0
func WithStoreFileTransform(transform func(string) []string) StoreFileOption
WithStoreFileTransform sets the transform function that is used to
type StoreMemory ¶
type StoreMemory struct {
// contains filtered or unexported fields
}
StoreMemory is a memory storage for sessions. It implements Store and is thread-safe.
func NewStoreMemory ¶
func NewStoreMemory() *StoreMemory