func (d *Dispatcher) AddHandlerToGroup(handler Handler, group int) {
	currHandlers, ok := d.handlers[group]
	if !ok {
		d.handlerGroups = append(d.handlerGroups, group)
		sort.Ints(d.handlerGroups)
	}
	d.handlers[group] = append(currHandlers, handler)
}
AddHandlerToGroup adds a handler to a specific group; lowest number will be processed first.
package ext
import (
	"encoding/json"
	"errors"
	"log"
	"runtime/debug"
	"sort"
	"sync"
	"github.com/PaulSonOfLars/gotgbot/v2"
)
const DefaultMaxRoutines = 50
type (
	DispatcherErrorHandler func(b *gotgbot.Bot, ctx *Context, err error) DispatcherAction
	DispatcherPanicHandler func(b *gotgbot.Bot, ctx *Context, stack []byte)
)
type DispatcherAction int64
const (
	DispatcherActionNoop DispatcherAction = iota
	DispatcherActionContinueGroups
	DispatcherActionEndGroups
)
var (
	EndGroups      = errors.New("group iteration ended")
	ContinueGroups = errors.New("group iteration continued")
)
type Dispatcher struct {
	Error DispatcherErrorHandler
	Panic DispatcherPanicHandler
	ErrorLog *log.Logger
	handlerGroups []int
	handlers map[int][]Handler
	updatesChan chan json.RawMessage
	limiter chan struct{}
	waitGroup sync.WaitGroup
}
type DispatcherOpts struct {
	Error DispatcherErrorHandler
	Panic DispatcherPanicHandler
	ErrorLog *log.Logger
	MaxRoutines int
}
func NewDispatcher(updates chan json.RawMessage, opts *DispatcherOpts) *Dispatcher {
	var limiter chan struct{}
	var errFunc DispatcherErrorHandler
	var panicFunc DispatcherPanicHandler
	maxRoutines := DefaultMaxRoutines
	errLog := errorLog
	if opts != nil {
		if opts.MaxRoutines != 0 {
			maxRoutines = opts.MaxRoutines
		}
		if opts.ErrorLog != nil {
			errLog = opts.ErrorLog
		}
		errFunc = opts.Error
		panicFunc = opts.Panic
	}
	if maxRoutines >= 0 {
		if maxRoutines == 0 {
			maxRoutines = DefaultMaxRoutines
		}
		limiter = make(chan struct{}, maxRoutines)
	}
	return &Dispatcher{
		Error:       errFunc,
		Panic:       panicFunc,
		ErrorLog:    errLog,
		updatesChan: updates,
		handlers:    make(map[int][]Handler),
		limiter:     limiter,
		waitGroup:   sync.WaitGroup{},
	}
}
func (d *Dispatcher) Start(b *gotgbot.Bot) {
	if d.limiter == nil {
		d.limitlessDispatcher(b)
		return
	}
	d.limitedDispatcher(b)
}
func (d *Dispatcher) Stop() {
	d.waitGroup.Wait()
}
func (d *Dispatcher) limitedDispatcher(b *gotgbot.Bot) {
	for upd := range d.updatesChan {
		d.waitGroup.Add(1)
		d.limiter <- struct{}{}
		go func(upd json.RawMessage) {
			d.ProcessRawUpdate(b, upd)
			<-d.limiter
			d.waitGroup.Done()
		}(upd)
	}
}
func (d *Dispatcher) limitlessDispatcher(b *gotgbot.Bot) {
	for upd := range d.updatesChan {
		d.waitGroup.Add(1)
		go func(upd json.RawMessage) {
			d.ProcessRawUpdate(b, upd)
			d.waitGroup.Done()
		}(upd)
	}
}
func (d *Dispatcher) AddHandler(handler Handler) {
	d.AddHandlerToGroup(handler, 0)
}