daemon_proto.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. package daemonproto
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "log"
  6. )
  7. /*
  8. #########################################################
  9. ######## PROTOCOL RELATED FUNCTIONS AND STRUCTS #########
  10. #########################################################
  11. */
  12. const SockMsgVers = 2
  13. const MESSAGE_RECIEVED = "MSG_RECV"
  14. const UNRESOLVEABLE = "UNRESOLVEABLE"
  15. const RequestOk = "OK"
  16. /*
  17. #################################
  18. ####### Protocol v2 area ########
  19. #################################
  20. */
  21. const VersionIdx = 0
  22. const StatusCodeIdx = 1
  23. const TypeInfoIdx = 2
  24. const BodyInfoIdx = 3
  25. const TargetInfoIdx = 11
  26. const MethodInfoIdx = 19
  27. const MsgHeaderEnd = 27
  28. const MsgRequest = "REQUEST"
  29. const MsgResponse = "RESPONSE"
  30. /*
  31. ################################
  32. ### Protocol v2 status codes ###
  33. ################################
  34. */
  35. const REQUEST_OK = 0
  36. const REQUEST_TIMEOUT = 1
  37. const REQUEST_FAILED = 2
  38. const REQUEST_UNAUTHORIZED = 3
  39. const REQUEST_ACCEPTED = 4
  40. const REQUEST_UNRESOLVED = 5
  41. /*
  42. ###############################
  43. ##### Protocol v2 methods #####
  44. ###############################
  45. */
  46. type Method string
  47. func MethodCheck(m string) (Method, error) {
  48. switch m {
  49. case "show":
  50. return SHOW, nil
  51. case "add":
  52. return ADD, nil
  53. case "delete":
  54. return DELETE, nil
  55. case "bootstrap":
  56. return BOOTSTRAP, nil
  57. case "reload":
  58. return RELOAD, nil
  59. case "poll":
  60. return POLL, nil
  61. case "run":
  62. return RUN, nil
  63. case "save":
  64. return SAVE, nil
  65. }
  66. return SHOW, &InvalidMethod{Method: m}
  67. }
  68. type InvalidMethod struct {
  69. Method string
  70. }
  71. func (i *InvalidMethod) Error() string {
  72. return "Invalid method passed: " + i.Method
  73. }
  74. const (
  75. SHOW Method = "show"
  76. ADD Method = "add"
  77. DELETE Method = "delete"
  78. BOOTSTRAP Method = "bootstrap"
  79. RELOAD Method = "reload"
  80. POLL Method = "poll"
  81. RUN Method = "run"
  82. SAVE Method = "save"
  83. )
  84. type SockMessage struct {
  85. Type string // the type of message being decoded
  86. TypeLen int8 // The length of the Type, used for convenience when Marshalling
  87. StatusMsg string // a string denoting what the output was, used in response messages
  88. StatusCode int8 // a status code that can be used to easily identify the type of error in response messages
  89. Version int8 `json:"version"` // This is a version header for failing fast
  90. Body []byte `json:"body"` // The body of a SockMessage SHOULD be json decodable, to allow for complex data to get sent over
  91. Target string `json:"target"` // This target 'route' for where this message should be sent. Think of this like an HTTP URI/path
  92. Method string `json:"method"` // This is the method that we will be executing on the target endpoint. Think of this like the HTTP method
  93. }
  94. func NewSockMessage(msgType string, statCode int8, body []byte) *SockMessage { // TODO: this function needs to be more versatile, and allow for additional more arguments
  95. return &SockMessage{Target: "",
  96. Method: "",
  97. Body: body,
  98. Version: SockMsgVers,
  99. Type: msgType,
  100. TypeLen: int8(len(msgType)),
  101. StatusCode: statCode,
  102. StatusMsg: RequestOk,
  103. }
  104. }
  105. /*
  106. Takes in a SockMessage struct and serializes it so that it can be sent over a socket, and then decoded as a SockMessage
  107. :param v: a SockMessage to serialize for transportation
  108. */
  109. func Marshal(v SockMessage) []byte { // TODO: Need to clean up the error handling here. This is really brittle. I just wanted to get it working
  110. msgHeader := []byte{}
  111. msgHeaderBuf := bytes.NewBuffer(msgHeader)
  112. preamble := []int8{
  113. SockMsgVers,
  114. v.StatusCode,
  115. v.TypeLen,
  116. }
  117. msgMeta := []int64{
  118. int64(len(v.Body)),
  119. int64(len(v.Target)),
  120. int64(len(v.Method)),
  121. }
  122. msgBody := [][]byte{
  123. []byte(v.Type),
  124. v.Body,
  125. []byte(v.Target),
  126. []byte(v.Method),
  127. }
  128. for i := range preamble {
  129. err := binary.Write(msgHeaderBuf, binary.LittleEndian, preamble[i])
  130. if err != nil {
  131. log.Fatal("Fatal error when writing: ", preamble[i], " into message header buffer.")
  132. }
  133. }
  134. for i := range msgMeta {
  135. err := binary.Write(msgHeaderBuf, binary.LittleEndian, msgMeta[i])
  136. if err != nil {
  137. log.Fatal("Fatal error when writing: ", msgMeta[i], " into message header buffer.")
  138. }
  139. }
  140. for i := range msgBody {
  141. _, err := msgHeaderBuf.Write(msgBody[i])
  142. if err != nil {
  143. log.Fatal("Fatal error when writing: ", msgBody[i], " into message header buffer.")
  144. }
  145. }
  146. return msgHeaderBuf.Bytes()
  147. }
  148. /*
  149. Unmarshalls a sock message byte array into a SockMessage struct, undoing what was done when Marshal() was called on the SockMessage
  150. :param msg: a byte array that can be unmarshalled into a SockMessage
  151. */
  152. func Unmarshal(msg []byte) SockMessage {
  153. vers := int8(msg[VersionIdx])
  154. statusCode := int8(msg[StatusCodeIdx])
  155. typeInfo := int(msg[TypeInfoIdx])
  156. bodyInfo := int(binary.LittleEndian.Uint64(msg[BodyInfoIdx:TargetInfoIdx]))
  157. targetInfo := int(binary.LittleEndian.Uint64(msg[TargetInfoIdx:MethodInfoIdx]))
  158. msgPayload := msg[MsgHeaderEnd:]
  159. body := msgPayload[typeInfo : typeInfo+bodyInfo]
  160. var msgInfo = []string{
  161. string(msgPayload[0:typeInfo]),
  162. string(msgPayload[(typeInfo + bodyInfo):(typeInfo + bodyInfo + targetInfo)]),
  163. string(msgPayload[(typeInfo + bodyInfo + targetInfo):]),
  164. }
  165. return SockMessage{
  166. Type: msgInfo[0],
  167. StatusCode: statusCode,
  168. StatusMsg: MESSAGE_RECIEVED,
  169. Version: vers,
  170. Body: body,
  171. Target: msgInfo[1],
  172. Method: msgInfo[2],
  173. }
  174. }