session

package
v0.15.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 29, 2024 License: MIT Imports: 9 Imported by: 3

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

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func KeyFuncChat

func KeyFuncChat(update *tgb.Update) string

KeyFuncChat generate a key from update chat id.

Types

type KeyFunc

type KeyFunc func(update *tgb.Update) string

KeyFunc is a function that returns a key for a session from update.

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

func (manager *Manager[T]) Filter(fn func(*T) bool) tgb.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

func (manager *Manager[T]) Get(ctx context.Context) *T

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

func (manager *Manager[T]) SetEqualFunc(fn func(T, T) bool)

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

func (manager *Manager[T]) Wrap(next tgb.Handler) tgb.Handler

Wrap allow use manager as github.com/mr-linch/go-tg/tgb.Middleware.

This middleware do following:

  1. fetch session data from Store or create new one if it doesn't exist.
  2. put session data to context.Context
  3. call handler (note: if chain returns error, return an error and do not save changes)
  4. 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.

func (*StoreFile) Del added in v0.4.0

func (store *StoreFile) Del(ctx context.Context, key string) error

Del deletes the session data.

func (*StoreFile) Get added in v0.4.0

func (store *StoreFile) Get(ctx context.Context, key string) ([]byte, error)

Get retrieves the session data.

func (*StoreFile) Set added in v0.4.0

func (store *StoreFile) Set(ctx context.Context, key string, value []byte) error

Set stores the session data.

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

func (*StoreMemory) Del

func (s *StoreMemory) Del(ctx context.Context, key string) error

func (*StoreMemory) Get

func (s *StoreMemory) Get(ctx context.Context, key string) ([]byte, error)

func (*StoreMemory) Set

func (s *StoreMemory) Set(ctx context.Context, key string, value []byte) error

Directories

Path Synopsis
sessionredis module
sessionsql module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL