func Connect(target string) (Client, error) { conn, err := net.Dial("tcp", target) if err != nil { return nil, err } // hanshake _, cmd, _, err := network.Receive(conn) if err != nil { return nil, err } ch := make(chan PendingOperation) c := &NetworkClient{connectionId: *cmd.Header.ConnectionID, userId: USER_ID, secret: CLIENT_SECRET, sequence: 1, conn: conn, closed: false, error: nil, notifier: ch} go c.listen(ch) return c, nil }
func (self *NetworkClient) listen(notifications <-chan PendingOperation) { pending := make(map[int64]PendingOperation) // pendings for { _, cmd, _, err := network.Receive(self.conn) if err != nil { if !self.closed { self.error = err // TODO: try closing socket } break } var response error if *cmd.Status.Code != kproto.Command_Status_SUCCESS { response = RemoteError{status: *cmd.Status} } // Notify caller // Seems more complicated than it should, but we are optimizing // for when we receive in order for { op := <-notifications // Chances are, it's in order if op.sequence == *cmd.Header.AckSequence { op.receiver <- response // TODO: send back the actual response break } else { // Either we missed it or it hasnt arrived yet. pending[op.sequence] = op op, ok := pending[*cmd.Header.AckSequence] if ok { // this is the case where we missed it op.receiver <- response delete(pending, op.sequence) break } } } } // Notify all pendings that we are closed for business }