| /* |
| 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() |
| } |