package protocol import "io" import "fmt" // Status is an 8-bit code that routers and services can send to each-other to // inform the other about issues (or lack thereof) with the last recieved // message in a given sequence. This is not to be confused with an HTTP status // code. type Status uint8; const ( StatusOk Status = iota StatusBadMessageType StatusMalformedMessage StatusBadVersion StatusBadCredentials StatusBadMount ) // ReadStatus reads a Status code from a Reader. func ReadStatus (reader io.Reader) (status Status, err error) { untyped, err := ReadU8(reader) return Status(untyped), err } // Serialize writes a Status code to a Writer. func (status Status) Serialize (writer io.Writer) error { return WriteU8(writer, uint8(status)) } // String returns a human-readable representation of a status code. func (status Status) String () string { switch status { case StatusOk: return "ok" case StatusBadMessageType: return "invalid message type" case StatusMalformedMessage: return "malformed message" case StatusBadVersion: return "unsupported protocol version" case StatusBadCredentials: return "invalid credentials" case StatusBadMount: return "invalid mount" } return fmt.Sprintf("Status(%d)", status) } // Error is equivalent to String. This lets a status be returned as an error. func (status Status) Error () string { return status.String() } // Version represents a Hnakra protocol version. type Version struct { Major uint8 Minor uint8 } // ReadVersion reads version information from a Reader. func ReadVersion (reader io.Reader) (version Version, err error) { version.Major, err = ReadU8(reader) if err != nil { return } version.Minor, err = ReadU8(reader) return } // Serialize writes version information to a Writer. func (version Version) Serialize (writer io.Writer) error { err := WriteU8(writer, uint8(version.Major)) if err != nil { return err } return WriteU8(writer, uint8(version.Minor)) } // String returns a human-readable representation of a version. func (version Version) String () string { return fmt.Sprintf("%d.%d", version.Major, version.Minor) } // MessageLogin is a message sent to a router by a service requesting to log in // and mount on a path. The service should not send anything before this // message. The router must reply with a MessageStatus containing StatusOk if // the login and mount suceeded. or some other code if it did not. While waiting // for this message to be sent, the service should not send anything. type MessageLogin struct { ID Version User string Key []byte Name string Description string Scheme string Host string Path string } // ReadMessageLogin reads a login message from a Reader, starting after the type // code. func ReadMessageLogin (reader io.Reader) (message MessageLogin, err error) { message.ID, err = ReadID(reader) if err != nil { return } message.Version, err = ReadVersion(reader) if err != nil { return } message.User, err = ReadString8(reader) if err != nil { return } message.Key, err = ReadBuf8(reader) if err != nil { return } message.Name, err = ReadString8(reader) if err != nil { return } message.Description, err = ReadString8(reader) if err != nil { return } message.Scheme, err = ReadString8(reader) if err != nil { return } message.Host, err = ReadString16(reader) if err != nil { return } message.Path, err = ReadString16(reader) return } // Serialize writes the login message to a Writer, starting after the type code. func (message MessageLogin) Serialize (writer io.Writer) (err error) { err = message.ID.Serialize(writer) if err != nil { return } err = message.Version.Serialize(writer) if err != nil { return } err = WriteString8(writer, message.User) if err != nil { return } err = WriteBuf8(writer, message.Key) if err != nil { return } err = WriteString8(writer, message.Name) if err != nil { return } err = WriteString8(writer, message.Description) if err != nil { return } err = WriteString8(writer, message.Scheme) if err != nil { return } err = WriteString16(writer, message.Host) if err != nil { return } err = WriteString16(writer, message.Path) return } // Send writes the type code and the message to a Writer. func (message MessageLogin) Send (writer io.Writer) (err error) { err = TypeLogin.Serialize(writer) if err != nil { return } return message.Serialize(writer) } // MessageStatus is a message that carries a Status code. If sent, it must be in // reply to the last recieved message with an equivalent ID. type MessageStatus struct { ID Status } // ReadMessageStatus reads a status message from a Reader, starting after the // type code. func ReadMessageStatus (reader io.Reader) (message MessageStatus, err error) { message.ID, err = ReadID(reader) if err != nil { return } message.Status, err = ReadStatus(reader) return } // Serialize writes the status message to a Writer, starting after the type // code. func (message MessageStatus) Serialize (writer io.Writer) (err error) { err = message.ID.Serialize(writer) if err != nil { return } return message.Status.Serialize(writer) } // Send writes the type code and the message to a Writer. func (message MessageStatus) Send (writer io.Writer) (err error) { err = TypeStatus.Serialize(writer) if err != nil { return } return message.Serialize(writer) }