public Task<IEnumerable<Achievement>> Process(User user, IEnumerable<Workout> workouts, CancellationToken cancel = default(CancellationToken)) { return Task.FromResult(Enumerable.Empty<Achievement>()); }
public async Task<IEnumerable<Achievement>> Process(User user, IEnumerable<Workout> workouts, CancellationToken cancel = default(CancellationToken)) { var achievements = new List<Achievement>(); foreach (var workout in workouts) { var tasks = _providers.Select(achievement => achievement.Execute(workout)).ToList(); var staleAchievements = (await _database.GetAchievements(workout.Id)).ToList(); while (tasks.Count > 0) { var task = await Task.WhenAny(tasks); foreach (var freshAchievement in task.Result) { var matchingAchievements = staleAchievements .Where(achievement => achievement.Type == freshAchievement.Type && achievement.Group == freshAchievement.Group && achievement.Activity == freshAchievement.Activity) .ToList(); if (matchingAchievements.Count == 0) { freshAchievement.WorkoutId = workout.Id; _database.Insert(freshAchievement); if (workout.Date > user.InsertDate.AddDays(-7)) { achievements.Add(freshAchievement); } } else { var staleAchievement = matchingAchievements.FirstOrDefault(achievement => !freshAchievement.HasChanges(achievement)); if (staleAchievement == null) { staleAchievement = matchingAchievements[0]; freshAchievement.Id = staleAchievement.Id; freshAchievement.WorkoutId = workout.Id; _database.Update(freshAchievement); if (freshAchievement.CommentText != staleAchievement.CommentText || (freshAchievement.IsPropped && !staleAchievement.IsPropped)) { achievements.Add(freshAchievement); } } staleAchievements.Remove(staleAchievement); } } tasks.Remove(task); } foreach (var staleAchievement in staleAchievements) { _database.Delete(staleAchievement); if (staleAchievement.CommentId != null) { staleAchievement.CommentText = null; achievements.Add(staleAchievement); } } cancel.ThrowIfCancellationRequested(); } return achievements; }
public async Task<IEnumerable<Workout>> Pull(User user, CancellationToken cancel = default(CancellationToken)) { var changes = Enumerable.Repeat(new {workout = default(Workout), operation = default(byte)}, 0).ToList(); const byte none = 0; const byte insert = 1; const byte updateDeep = 2; const byte updateShallow = 3; const byte delete = 4; var offset = 0; var processedIds = new HashSet<long>(); var toDate = DateTime.MaxValue; var deletedWorkouts = new List<Workout>(); while (true) { var freshWorkouts = await _fitocracy.GetWorkouts(user.Id, offset); var freshLookup = freshWorkouts.ToLookup(workout => workout.Id); foreach (var workout in deletedWorkouts.Where(workout => !freshLookup[workout.Id].Any())) { changes.Add(new {workout, operation = delete}); } if (freshWorkouts.Count == 0) { _database.DeleteWorkoutsBefore(user.Id, toDate); break; } offset += freshWorkouts.Count; freshWorkouts = freshWorkouts.Where(workout => processedIds.Add(workout.Id)).ToList(); if (freshWorkouts.Count == 0) { continue; } var fromDate = freshWorkouts.Min(workout => workout.Date); var staleWorkouts = (await _database.GetWorkouts(user.Id, fromDate, toDate)).ToList(); toDate = fromDate; var staleLookup = staleWorkouts.ToLookup(workout => workout.Id); changes.AddRange(freshWorkouts .Select(workout => { workout.ActivitiesHash = ComputeActivitiesHashCode(workout.Activities); foreach (var activity in workout.Activities) { activity.Group = _grouping.GetActvityGroup(activity.Name); } var staleWorkout = staleLookup[workout.Id].FirstOrDefault() ?? deletedWorkouts.FirstOrDefault(item => item.Id == workout.Id); return new { workout, operation = staleWorkout != null ? workout.HasChanges(staleWorkout) ? staleWorkout.ActivitiesHash != workout.ActivitiesHash ? updateDeep : updateShallow : none : insert }; })); deletedWorkouts = staleWorkouts.Where(workout => !freshLookup[workout.Id].Any()).ToList(); if (deletedWorkouts.Count == 0 && changes[changes.Count - 1].operation == none) { break; } cancel.ThrowIfCancellationRequested(); } changes.Reverse(); changes.Sort((left, right) => left.workout.Date.CompareTo(right.workout.Date)); foreach (var item in changes) { switch (item.operation) { case insert: _database.Insert(item.workout); break; case updateDeep: case updateShallow: _database.Update(item.workout, item.operation == updateDeep); break; case delete: _database.Delete(item.workout); break; } } return changes.Where(item => item.operation != delete) .SkipWhile(item => item.operation == none) .Select(item => item.workout) .ToList(); }
public bool HasChanges(User user) { return Username != user.Username; }