hnakra/protocol/login.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)
}