Merge pull request #4 from leif/RawLines
make ReadResponse public, and add RawLines
This commit is contained in:
commit
2d65b370c8
14
conn.go
14
conn.go
|
@ -66,7 +66,7 @@ func (c *Conn) isAsyncReaderRunning() bool {
|
|||
|
||||
func (c *Conn) asyncReader() {
|
||||
for {
|
||||
resp, err := c.readResponse()
|
||||
resp, err := c.ReadResponse()
|
||||
if err != nil {
|
||||
c.setRdErr(err, false)
|
||||
break
|
||||
|
@ -107,7 +107,7 @@ func (c *Conn) Close() error {
|
|||
|
||||
// StartAsyncReader starts the asynchronous reader go routine that allows
|
||||
// asynchronous events to be handled. It must not be called simultaniously
|
||||
// with Request or undefined behavior will occur.
|
||||
// with Read, Request, or ReadResponse or undefined behavior will occur.
|
||||
func (c *Conn) StartAsyncReader() {
|
||||
c.asyncReaderLock.Lock()
|
||||
defer c.asyncReaderLock.Unlock()
|
||||
|
@ -145,8 +145,9 @@ func (c *Conn) NextEvent() (*Response, error) {
|
|||
|
||||
// Request sends a raw control port request and returns the response.
|
||||
// If the async. reader is not currently running, events received while waiting
|
||||
// for the response will be silently dropped. Calling StartAsyncReader
|
||||
// simultaniously with Request will lead to undefined behavior.
|
||||
// for the response will be silently dropped. Calling Request simultaniously
|
||||
// with StartAsyncReader, Read, Write, or ReadResponse will lead to undefined
|
||||
// behavior.
|
||||
func (c *Conn) Request(fmt string, args ...interface{}) (*Response, error) {
|
||||
if err := c.getRdErr(); err != nil {
|
||||
return nil, err
|
||||
|
@ -175,7 +176,7 @@ func (c *Conn) Request(fmt string, args ...interface{}) (*Response, error) {
|
|||
// Event handing requires the asyncReader() goroutine, try to get a
|
||||
// response, while silently swallowing events.
|
||||
for resp == nil || resp.IsAsync() {
|
||||
resp, err = c.readResponse()
|
||||
resp, err = c.ReadResponse()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -191,7 +192,8 @@ func (c *Conn) Request(fmt string, args ...interface{}) (*Response, error) {
|
|||
}
|
||||
|
||||
// Read reads directly from the control port connection. Mixing this call
|
||||
// with Request, or asynchronous events will lead to undefined behavior.
|
||||
// with Request, ReadResponse, or asynchronous events will lead to undefined
|
||||
// behavior.
|
||||
func (c *Conn) Read(p []byte) (int, error) {
|
||||
return c.conn.R.Read(p)
|
||||
}
|
||||
|
|
20
response.go
20
response.go
|
@ -11,6 +11,7 @@ import (
|
|||
"log"
|
||||
"net/textproto"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Response is a response to a control port command, or an asyncrhonous event.
|
||||
|
@ -27,6 +28,9 @@ type Response struct {
|
|||
// data is "decoded" and presented as a single string (terminal ".CRLF"
|
||||
// removed, all intervening CRs stripped).
|
||||
Data []string
|
||||
|
||||
// RawLines is all of the lines of a response, without CRLFs.
|
||||
RawLines []string
|
||||
}
|
||||
|
||||
// IsOk returns true if the response status code indicates success or
|
||||
|
@ -45,7 +49,10 @@ func (r *Response) IsAsync() bool {
|
|||
return r.Err.Code == StatusAsyncEvent
|
||||
}
|
||||
|
||||
func (c *Conn) readResponse() (*Response, error) {
|
||||
// ReadResponse returns the next response object. Calling this
|
||||
// simultaniously with Read, Request, or StartAsyncReader will lead to
|
||||
// undefined behavior
|
||||
func (c *Conn) ReadResponse() (*Response, error) {
|
||||
var resp *Response
|
||||
var statusCode int
|
||||
for {
|
||||
|
@ -74,11 +81,15 @@ func (c *Conn) readResponse() (*Response, error) {
|
|||
// lines.
|
||||
return nil, newProtocolError("status code changed: %03d != %03d", code, statusCode)
|
||||
}
|
||||
if resp.RawLines == nil {
|
||||
resp.RawLines = make([]string, 0, 1)
|
||||
}
|
||||
|
||||
if line[3] == ' ' {
|
||||
// Final line in the response.
|
||||
resp.Reply = line[4:]
|
||||
resp.Err = statusCodeToError(statusCode, resp.Reply)
|
||||
resp.RawLines = append(resp.RawLines, line)
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
|
@ -89,9 +100,11 @@ func (c *Conn) readResponse() (*Response, error) {
|
|||
case '-':
|
||||
// Continuation, keep reading.
|
||||
resp.Data = append(resp.Data, line[4:])
|
||||
resp.RawLines = append(resp.RawLines, line)
|
||||
case '+':
|
||||
// A "dot-encoded" payload follows.
|
||||
resp.Data = append(resp.Data, line[4:])
|
||||
resp.RawLines = append(resp.RawLines, line)
|
||||
dotBody, err := c.conn.ReadDotBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -100,6 +113,11 @@ func (c *Conn) readResponse() (*Response, error) {
|
|||
log.Printf("S: [dot encoded data]")
|
||||
}
|
||||
resp.Data = append(resp.Data, string(dotBody))
|
||||
dotLines := strings.Split(string(dotBody), "\n")
|
||||
for _, dotLine := range dotLines[:len(dotLines)-1] {
|
||||
resp.RawLines = append(resp.RawLines, dotLine)
|
||||
}
|
||||
resp.RawLines = append(resp.RawLines, ".")
|
||||
default:
|
||||
return nil, newProtocolError("invalid separator: '%c'", line[3])
|
||||
}
|
||||
|
|
Reference in New Issue