/ dispatcher.go
dispatcher.go
1 package dispatch2 2 3 import ( 4 "context" 5 "fmt" 6 ) 7 8 type Dispatcher[Config any] interface { 9 After(middlewares ...MiddlewareFunc[Config]) 10 Before(middlewares ...MiddlewareFunc[Config]) 11 Commands() []Command[Config] 12 Config() *Config 13 Dispatch(context.Context, []string) error 14 Register(name, synopsis, usage string, aliases []string, executer Executer[Config]) error 15 RegisterCommand(Command[Config]) error 16 RegisterFunc(name, synopsis, usage string, aliases []string, executer ExecuterFunc[Config]) error 17 } 18 19 type dispatcher[Config any] struct { 20 afterMiddlewares []MiddlewareFunc[Config] 21 beforeMiddlewares []MiddlewareFunc[Config] 22 commands []Command[Config] 23 config Config 24 } 25 26 var _ Dispatcher[struct{}] = &dispatcher[struct{}]{} 27 28 func NewDispatcher[Config any]() *dispatcher[Config] { 29 return &dispatcher[Config]{} 30 } 31 32 func (d *dispatcher[Config]) After(middlewares ...MiddlewareFunc[Config]) { 33 for _, m := range middlewares { 34 d.afterMiddlewares = append(d.afterMiddlewares, invertMiddleware(m)) 35 } 36 } 37 38 func (d *dispatcher[Config]) Before(middlewares ...MiddlewareFunc[Config]) { 39 d.beforeMiddlewares = append(d.beforeMiddlewares, middlewares...) 40 } 41 42 func (d *dispatcher[Config]) Config() *Config { 43 return &d.config 44 } 45 46 func (d *dispatcher[Config]) Commands() []Command[Config] { 47 return d.commands 48 } 49 50 func (d *dispatcher[Config]) Dispatch(ctx context.Context, args []string) error { 51 select { 52 case <-ctx.Done(): 53 return ctx.Err() 54 default: 55 cmd, argsLeft, err := d.parseArgsForSubcommand(args) 56 if err != nil { 57 return err 58 } 59 60 if cmd == nil { 61 return fmt.Errorf("dispatch: command is nil") 62 } 63 64 if cmd.Executer() == nil { 65 return fmt.Errorf("dispatch: command has nil executer") 66 } 67 68 wrappedCmd := WrapExecuter(cmd) 69 if wrappedCmd == nil { 70 return fmt.Errorf("command: cannot execute nil executer") 71 } 72 73 // Apply AFTER middlewares (registration order, inverted) 74 for _, middleware := range d.afterMiddlewares { 75 wrappedCmd = middleware(wrappedCmd) 76 } 77 78 // Before middlewares: (reverse order) 79 for i := len(d.beforeMiddlewares) - 1; i >= 0; i-- { 80 wrappedCmd = d.beforeMiddlewares[i](wrappedCmd) 81 } 82 83 return wrappedCmd.Execute(ctx, d.Config(), argsLeft) 84 } 85 } 86 87 func (d *dispatcher[Config]) RegisterCommand(commands Command[Config]) error { 88 d.commands = append(d.commands, commands) 89 //TODO check if name or alias is taken 90 return nil 91 } 92 93 func (d *dispatcher[Config]) Register(name, synopsis, usage string, aliases []string, executer Executer[Config]) error { 94 return d.RegisterCommand(NewCommand(name, synopsis, usage, aliases, executer)) 95 } 96 97 func (d *dispatcher[Config]) RegisterFunc(name, synopsis, usage string, aliases []string, executerFunc ExecuterFunc[Config]) error { 98 return d.RegisterCommand(NewCommand(name, synopsis, usage, aliases, executerFunc)) 99 } 100 101 // unexported 102 103 func (d *dispatcher[Config]) parseArgsForSubcommand(args []string) (Command[Config], []string, error) { 104 return parseArgsForSubcommand(d.commands, args) 105 }