func roundTrip(conn *client.Conn, deviceId, channelId, endpoint string, version int64) (err error) { stopChan, errChan := make(chan bool), make(chan error) defer close(stopChan) go func() { err := client.Notify(endpoint, version) if err != nil { err = fmt.Errorf("Error sending update %d on channel %q: %s", version, channelId, err) } select { case <-stopChan: case errChan <- err: } }() go func() { var ( pendingAccepts []client.Update err error ) timeout := time.After(15 * time.Second) for ok := true; ok; { var packet client.Packet select { case ok = <-stopChan: case <-timeout: ok = false err = client.ErrTimedOut case packet, ok = <-conn.Packets: if !ok { err = client.ErrChanClosed break } updates, _ := packet.(client.ServerUpdates) if len(updates) == 0 { continue } pendingAccepts = append(pendingAccepts, updates...) var ( update client.Update hasUpdate bool ) for _, update = range updates { if update.ChannelId == channelId && update.Version >= version { hasUpdate = true break } } if !hasUpdate { continue } ok = false if update.Version != version { err = fmt.Errorf("Wrong update version: got %d; want %d", update.Version, version) break } } } if acceptErr := conn.AcceptBatch(pendingAccepts); acceptErr != nil { err = fmt.Errorf("Error acknowledging updates: %s", acceptErr) } select { case <-stopChan: case errChan <- err: } }() for i := 0; i < 2; i++ { if err := <-errChan; err != nil { return err } } return nil }