123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- package daemonproto
- import (
- "bytes"
- "encoding/binary"
- "log"
- )
- /*
- #########################################################
- ######## PROTOCOL RELATED FUNCTIONS AND STRUCTS #########
- #########################################################
- */
- const SockMsgVers = 2
- const MESSAGE_RECIEVED = "MSG_RECV"
- const UNRESOLVEABLE = "UNRESOLVEABLE"
- const RequestOk = "OK"
- /*
- #################################
- ####### Protocol v2 area ########
- #################################
- */
- const VersionIdx = 0
- const StatusCodeIdx = 1
- const TypeInfoIdx = 2
- const BodyInfoIdx = 3
- const TargetInfoIdx = 11
- const MethodInfoIdx = 19
- const MsgHeaderEnd = 27
- const MsgRequest = "REQUEST"
- const MsgResponse = "RESPONSE"
- /*
- ################################
- ### Protocol v2 status codes ###
- ################################
- */
- const REQUEST_OK = 0
- const REQUEST_TIMEOUT = 1
- const REQUEST_FAILED = 2
- const REQUEST_UNAUTHORIZED = 3
- const REQUEST_ACCEPTED = 4
- const REQUEST_UNRESOLVED = 5
- /*
- ###############################
- ##### Protocol v2 methods #####
- ###############################
- */
- type Method string
- func MethodCheck(m string) (Method, error) {
- switch m {
- case "show":
- return SHOW, nil
- case "add":
- return ADD, nil
- case "delete":
- return DELETE, nil
- case "bootstrap":
- return BOOTSTRAP, nil
- case "reload":
- return RELOAD, nil
- case "poll":
- return POLL, nil
- case "run":
- return RUN, nil
- case "save":
- return SAVE, nil
- }
- return SHOW, &InvalidMethod{Method: m}
- }
- type InvalidMethod struct {
- Method string
- }
- func (i *InvalidMethod) Error() string {
- return "Invalid method passed: " + i.Method
- }
- const (
- SHOW Method = "show"
- ADD Method = "add"
- DELETE Method = "delete"
- BOOTSTRAP Method = "bootstrap"
- RELOAD Method = "reload"
- POLL Method = "poll"
- RUN Method = "run"
- SAVE Method = "save"
- )
- type SockMessage struct {
- Type string // the type of message being decoded
- TypeLen int8 // The length of the Type, used for convenience when Marshalling
- StatusMsg string // a string denoting what the output was, used in response messages
- StatusCode int8 // a status code that can be used to easily identify the type of error in response messages
- Version int8 `json:"version"` // This is a version header for failing fast
- Body []byte `json:"body"` // The body of a SockMessage SHOULD be json decodable, to allow for complex data to get sent over
- Target string `json:"target"` // This target 'route' for where this message should be sent. Think of this like an HTTP URI/path
- Method string `json:"method"` // This is the method that we will be executing on the target endpoint. Think of this like the HTTP method
- }
- func NewSockMessage(msgType string, statCode int8, body []byte) *SockMessage { // TODO: this function needs to be more versatile, and allow for additional more arguments
- return &SockMessage{Target: "",
- Method: "",
- Body: body,
- Version: SockMsgVers,
- Type: msgType,
- TypeLen: int8(len(msgType)),
- StatusCode: statCode,
- StatusMsg: RequestOk,
- }
- }
- /*
- Takes in a SockMessage struct and serializes it so that it can be sent over a socket, and then decoded as a SockMessage
- :param v: a SockMessage to serialize for transportation
- */
- 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
- msgHeader := []byte{}
- msgHeaderBuf := bytes.NewBuffer(msgHeader)
- preamble := []int8{
- SockMsgVers,
- v.StatusCode,
- v.TypeLen,
- }
- msgMeta := []int64{
- int64(len(v.Body)),
- int64(len(v.Target)),
- int64(len(v.Method)),
- }
- msgBody := [][]byte{
- []byte(v.Type),
- v.Body,
- []byte(v.Target),
- []byte(v.Method),
- }
- for i := range preamble {
- err := binary.Write(msgHeaderBuf, binary.LittleEndian, preamble[i])
- if err != nil {
- log.Fatal("Fatal error when writing: ", preamble[i], " into message header buffer.")
- }
- }
- for i := range msgMeta {
- err := binary.Write(msgHeaderBuf, binary.LittleEndian, msgMeta[i])
- if err != nil {
- log.Fatal("Fatal error when writing: ", msgMeta[i], " into message header buffer.")
- }
- }
- for i := range msgBody {
- _, err := msgHeaderBuf.Write(msgBody[i])
- if err != nil {
- log.Fatal("Fatal error when writing: ", msgBody[i], " into message header buffer.")
- }
- }
- return msgHeaderBuf.Bytes()
- }
- /*
- Unmarshalls a sock message byte array into a SockMessage struct, undoing what was done when Marshal() was called on the SockMessage
- :param msg: a byte array that can be unmarshalled into a SockMessage
- */
- func Unmarshal(msg []byte) SockMessage {
- vers := int8(msg[VersionIdx])
- statusCode := int8(msg[StatusCodeIdx])
- typeInfo := int(msg[TypeInfoIdx])
- bodyInfo := int(binary.LittleEndian.Uint64(msg[BodyInfoIdx:TargetInfoIdx]))
- targetInfo := int(binary.LittleEndian.Uint64(msg[TargetInfoIdx:MethodInfoIdx]))
- msgPayload := msg[MsgHeaderEnd:]
- body := msgPayload[typeInfo : typeInfo+bodyInfo]
- var msgInfo = []string{
- string(msgPayload[0:typeInfo]),
- string(msgPayload[(typeInfo + bodyInfo):(typeInfo + bodyInfo + targetInfo)]),
- string(msgPayload[(typeInfo + bodyInfo + targetInfo):]),
- }
- return SockMessage{
- Type: msgInfo[0],
- StatusCode: statusCode,
- StatusMsg: MESSAGE_RECIEVED,
- Version: vers,
- Body: body,
- Target: msgInfo[1],
- Method: msgInfo[2],
- }
- }
|