public void Update(DateTime utcNow, IReadOnlyList<LocationState> locations, bool simulateFailure) { this.LastUpdateRequest = utcNow; if (this.PeerGroup.CanPoll(utcNow, this.LastUpdated)) { this.LastUpdated = utcNow; // Increment this each time so we can uniquely identify which Update call last // updated an item and so we'll round-robin through each location in the list. this.UpdateCounter++; bool wasConnected = this.IsConnected; bool? isPeerGroupConnected = null; int numLocations = locations.Count; for (int i = 0; i < numLocations; i++) { int locationIndex = (int)unchecked((this.UpdateCounter + i) % numLocations); LocationState locationState = locations[locationIndex]; bool? wasLocationUpdated = locationState.Update(utcNow, this.UpdateCounter, simulateFailure); // A null result means we've polled it too recently. if (wasLocationUpdated != null) { // If we get a connected result, then we can quit early. isPeerGroupConnected = locationState.IsConnected; if (isPeerGroupConnected ?? false) { break; } } } if (isPeerGroupConnected != null) { this.IsConnected = isPeerGroupConnected.Value; } if (this.IsConnected != wasConnected) { this.IsConnectedChanged = utcNow; } bool wasFailed = this.IsFailed; if (this.IsConnected) { this.IsFailed = false; } else if (!this.IsFailed && (this.IsConnectedChanged == null || utcNow >= (this.IsConnectedChanged.Value + this.PeerGroup.Fail))) { this.IsFailed = true; } if (this.IsFailed != wasFailed) { this.IsFailedChanged = utcNow; } } }
private void UpdateLocations(NotifyCollectionChangedEventArgs e) { bool FindLocationState(Location location, out LocationState state) { state = this.Locations.FirstOrDefault(l => l.Location == location); return(state != null); } LocationState GetLocationState(Location location, bool allowAdd = true) { if (!FindLocationState(location, out LocationState result)) { this.GetPeerGroupState(location.PeerGroup); result = new LocationState(location); if (allowAdd) { this.Locations.Add(result); } } return(result); } switch (e.Action) { case NotifyCollectionChangedAction.Add: foreach (Location location in e.NewItems) { GetLocationState(location); } break; case NotifyCollectionChangedAction.Remove: foreach (Location location in e.OldItems) { if (FindLocationState(location, out LocationState state)) { this.Locations.Remove(state); } } break; case NotifyCollectionChangedAction.Replace: foreach (var pair in e.OldItems.Cast <Location>().Zip(e.NewItems.Cast <Location>(), (o, n) => Tuple.Create(o, n))) { if (FindLocationState(pair.Item1, out LocationState oldState)) { LocationState newState = GetLocationState(pair.Item2, allowAdd: false); int index = this.Locations.IndexOf(oldState); this.Locations[index] = newState; } } break; case NotifyCollectionChangedAction.Move: // We don't care about the profile's Location positions. break; default: // NotifyCollectionChangedAction.Reset foreach (Location location in this.profile.Locations) { GetLocationState(location); } foreach (LocationState state in this.Locations.ToList()) { if (!this.profile.Locations.Contains(state.Location)) { this.Locations.Remove(state); } } break; } lock (this.mapLock) { this.peerGroupToLocationsMap = this.Locations .GroupBy(l => this.GetPeerGroupState(l.Location.PeerGroup)) .ToDictionary(group => group.Key, group => group.OrderBy(l => l.Location.Name).ToList()); } }
public void Update(DateTime utcNow, IReadOnlyList <LocationState> locations, ConnectionState?simulateConnection) { this.LastUpdateRequest = utcNow; if (this.PeerGroup.CanPoll(utcNow, this.LastUpdated)) { this.LastUpdated = utcNow; // Increment this each time so we can uniquely identify which Update call last // updated an item and so we'll round-robin through each location in the list. this.UpdateCounter++; ConnectionState priorConnection = this.Connection; ConnectionState?peerGroupConnection = null; int numLocations = locations.Count; for (int i = 0; i < numLocations; i++) { int locationIndex = (int)unchecked ((this.UpdateCounter + i) % numLocations); LocationState locationState = locations[locationIndex]; bool? wasLocationUpdated = locationState.Update(utcNow, this.UpdateCounter, simulateConnection); // A null result means we've polled it too recently. if (wasLocationUpdated != null) { // If we get a Connected result, then we can quit early. // If we only get Disconnected or Unavailable, then we have to check them all. peerGroupConnection = locationState.Connection; if (peerGroupConnection == ConnectionState.Connected) { break; } } } // This should only be null when we've polled all the locations too recently, so Connection shouldn't change. if (peerGroupConnection != null) { this.Connection = peerGroupConnection.Value; } if (this.Connection != priorConnection) { this.ConnectionChanged = utcNow; } bool wasFailed = this.IsFailed; if (this.Connection == ConnectionState.Connected || this.Connection == ConnectionState.Unavailable) { this.IsFailed = false; } else if (!this.IsFailed && (this.ConnectionChanged == null || utcNow >= (this.ConnectionChanged.Value + this.PeerGroup.Fail))) { this.IsFailed = true; } if (this.IsFailed != wasFailed) { this.IsFailedChanged = utcNow; } } }