From 226142ae1b0adeeaa7edab858ce768063a1f6e22 Mon Sep 17 00:00:00 2001
From: Jack Christensen <jack@jackchristensen.com>
Date: Sat, 30 Mar 2013 19:57:37 -0500
Subject: [PATCH] Added rxMsg*

---
 conn.go     | 76 +++++++++++++++++++++++++++++++++++++++++++++++------
 messages.go |  4 +++
 2 files changed, 72 insertions(+), 8 deletions(-)

diff --git a/conn.go b/conn.go
index 0a582541..f3716451 100644
--- a/conn.go
+++ b/conn.go
@@ -2,11 +2,15 @@ package pqx
 
 import (
 	"encoding/binary"
+	"errors"
+	"fmt"
+	"io"
 	"net"
 )
 
 type conn struct {
-	conn net.Conn
+	conn net.Conn // the underlying TCP or unix domain socket connection
+	buf  []byte   // work buffer to avoid constant alloc and dealloc
 }
 
 func Connect(options map[string]string) (c *conn, err error) {
@@ -22,19 +26,75 @@ func Connect(options map[string]string) (c *conn, err error) {
 		}
 	}
 
+	c.buf = make([]byte, 1024)
+
 	// conn, err := net.Dial("tcp", "localhost:5432")
 
 	msg := newStartupMessage()
 	msg.options["user"] = "jack"
 	c.conn.Write(msg.Bytes())
 
-	buf := make([]byte, 512)
-
-	num, _ := c.conn.Read(buf)
-	println(string(buf[0:1]))
-	println(binary.BigEndian.Uint32(buf[1:5]))
-	println(binary.BigEndian.Uint32(buf[5:9]))
-	println(num)
+	var response interface{}
+	response, err = c.rxMsg()
+	fmt.Println(err)
+	fmt.Println(response)
 
 	return c, nil
 }
+
+func (c *conn) rxMsg() (msg interface{}, err error) {
+	var t byte
+	var bodySize int32
+	t, bodySize, err = c.rxMsgHeader()
+	if err != nil {
+		return nil, err
+	}
+
+	var buf []byte
+	if buf, err = c.rxMsgBody(bodySize); err != nil {
+		return nil, err
+	}
+
+	switch t {
+	case 'R':
+		return c.rxAuthenticationX(buf)
+	default:
+		return nil, errors.New("Received unknown message type")
+	}
+
+	panic("Unreachable")
+}
+
+func (c *conn) rxMsgHeader() (t byte, bodySize int32, err error) {
+	buf := c.buf[:5]
+	if _, err = io.ReadFull(c.conn, buf); err != nil {
+		return 0, 0, err
+	}
+
+	t = buf[0]
+	bodySize = int32(binary.BigEndian.Uint32(buf[1:5])) - 4
+	return t, bodySize, nil
+}
+
+func (c *conn) rxMsgBody(bodySize int32) (buf []byte, err error) {
+	if int(bodySize) <= cap(c.buf) {
+		buf = c.buf[:bodySize]
+	} else {
+		buf = make([]byte, bodySize)
+	}
+
+	_, err = io.ReadFull(c.conn, buf)
+	return
+}
+
+func (c *conn) rxAuthenticationX(buf []byte) (msg interface{}, err error) {
+	code := binary.BigEndian.Uint32(buf[:4])
+	switch code {
+	case 0:
+		return &authenticationOk{}, nil
+	default:
+		return nil, errors.New("Received unknown authentication message")
+	}
+
+	panic("Unreachable")
+}
diff --git a/messages.go b/messages.go
index b6e6f907..0ecb9bed 100644
--- a/messages.go
+++ b/messages.go
@@ -32,3 +32,7 @@ func (self *startupMessage) Bytes() (buf []byte) {
 
 type authenticationOk struct {
 }
+
+func (self *authenticationOk) String() string {
+	return "AuthenticationOk"
+}