command.go 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. package raft
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "reflect"
  8. )
  9. var commandTypes map[string]Command
  10. func init() {
  11. commandTypes = map[string]Command{}
  12. }
  13. // Command represents an action to be taken on the replicated state machine.
  14. type Command interface {
  15. CommandName() string
  16. }
  17. // CommandApply represents the interface to apply a command to the server.
  18. type CommandApply interface {
  19. Apply(Context) (interface{}, error)
  20. }
  21. // deprecatedCommandApply represents the old interface to apply a command to the server.
  22. type deprecatedCommandApply interface {
  23. Apply(Server) (interface{}, error)
  24. }
  25. type CommandEncoder interface {
  26. Encode(w io.Writer) error
  27. Decode(r io.Reader) error
  28. }
  29. // Creates a new instance of a command by name.
  30. func newCommand(name string, data []byte) (Command, error) {
  31. // Find the registered command.
  32. command := commandTypes[name]
  33. if command == nil {
  34. return nil, fmt.Errorf("raft.Command: Unregistered command type: %s", name)
  35. }
  36. // Make a copy of the command.
  37. v := reflect.New(reflect.Indirect(reflect.ValueOf(command)).Type()).Interface()
  38. copy, ok := v.(Command)
  39. if !ok {
  40. panic(fmt.Sprintf("raft: Unable to copy command: %s (%v)", command.CommandName(), reflect.ValueOf(v).Kind().String()))
  41. }
  42. // If data for the command was passed in the decode it.
  43. if data != nil {
  44. if encoder, ok := copy.(CommandEncoder); ok {
  45. if err := encoder.Decode(bytes.NewReader(data)); err != nil {
  46. return nil, err
  47. }
  48. } else {
  49. json.NewDecoder(bytes.NewReader(data)).Decode(copy)
  50. }
  51. }
  52. return copy, nil
  53. }
  54. // Registers a command by storing a reference to an instance of it.
  55. func RegisterCommand(command Command) {
  56. if command == nil {
  57. panic(fmt.Sprintf("raft: Cannot register nil"))
  58. } else if commandTypes[command.CommandName()] != nil {
  59. panic(fmt.Sprintf("raft: Duplicate registration: %s", command.CommandName()))
  60. }
  61. commandTypes[command.CommandName()] = command
  62. }