func doReceive( uprconn *uprConnection, host string, msgch chan msgT, killSwitch chan bool) { var hdr [mcd.HDR_LEN]byte var msg msgT var pkt mcd.MCRequest var err error mcconn := uprconn.conn.Hijack() loop: for { if _, err = pkt.Receive(mcconn, hdr[:]); err != nil { msg = msgT{uprconn: uprconn, err: err} } else { msg = msgT{uprconn: uprconn, pkt: pkt} } select { case msgch <- msg: case <-killSwitch: break loop } } return }
// Internal goroutine that reads from the socket and writes events to // the channel func (mc *Client) runFeed(ch chan TapEvent, feed *TapFeed) { defer close(ch) var headerBuf [gomemcached.HDR_LEN]byte loop: for { // Read the next request from the server. // // (Can't call mc.Receive() because it reads a // _response_ not a request.) var pkt gomemcached.MCRequest n, err := pkt.Receive(mc.conn, headerBuf[:]) if TapRecvHook != nil { TapRecvHook(&pkt, n, err) } if err != nil { if err != io.EOF { feed.Error = err } break loop } //log.Printf("** TapFeed received %#v : %q", pkt, pkt.Body) if pkt.Opcode == gomemcached.TAP_CONNECT { // This is not an event from the server; it's // an error response to my connect request. feed.Error = fmt.Errorf("tap connection failed: %s", pkt.Body) break loop } event := makeTapEvent(pkt) if event != nil { if event.Opcode == tapEndStream { break loop } select { case ch <- *event: case <-feed.closer: break loop } } if len(pkt.Extras) >= 4 { reqFlags := binary.BigEndian.Uint16(pkt.Extras[2:]) if reqFlags&gomemcached.TAP_ACK != 0 { if _, err := mc.sendAck(&pkt); err != nil { feed.Error = err break loop } } } } if err := mc.Close(); err != nil { log.Printf("Error closing memcached client: %v", err) } }