blob: 83e1b17a83b0b5efdb630aaf1775f1db96be1b7c [file] [log] [blame]
/*
Copyright 2016 The Transicator Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package pgclient
import (
"bytes"
"encoding/binary"
)
var networkByteOrder = binary.BigEndian
/*
An OutputMessage represents a single message that is going to be sent to
the Postgres server. It will be prepended with a type byte and a four-byte
length.
*/
type OutputMessage struct {
buf *bytes.Buffer
msgType int
hasType bool
}
/*
NewOutputMessage constructs a new message with the given type byte
*/
func NewOutputMessage(msgType PgOutputType) *OutputMessage {
return &OutputMessage{
buf: &bytes.Buffer{},
msgType: int(msgType),
hasType: true,
}
}
/*
NewServerOutputMessage constructs a new message with the given type byte
*/
func NewServerOutputMessage(msgType PgInputType) *OutputMessage {
return &OutputMessage{
buf: &bytes.Buffer{},
msgType: int(msgType),
hasType: true,
}
}
/*
NewStartupMessage constructs a startup message, which has no type byte
*/
func NewStartupMessage() *OutputMessage {
return &OutputMessage{
buf: &bytes.Buffer{},
hasType: false,
}
}
/*
Type returns the message type byte from the message that was passed in to
the "NewOutputMessage" function.
*/
func (m *OutputMessage) Type() PgOutputType {
return PgOutputType(m.msgType)
}
/*
ServerType returns the message type byte from the message that was passed in to
the "NewOutputMessage" function if we're a server
*/
func (m *OutputMessage) ServerType() PgInputType {
return PgInputType(m.msgType)
}
/*
WriteInt64 writes a single "int64" to the output.
*/
func (m *OutputMessage) WriteInt64(i int64) {
err := binary.Write(m.buf, networkByteOrder, &i)
if err != nil {
panic(err.Error())
}
}
/*
WriteUint64 writes a single "uint64" to the output.
*/
func (m *OutputMessage) WriteUint64(i uint64) {
err := binary.Write(m.buf, networkByteOrder, &i)
if err != nil {
panic(err.Error())
}
}
/*
WriteInt32 writes a single "int32" to the output.
*/
func (m *OutputMessage) WriteInt32(i int32) {
err := binary.Write(m.buf, networkByteOrder, &i)
if err != nil {
panic(err.Error())
}
}
/*
WriteInt16 writes a single "int16" to the output.
*/
func (m *OutputMessage) WriteInt16(i int16) {
err := binary.Write(m.buf, networkByteOrder, &i)
if err != nil {
panic(err.Error())
}
}
/*
WriteByte writes a single byte to the output.
*/
func (m *OutputMessage) WriteByte(b byte) error {
return m.buf.WriteByte(b)
}
/*
WriteBytes writes a bunch of bytes to the output.
*/
func (m *OutputMessage) WriteBytes(b []byte) error {
_, err := m.buf.Write(b)
return err
}
/*
WriteString writes a single "string" to the output.
*/
func (m *OutputMessage) WriteString(s string) {
_, err := m.buf.WriteString(s)
if err != nil {
panic(err.Error())
}
err = m.buf.WriteByte(0)
if err != nil {
panic(err.Error())
}
}
/*
Encode returns a byte slice that represents the entire message, including
the header byte and length.
*/
func (m *OutputMessage) Encode() []byte {
var hdr *bytes.Buffer
if m.hasType {
hdr = bytes.NewBuffer(make([]byte, 5))
hdr.Reset()
hdr.WriteByte(byte(m.msgType))
} else {
hdr = bytes.NewBuffer(make([]byte, 4))
hdr.Reset()
}
bufLen := int32(m.buf.Len() + 4)
binary.Write(hdr, networkByteOrder, &bufLen)
return append(hdr.Bytes(), m.buf.Bytes()...)
}
/*
An InputMessage represents a message read from the server. It's understood
that we already read the type byte and also the four-byte length, and that
we are being given a slice to the data of the appropriate length for the
message.
*/
type InputMessage struct {
buf *bytes.Buffer
msgType int
}
/*
NewInputMessage generates a new input message from the specified byte array,
which must be the correct length for the message.
*/
func NewInputMessage(msgType PgInputType, b []byte) *InputMessage {
return &InputMessage{
buf: bytes.NewBuffer(b),
msgType: int(msgType),
}
}
/*
NewServerInputMessage generates a new input message from the specified byte array,
which must be the correct length for the message.
*/
func NewServerInputMessage(msgType PgOutputType, b []byte) *InputMessage {
return &InputMessage{
buf: bytes.NewBuffer(b),
msgType: int(msgType),
}
}
/*
Type returns the message type byte from the message that was passed in to
the "NewInputMessage" function.
*/
func (m *InputMessage) Type() PgInputType {
return PgInputType(m.msgType)
}
/*
ServerType returns the message type byte from the message that was passed in to
the "NewInputMessage" function when we're a server.
*/
func (m *InputMessage) ServerType() PgOutputType {
return PgOutputType(m.msgType)
}
/*
ReadInt64 reads a single int64 from the message and returns it.
*/
func (m *InputMessage) ReadInt64() (int64, error) {
var i int64
err := binary.Read(m.buf, networkByteOrder, &i)
if err == nil {
return i, nil
}
return 0, err
}
/*
ReadInt32 reads a single int32 from the message and returns it.
*/
func (m *InputMessage) ReadInt32() (int32, error) {
var i int32
err := binary.Read(m.buf, networkByteOrder, &i)
if err == nil {
return i, nil
}
return 0, err
}
/*
ReadInt16 reads a single int16 from the message and returns it.
*/
func (m *InputMessage) ReadInt16() (int16, error) {
var i int16
err := binary.Read(m.buf, networkByteOrder, &i)
if err == nil {
return i, nil
}
return 0, err
}
/*
ReadInt8 reads a single int8 from the message and returns it.
*/
func (m *InputMessage) ReadInt8() (int8, error) {
var i int8
err := binary.Read(m.buf, networkByteOrder, &i)
if err == nil {
return i, nil
}
return 0, err
}
/*
ReadString reads a single null-terminated string form the message and
returns it.
*/
func (m *InputMessage) ReadString() (string, error) {
asc, err := m.buf.ReadBytes(0)
if err != nil {
return "", err
}
return string(asc[:len(asc)-1]), nil
}
/*
ReadByte reads a single byte.
*/
func (m *InputMessage) ReadByte() (byte, error) {
b, err := m.buf.ReadByte()
if err != nil {
return 0, err
}
return b, nil
}
/*
ReadBytes reads a count of bytes.
*/
func (m *InputMessage) ReadBytes(n int) ([]byte, error) {
buf := make([]byte, n)
_, err := m.buf.Read(buf)
if err != nil {
return nil, err
}
return buf, nil
}
/*
ReadRemaining reads everything that is left in the message.
*/
func (m *InputMessage) ReadRemaining() []byte {
return m.buf.Bytes()
}