Exemplo n.º 1
0
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
}