175 lines
5.3 KiB
Go
175 lines
5.3 KiB
Go
|
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)
|
||
|
}
|