@@ 21,6 21,7 @@ const (
type Client struct {
net.Conn
queue commQueue
+ sendmutex sync.Mutex
}
func NewClient(addr string) (c *Client, err error) {
@@ 39,32 40,43 @@ func NewClient(addr string) (c *Client,
}
func (c *Client) Auth(data string) (<-chan error) {
- _, errch := c.writeCommand(AUTH_ID, SERVERDATA_AUTH, []byte(data))
+ _, errch := c.sendCmd(AUTH_ID, SERVERDATA_AUTH, []byte(data))
return errch
}
func (c *Client) Exec(data string) (<-chan *Message, <-chan error) {
- return c.writeCommand(EXEC_ID, SERVERDATA_EXECCOMMAND, []byte(data))
+ return c.sendCmd(EXEC_ID, SERVERDATA_EXECCOMMAND, []byte(data))
}
-func (c *Client) writeCommand(id int32, cmdtype CmdType, body []byte) (<-chan *Message, <-chan error) {
+func (c *Client) sendCmd(id int32, cmdtype CmdType, body []byte) (<-chan *Message, <-chan error) {
msgch := make(chan *Message, 1) // Keep these async
errch := make(chan error, 1)
+ c.sendmutex.Lock()
+ defer c.sendmutex.Unlock()
if err := writeCommand(c, id, cmdtype, body); err != nil {
errch <- err
//close(msgch)
- } else {
- c.queue.Push(&comm{msgch, errch})
+ return msgch, errch
+ }
+ c.queue.Push(&comm{msgch, errch})
+ if id == EXEC_ID {
+ // Also send a terminal packet (this seems like a not great place to put this?)
+ if err := writeCommand(c, TERM_ID, cmdtype, []byte{}); err != nil {
+ // We have to panic here
+ // We can't simply remove msg from the queue since readLoop() may
+ // or may not have started writing to it already
+ panic(err)
+ }
}
return msgch, errch
}
func (c *Client) readLoop() {
+ var current *Message
r := bufio.NewReader(c)
for {
- resp, err := readResp(r)
- log.Printf("<<< %+v / %v\n", resp, err)
- // TODO, implement terminal packets
+ pack, err := readResp(r)
+ log.Printf("<<< %+v / %v\n", pack, err)
comm := c.queue.Peek()
if comm == nil {
log.Panicln("u maek le bug uheuheuheh")
@@ 76,26 88,38 @@ func (c *Client) readLoop() {
}
comm.errch <- err
}
- if (resp.Id == AUTH_ID || resp.Id == -1) && resp.Type == SERVERDATA_AUTH_RESPONSE {
+ // TODO a switch may be more readable
+ if (pack.Id == AUTH_ID || pack.Id == -1) && pack.Type == SERVERDATA_AUTH_RESPONSE {
// Packet two of two of response to auth request
log.Println("Received two of two of responses to auth request")
c.queue.Pop()
- if resp.Id == AUTH_ID {
+ if pack.Id == AUTH_ID {
comm.errch <- nil
} else {
comm.errch <- fmt.Errorf("Authentication Failed")
}
//close(comm.msgch)
- } else if resp.Id == AUTH_ID && resp.Type == SERVERDATA_RESPONSE_VALUE {
+ } else if pack.Id == AUTH_ID && pack.Type == SERVERDATA_RESPONSE_VALUE {
// Packet one of two of response to auth request
log.Println("Received one of two of responses to auth request")
continue
- } else if (resp.Id & EXEC_ID|TERM_ID != 0) && (resp.Type == SERVERDATA_RESPONSE_VALUE) {
+ } else if (pack.Id == EXEC_ID) && (pack.Type == SERVERDATA_RESPONSE_VALUE) {
+ // Response to an exec packet
log.Println("Received response to exec request")
+ if current == nil {
+ current = &Message{pack.Body}
+ } else {
+ current.Contents = append(current.Contents, pack.Body...)
+ }
+ } else if (pack.Id == TERM_ID) && (pack.Type == SERVERDATA_RESPONSE_VALUE) {
+ // Terminal response to an exec packet
+ log.Println("Received terminal response")
+ comm.msgch <- current
c.queue.Pop()
- comm.msgch <- &Message{[]*packet{resp}}
+ current = nil
//close(comm.errch)
} else {
+ // Some other case that we don't handle properly
log.Println("Received ... fuck if I know ... I'm likely going to crash and burn!")
c.queue.Pop()
}
@@ 106,14 130,7 @@ func (c *Client) readLoop() {
// This needs help ...
type Message struct {
- packets []*packet
-}
-
-func (m *Message) AllText() (s string) {
- for _, p := range m.packets {
- s += string(p.Body)
- }
- return
+ Contents []byte
}
////////////////////////////////////////////////////////////////////////////////
@@ 60,8 60,7 @@ func main() {
msgch, errch := client.Exec(inp)
select {
case msg := <-msgch:
- log.Println(msg)
- log.Print(string(msg.AllText()))
+ log.Print(string(msg.Contents))
case err := <-errch:
log.Panicln(err)
}