command.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  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. if err := json.NewDecoder(bytes.NewReader(data)).Decode(copy); err != nil {
  50. return nil, err
  51. }
  52. }
  53. }
  54. return copy, nil
  55. }
  56. // Registers a command by storing a reference to an instance of it.
  57. func RegisterCommand(command Command) {
  58. if command == nil {
  59. panic(fmt.Sprintf("raft: Cannot register nil"))
  60. } else if commandTypes[command.CommandName()] != nil {
  61. panic(fmt.Sprintf("raft: Duplicate registration: %s", command.CommandName()))
  62. }
  63. commandTypes[command.CommandName()] = command
  64. }