Пример #1
0
        private static void configurePushTransitions(
            ITransitionConfigurator transitions,
            ITogglApi api,
            ITogglDataSource dataSource,
            IAnalyticsService analyticsService,
            ILeakyBucket minutesLeakyBucket,
            IRateLimiter rateLimiter,
            IScheduler scheduler,
            StateResult entryPoint,
            DependencyContainer dependencyContainer)
        {
            var delayState             = new WaitForAWhileState(scheduler, analyticsService);
            var pushNotificationsToken = new SyncPushNotificationsTokenState(dependencyContainer.PushNotificationsTokenStorage, api, dependencyContainer.PushNotificationsTokenService, dependencyContainer.TimeService, dependencyContainer.RemoteConfigService);

            transitions.ConfigureTransition(entryPoint, pushNotificationsToken);

            var pushingWorkspaces  = configureCreateOnlyPush(transitions, pushNotificationsToken.Done, dataSource.Workspaces, analyticsService, api.Workspaces, minutesLeakyBucket, rateLimiter, delayState, Workspace.Clean, Workspace.Unsyncable);
            var pushingUsers       = configurePushSingleton(transitions, pushingWorkspaces.NoMoreChanges, dataSource.User, analyticsService, api.User, minutesLeakyBucket, rateLimiter, delayState, User.Clean, User.Unsyncable);
            var pushingPreferences = configurePushSingleton(transitions, pushingUsers.NoMoreChanges, dataSource.Preferences, analyticsService, api.Preferences, minutesLeakyBucket, rateLimiter, delayState, Preferences.Clean, Preferences.Unsyncable);
            var pushingTags        = configureCreateOnlyPush(transitions, pushingPreferences.NoMoreChanges, dataSource.Tags, analyticsService, api.Tags, minutesLeakyBucket, rateLimiter, delayState, Tag.Clean, Tag.Unsyncable);
            var pushingClients     = configureCreateOnlyPush(transitions, pushingTags.NoMoreChanges, dataSource.Clients, analyticsService, api.Clients, minutesLeakyBucket, rateLimiter, delayState, Client.Clean, Client.Unsyncable);
            var pushingProjects    = configureCreateOnlyPush(transitions, pushingClients.NoMoreChanges, dataSource.Projects, analyticsService, api.Projects, minutesLeakyBucket, rateLimiter, delayState, Project.Clean, Project.Unsyncable);
            var pushingTimeEntries = configurePush(transitions, pushingProjects.NoMoreChanges, dataSource.TimeEntries, analyticsService, api.TimeEntries, api.TimeEntries, api.TimeEntries, minutesLeakyBucket, rateLimiter, delayState, TimeEntry.Clean, TimeEntry.Unsyncable);

            transitions.ConfigureTransition(delayState.Done, pushingWorkspaces);
            transitions.ConfigureTransition(pushingTimeEntries.NoMoreChanges, new DeadEndState());
        }
Пример #2
0
        private static void configureCleanUpTransitions(
            ITransitionConfigurator transitions,
            ITimeService timeService,
            ITogglDataSource dataSource,
            StateResult entryPoint)
        {
            var deleteOlderEntries = new DeleteOldEntriesState(timeService, dataSource.TimeEntries);
            var deleteNonReferencedGhostProjects = new DeleteNonReferencedProjectGhostsState(dataSource.Projects, dataSource.TimeEntries);

            transitions.ConfigureTransition(entryPoint, deleteOlderEntries);
            transitions.ConfigureTransition(deleteOlderEntries.FinishedDeleting, deleteNonReferencedGhostProjects);
        }
Пример #3
0
        private static IStateResult configureCreateOnlyPush <TModel, TDatabase, TThreadsafe>(
            ITransitionConfigurator transitions,
            IStateResult entryPoint,
            IDataSource <TThreadsafe, TDatabase> dataSource,
            IAnalyticsService analyticsService,
            ICreatingApiClient <TModel> creatingApi,
            Func <TModel, TThreadsafe> toClean,
            Func <TThreadsafe, string, TThreadsafe> toUnsyncable,
            ITogglApi api,
            IScheduler scheduler,
            IObservable <Unit> delayCancellation)
            where TModel : IIdentifiable, ILastChangedDatable
            where TDatabase : class, TModel, IDatabaseSyncable
            where TThreadsafe : class, TDatabase, IThreadSafeModel
        {
            var rnd         = new Random();
            var apiDelay    = new RetryDelayService(rnd);
            var statusDelay = new RetryDelayService(rnd);

            var push    = new PushState <TDatabase, TThreadsafe>(dataSource);
            var pushOne = new PushOneEntityState <TThreadsafe>();
            var create  = new CreateEntityState <TModel, TDatabase, TThreadsafe>(creatingApi, dataSource, analyticsService, toClean);
            var tryResolveClientError = new TryResolveClientErrorState <TThreadsafe>();
            var unsyncable            = new UnsyncableEntityState <TThreadsafe>(dataSource, toUnsyncable);
            var checkServerStatus     = new CheckServerStatusState(api, scheduler, apiDelay, statusDelay, delayCancellation);
            var finished = new ResetAPIDelayState(apiDelay);

            transitions.ConfigureTransition(entryPoint, push);
            transitions.ConfigureTransition(push.PushEntity, pushOne);
            transitions.ConfigureTransition(pushOne.CreateEntity, create);

            transitions.ConfigureTransition(pushOne.UpdateEntity, new InvalidTransitionState($"Updating is not supported for {typeof(TModel).Name} during Push sync."));
            transitions.ConfigureTransition(pushOne.DeleteEntity, new InvalidTransitionState($"Deleting is not supported for {typeof(TModel).Name} during Push sync."));
            transitions.ConfigureTransition(pushOne.DeleteEntityLocally, new InvalidTransitionState($"Deleting locally is not supported for {typeof(TModel).Name} during Push sync."));

            transitions.ConfigureTransition(create.ClientError, tryResolveClientError);
            transitions.ConfigureTransition(create.ServerError, checkServerStatus);
            transitions.ConfigureTransition(create.UnknownError, checkServerStatus);

            transitions.ConfigureTransition(tryResolveClientError.UnresolvedTooManyRequests, checkServerStatus);
            transitions.ConfigureTransition(tryResolveClientError.Unresolved, unsyncable);

            transitions.ConfigureTransition(checkServerStatus.Retry, checkServerStatus);
            transitions.ConfigureTransition(checkServerStatus.ServerIsAvailable, push);

            transitions.ConfigureTransition(create.EntityChanged, create);
            transitions.ConfigureTransition(create.Finished, finished);

            transitions.ConfigureTransition(finished.Continue, push);

            return(push.NothingToPush);
        }
 public static void ConfigureTransitions(
     ITransitionConfigurator transitions,
     ITogglDatabase database,
     ITogglApi api,
     ITogglDataSource dataSource,
     IRetryDelayService apiDelay,
     IScheduler scheduler,
     ITimeService timeService,
     IAnalyticsService analyticsService,
     StateMachineEntryPoints entryPoints,
     IObservable <Unit> delayCancellation)
 {
     configurePullTransitions(transitions, database, api, dataSource, timeService, analyticsService, scheduler, entryPoints.StartPullSync, delayCancellation);
     configurePushTransitions(transitions, api, dataSource, analyticsService, apiDelay, scheduler, entryPoints.StartPushSync, delayCancellation);
 }
Пример #5
0
        private static void configurePullTimeEntriesTransitions(
            ITransitionConfigurator transitions,
            ITogglApi api,
            ITogglDataSource dataSource,
            ITogglDatabase database,
            IAnalyticsService analyticsService,
            ITimeService timeService,
            ILeakyBucket leakyBucket,
            IRateLimiter rateLimiter,
            ILastTimeUsageStorage lastTimeUsageStorage,
            StateResult entryPoint)
        {
            var fetchTimeEntries = new FetchJustTimeEntriesSinceState(api, database.SinceParameters, timeService, leakyBucket, rateLimiter);
            var ensureFetchTimeEntriesSucceeded = new EnsureFetchListSucceededState <ITimeEntry>();

            var placeholderStateFactory = new CreatePlaceholdersStateFactory(
                dataSource,
                analyticsService,
                lastTimeUsageStorage,
                timeService);
            var createWorkspacePlaceholder = placeholderStateFactory.ForWorkspaces();
            var createProjectPlaceholder   = placeholderStateFactory.ForProjects();
            var createTaskPlaceholder      = placeholderStateFactory.ForTasks();
            var createTagPlaceholder       = placeholderStateFactory.ForTags();

            var persistTimeEntries =
                new PersistListState <ITimeEntry, IDatabaseTimeEntry, IThreadSafeTimeEntry>(dataSource.TimeEntries, TimeEntry.Clean);
            var updateTimeEntriesSinceDate = new UpdateSinceDateState <ITimeEntry>(database.SinceParameters);
            var timeEntriesAnalytics       = new TimeEntriesAnalyticsState(analyticsService);


            transitions.ConfigureTransition(entryPoint, fetchTimeEntries);
            transitions.ConfigureTransition(fetchTimeEntries.PreventOverloadingServer, new DeadEndState());
            transitions.ConfigureTransition(fetchTimeEntries.Done, ensureFetchTimeEntriesSucceeded);
            transitions.ConfigureTransition(ensureFetchTimeEntriesSucceeded.ErrorOccured, new FailureState());

            transitions.ConfigureTransition(ensureFetchTimeEntriesSucceeded.Done, timeEntriesAnalytics);

            transitions.ConfigureTransition(timeEntriesAnalytics.Done, createWorkspacePlaceholder);
            transitions.ConfigureTransition(createWorkspacePlaceholder.Done, createProjectPlaceholder);
            transitions.ConfigureTransition(createProjectPlaceholder.Done, createTaskPlaceholder);
            transitions.ConfigureTransition(createTaskPlaceholder.Done, createTagPlaceholder);

            transitions.ConfigureTransition(createTagPlaceholder.Done, persistTimeEntries);
            transitions.ConfigureTransition(persistTimeEntries.Done, updateTimeEntriesSinceDate);
            transitions.ConfigureTransition(updateTimeEntriesSinceDate.Done, new DeadEndState());
        }
Пример #6
0
        private static LookForChangeToPushState <TDatabase, TThreadsafe> configureCreateOnlyPush <TModel, TDatabase, TThreadsafe>(
            ITransitionConfigurator transitions,
            IStateResult entryPoint,
            IDataSource <TThreadsafe, TDatabase> dataSource,
            IAnalyticsService analyticsService,
            ICreatingApiClient <TModel> creatingApi,
            ILeakyBucket minutesLeakyBucket,
            IRateLimiter rateLimiter,
            WaitForAWhileState waitForAWhileState,
            Func <TModel, TThreadsafe> toClean,
            Func <TThreadsafe, string, TThreadsafe> toUnsyncable)
            where TModel : IIdentifiable, ILastChangedDatable
            where TDatabase : class, TModel, IDatabaseSyncable
            where TThreadsafe : class, TDatabase, IThreadSafeModel
        {
            var lookForChange      = new LookForChangeToPushState <TDatabase, TThreadsafe>(dataSource);
            var chooseOperation    = new ChooseSyncOperationState <TThreadsafe>();
            var create             = new CreateEntityState <TModel, TDatabase, TThreadsafe>(creatingApi, dataSource, analyticsService, minutesLeakyBucket, rateLimiter, toClean);
            var processClientError = new ProcessClientErrorState <TThreadsafe>();
            var unsyncable         = new MarkEntityAsUnsyncableState <TThreadsafe>(dataSource, toUnsyncable);

            transitions.ConfigureTransition(entryPoint, lookForChange);
            transitions.ConfigureTransition(lookForChange.ChangeFound, chooseOperation);
            transitions.ConfigureTransition(chooseOperation.CreateEntity, create);

            transitions.ConfigureTransition(chooseOperation.UpdateEntity, new InvalidTransitionState($"Updating is not supported for {typeof(TModel).Name} during Push sync."));
            transitions.ConfigureTransition(chooseOperation.DeleteEntity, new InvalidTransitionState($"Deleting is not supported for {typeof(TModel).Name} during Push sync."));
            transitions.ConfigureTransition(chooseOperation.DeleteEntityLocally, new InvalidTransitionState($"Deleting locally is not supported for {typeof(TModel).Name} during Push sync."));

            transitions.ConfigureTransition(create.ClientError, processClientError);
            transitions.ConfigureTransition(create.ServerError, new FailureState());
            transitions.ConfigureTransition(create.UnknownError, new FailureState());

            transitions.ConfigureTransition(create.PreventOverloadingServer, waitForAWhileState);

            transitions.ConfigureTransition(processClientError.UnresolvedTooManyRequests, new FailureState());
            transitions.ConfigureTransition(processClientError.Unresolved, unsyncable);

            transitions.ConfigureTransition(create.EntityChanged, new InvalidTransitionState($"Entity cannot have changed since updating is not supported for {typeof(TModel).Name} during Push sync."));
            transitions.ConfigureTransition(create.Done, lookForChange);
            transitions.ConfigureTransition(unsyncable.Done, lookForChange);

            return(lookForChange);
        }
Пример #7
0
        private static void configureCleanUpTransitions(
            ITransitionConfigurator transitions,
            ITimeService timeService,
            ITogglDataSource dataSource,
            IAnalyticsService analyticsService,
            StateResult entryPoint)
        {
            var deleteOlderEntries = new DeleteOldTimeEntriesState(timeService, dataSource.TimeEntries);
            var deleteUnsnecessaryProjectPlaceholders = new DeleteUnnecessaryProjectPlaceholdersState(dataSource.Projects, dataSource.TimeEntries);

            var checkForInaccessibleWorkspaces = new CheckForInaccessibleWorkspacesState(dataSource);

            var deleteInaccessibleTimeEntries = new DeleteInaccessibleTimeEntriesState(dataSource.TimeEntries);
            var deleteInaccessibleTags        = new DeleteNonReferencedInaccessibleTagsState(dataSource.Tags, dataSource.TimeEntries);
            var deleteInaccessibleTasks       = new DeleteNonReferencedInaccessibleTasksState(dataSource.Tasks, dataSource.TimeEntries);
            var deleteInaccessibleProjects    = new DeleteNonReferencedInaccessibleProjectsState(dataSource.Projects, dataSource.Tasks, dataSource.TimeEntries);
            var deleteInaccessibleClients     = new DeleteNonReferencedInaccessibleClientsState(dataSource.Clients, dataSource.Projects);
            var deleteInaccessibleWorkspaces  = new DeleteNonReferencedInaccessibleWorkspacesState(
                dataSource.Workspaces,
                dataSource.TimeEntries,
                dataSource.Projects,
                dataSource.Tasks,
                dataSource.Clients,
                dataSource.Tags);

            var trackInaccesssibleDataAfterCleanUp       = new TrackInaccessibleDataAfterCleanUpState(dataSource, analyticsService);
            var trackInaccesssibleWorkspacesAfterCleanUp = new TrackInaccessibleWorkspacesAfterCleanUpState(dataSource, analyticsService);

            transitions.ConfigureTransition(entryPoint, deleteOlderEntries);
            transitions.ConfigureTransition(deleteOlderEntries.Done, deleteUnsnecessaryProjectPlaceholders);

            transitions.ConfigureTransition(deleteUnsnecessaryProjectPlaceholders.Done, checkForInaccessibleWorkspaces);
            transitions.ConfigureTransition(checkForInaccessibleWorkspaces.NoInaccessibleWorkspaceFound, new DeadEndState());
            transitions.ConfigureTransition(checkForInaccessibleWorkspaces.FoundInaccessibleWorkspaces, deleteInaccessibleTimeEntries);

            transitions.ConfigureTransition(deleteInaccessibleTimeEntries.Done, deleteInaccessibleTags);
            transitions.ConfigureTransition(deleteInaccessibleTags.Done, deleteInaccessibleTasks);
            transitions.ConfigureTransition(deleteInaccessibleTasks.Done, deleteInaccessibleProjects);
            transitions.ConfigureTransition(deleteInaccessibleProjects.Done, deleteInaccessibleClients);
            transitions.ConfigureTransition(deleteInaccessibleClients.Done, trackInaccesssibleDataAfterCleanUp);
            transitions.ConfigureTransition(trackInaccesssibleDataAfterCleanUp.Done, deleteInaccessibleWorkspaces);
            transitions.ConfigureTransition(deleteInaccessibleWorkspaces.Done, trackInaccesssibleWorkspacesAfterCleanUp);
            transitions.ConfigureTransition(trackInaccesssibleWorkspacesAfterCleanUp.Done, new DeadEndState());
        }
        private static void configurePushTransitions(
            ITransitionConfigurator transitions,
            ITogglApi api,
            ITogglDataSource dataSource,
            IAnalyticsService analyticsService,
            IRetryDelayService apiDelay,
            IScheduler scheduler,
            StateResult entryPoint,
            IObservable <Unit> delayCancellation)
        {
            var pushingWorkspacesFinished  = configureCreateOnlyPush(transitions, entryPoint, dataSource.Workspaces, analyticsService, api.Workspaces, Workspace.Clean, Workspace.Unsyncable, api, scheduler, delayCancellation);
            var pushingUsersFinished       = configurePushSingleton(transitions, pushingWorkspacesFinished, dataSource.User, analyticsService, api.User, User.Clean, User.Unsyncable, api, scheduler, delayCancellation);
            var pushingPreferencesFinished = configurePushSingleton(transitions, pushingUsersFinished, dataSource.Preferences, analyticsService, api.Preferences, Preferences.Clean, Preferences.Unsyncable, api, scheduler, delayCancellation);
            var pushingTagsFinished        = configureCreateOnlyPush(transitions, pushingPreferencesFinished, dataSource.Tags, analyticsService, api.Tags, Tag.Clean, Tag.Unsyncable, api, scheduler, delayCancellation);
            var pushingClientsFinished     = configureCreateOnlyPush(transitions, pushingTagsFinished, dataSource.Clients, analyticsService, api.Clients, Client.Clean, Client.Unsyncable, api, scheduler, delayCancellation);
            var pushingProjectsFinished    = configureCreateOnlyPush(transitions, pushingClientsFinished, dataSource.Projects, analyticsService, api.Projects, Project.Clean, Project.Unsyncable, api, scheduler, delayCancellation);

            configurePush(transitions, pushingProjectsFinished, dataSource.TimeEntries, analyticsService, api.TimeEntries, api.TimeEntries, api.TimeEntries, TimeEntry.Clean, TimeEntry.Unsyncable, api, apiDelay, scheduler, delayCancellation);
        }
Пример #9
0
        public static void ConfigureTransitions(
            ITransitionConfigurator transitions,
            ITogglDatabase database,
            ITogglApi api,
            ITogglDataSource dataSource,
            IScheduler scheduler,
            ITimeService timeService,
            IAnalyticsService analyticsService,
            StateMachineEntryPoints entryPoints,
            ISyncStateQueue queue)
        {
            var minutesLeakyBucket = new LeakyBucket(timeService, slotsPerWindow: 60, movingWindowSize: TimeSpan.FromSeconds(60));
            var secondsLeakyBucket = new LeakyBucket(timeService, slotsPerWindow: 3, movingWindowSize: TimeSpan.FromSeconds(1));
            var rateLimiter        = new RateLimiter(secondsLeakyBucket, scheduler);

            configurePullTransitions(transitions, database, api, dataSource, timeService, analyticsService, scheduler, entryPoints.StartPullSync, minutesLeakyBucket, rateLimiter, queue);
            configurePushTransitions(transitions, api, dataSource, analyticsService, minutesLeakyBucket, rateLimiter, scheduler, entryPoints.StartPushSync);
            configureCleanUpTransitions(transitions, timeService, dataSource, analyticsService, entryPoints.StartCleanUp);
        }
        private static void configurePullTransitions(
            ITransitionConfigurator transitions,
            ITogglDatabase database,
            ITogglApi api,
            ITogglDataSource dataSource,
            ITimeService timeService,
            IAnalyticsService analyticsService,
            IScheduler scheduler,
            StateResult entryPoint,
            IObservable <Unit> delayCancellation)
        {
            var rnd         = new Random();
            var apiDelay    = new RetryDelayService(rnd);
            var statusDelay = new RetryDelayService(rnd);

            var fetchAllSince = new FetchAllSinceState(database, api, timeService);

            var persistWorkspaces =
                new PersistListState <IWorkspace, IDatabaseWorkspace, IThreadSafeWorkspace>(dataSource.Workspaces, Workspace.Clean);

            var updateWorkspacesSinceDate =
                new SinceDateUpdatingState <IWorkspace, IDatabaseWorkspace>(database.SinceParameters);

            var detectNoWorkspaceState = new NoWorkspaceDetectingState();

            var persistWorkspaceFeatures =
                new PersistListState <IWorkspaceFeatureCollection, IDatabaseWorkspaceFeatureCollection, IThreadSafeWorkspaceFeatureCollection>(
                    dataSource.WorkspaceFeatures, WorkspaceFeatureCollection.From);

            var persistUser =
                new PersistSingletonState <IUser, IDatabaseUser, IThreadSafeUser>(dataSource.User, User.Clean);

            var noDefaultWorkspaceTrackingState = new NoDefaultWorkspaceTrackingState(analyticsService);

            var persistTags =
                new PersistListState <ITag, IDatabaseTag, IThreadSafeTag>(dataSource.Tags, Tag.Clean);

            var updateTagsSinceDate = new SinceDateUpdatingState <ITag, IDatabaseTag>(database.SinceParameters);

            var persistClients =
                new PersistListState <IClient, IDatabaseClient, IThreadSafeClient>(dataSource.Clients, Client.Clean);

            var updateClientsSinceDate = new SinceDateUpdatingState <IClient, IDatabaseClient>(database.SinceParameters);

            var persistPreferences =
                new PersistSingletonState <IPreferences, IDatabasePreferences, IThreadSafePreferences>(dataSource.Preferences, Preferences.Clean);

            var persistProjects =
                new PersistListState <IProject, IDatabaseProject, IThreadSafeProject>(dataSource.Projects, Project.Clean);

            var updateProjectsSinceDate = new SinceDateUpdatingState <IProject, IDatabaseProject>(database.SinceParameters);

            var createGhostProjects = new CreateGhostProjectsState(dataSource.Projects, analyticsService);

            var persistTimeEntries =
                new PersistListState <ITimeEntry, IDatabaseTimeEntry, IThreadSafeTimeEntry>(dataSource.TimeEntries, TimeEntry.Clean);

            var updateTimeEntriesSinceDate = new SinceDateUpdatingState <ITimeEntry, IDatabaseTimeEntry>(database.SinceParameters);

            var persistTasks =
                new PersistListState <ITask, IDatabaseTask, IThreadSafeTask>(dataSource.Tasks, Task.Clean);

            var updateTasksSinceDate = new SinceDateUpdatingState <ITask, IDatabaseTask>(database.SinceParameters);

            var refetchInaccessibleProjects =
                new TryFetchInaccessibleProjectsState(dataSource.Projects, timeService, api.Projects);

            var retryOrThrow      = new SevereApiExceptionsRethrowingState();
            var checkServerStatus = new CheckServerStatusState(api, scheduler, apiDelay, statusDelay, delayCancellation);

            var finished           = new ResetAPIDelayState(apiDelay);
            var deleteOlderEntries = new DeleteOldEntriesState(timeService, dataSource.TimeEntries);
            var deleteNonReferencedGhostProjects = new DeleteNonReferencedProjectGhostsState(dataSource.Projects, dataSource.TimeEntries);

            transitions.ConfigureTransition(entryPoint, fetchAllSince);
            transitions.ConfigureTransition(fetchAllSince.FetchStarted, persistWorkspaces);

            transitions.ConfigureTransition(persistWorkspaces.FinishedPersisting, updateWorkspacesSinceDate);
            transitions.ConfigureTransition(updateWorkspacesSinceDate.Finished, detectNoWorkspaceState);
            transitions.ConfigureTransition(detectNoWorkspaceState.Continue, persistUser);

            transitions.ConfigureTransition(persistUser.FinishedPersisting, noDefaultWorkspaceTrackingState);
            transitions.ConfigureTransition(noDefaultWorkspaceTrackingState.Continue, persistWorkspaceFeatures);

            transitions.ConfigureTransition(persistWorkspaceFeatures.FinishedPersisting, persistPreferences);

            transitions.ConfigureTransition(persistPreferences.FinishedPersisting, persistTags);

            transitions.ConfigureTransition(persistTags.FinishedPersisting, updateTagsSinceDate);
            transitions.ConfigureTransition(updateTagsSinceDate.Finished, persistClients);

            transitions.ConfigureTransition(persistClients.FinishedPersisting, updateClientsSinceDate);
            transitions.ConfigureTransition(updateClientsSinceDate.Finished, persistProjects);

            transitions.ConfigureTransition(persistProjects.FinishedPersisting, updateProjectsSinceDate);
            transitions.ConfigureTransition(updateProjectsSinceDate.Finished, persistTasks);

            transitions.ConfigureTransition(persistTasks.FinishedPersisting, updateTasksSinceDate);
            transitions.ConfigureTransition(updateTasksSinceDate.Finished, createGhostProjects);

            transitions.ConfigureTransition(createGhostProjects.FinishedPersisting, persistTimeEntries);
            transitions.ConfigureTransition(persistTimeEntries.FinishedPersisting, updateTimeEntriesSinceDate);
            transitions.ConfigureTransition(updateTimeEntriesSinceDate.Finished, refetchInaccessibleProjects);
            transitions.ConfigureTransition(refetchInaccessibleProjects.FetchNext, refetchInaccessibleProjects);

            transitions.ConfigureTransition(refetchInaccessibleProjects.FinishedPersisting, deleteOlderEntries);
            transitions.ConfigureTransition(deleteOlderEntries.FinishedDeleting, deleteNonReferencedGhostProjects);

            transitions.ConfigureTransition(persistWorkspaces.ErrorOccured, retryOrThrow);
            transitions.ConfigureTransition(persistUser.ErrorOccured, retryOrThrow);
            transitions.ConfigureTransition(persistWorkspaceFeatures.ErrorOccured, retryOrThrow);
            transitions.ConfigureTransition(persistPreferences.ErrorOccured, retryOrThrow);
            transitions.ConfigureTransition(persistTags.ErrorOccured, retryOrThrow);
            transitions.ConfigureTransition(persistClients.ErrorOccured, retryOrThrow);
            transitions.ConfigureTransition(persistProjects.ErrorOccured, retryOrThrow);
            transitions.ConfigureTransition(persistTasks.ErrorOccured, retryOrThrow);
            transitions.ConfigureTransition(createGhostProjects.ErrorOccured, retryOrThrow);
            transitions.ConfigureTransition(persistTimeEntries.ErrorOccured, retryOrThrow);
            transitions.ConfigureTransition(refetchInaccessibleProjects.ErrorOccured, retryOrThrow);

            transitions.ConfigureTransition(retryOrThrow.Retry, checkServerStatus);
            transitions.ConfigureTransition(checkServerStatus.Retry, checkServerStatus);
            transitions.ConfigureTransition(checkServerStatus.ServerIsAvailable, finished);
            transitions.ConfigureTransition(finished.Continue, fetchAllSince);
        }
Пример #11
0
        private static void configurePullTransitions(
            ITransitionConfigurator transitions,
            ITogglDatabase database,
            ITogglApi api,
            ITogglDataSource dataSource,
            ITimeService timeService,
            IAnalyticsService analyticsService,
            IScheduler scheduler,
            StateResult entryPoint,
            ILeakyBucket leakyBucket,
            IRateLimiter rateLimiter,
            ISyncStateQueue queue)
        {
            var delayState = new WaitForAWhileState(scheduler, analyticsService);

            var fetchAllSince = new FetchAllSinceState(api, database.SinceParameters, timeService, leakyBucket, rateLimiter);

            var ensureFetchWorkspacesSucceeded        = new EnsureFetchListSucceededState <IWorkspace>();
            var ensureFetchWorkspaceFeaturesSucceeded = new EnsureFetchListSucceededState <IWorkspaceFeatureCollection>();
            var ensureFetchTagsSucceeded        = new EnsureFetchListSucceededState <ITag>();
            var ensureFetchClientsSucceeded     = new EnsureFetchListSucceededState <IClient>();
            var ensureFetchProjectsSucceeded    = new EnsureFetchListSucceededState <IProject>();
            var ensureFetchTasksSucceeded       = new EnsureFetchListSucceededState <ITask>();
            var ensureFetchTimeEntriesSucceeded = new EnsureFetchListSucceededState <ITimeEntry>();
            var ensureFetchUserSucceeded        = new EnsureFetchSingletonSucceededState <IUser>();
            var ensureFetchPreferencesSucceeded = new EnsureFetchSingletonSucceededState <IPreferences>();

            var scheduleCleanUp = new ScheduleCleanUpState(queue);

            var detectGainingAccessToWorkspaces =
                new DetectGainingAccessToWorkspacesState(
                    dataSource.Workspaces,
                    analyticsService,
                    () => new HasFinsihedSyncBeforeInteractor(dataSource));

            var resetSinceParams = new ResetSinceParamsState(database.SinceParameters);

            var persistNewWorkspaces =
                new PersistNewWorkspacesState(dataSource.Workspaces);

            var detectLosingAccessToWorkspaces =
                new DetectLosingAccessToWorkspacesState(dataSource.Workspaces, analyticsService);

            var deleteRunningInaccessibleTimeEntry = new DeleteInaccessibleRunningTimeEntryState(dataSource.TimeEntries);

            var markWorkspacesAsInaccessible = new MarkWorkspacesAsInaccessibleState(dataSource.Workspaces);

            var persistWorkspaces =
                new PersistListState <IWorkspace, IDatabaseWorkspace, IThreadSafeWorkspace>(dataSource.Workspaces, Workspace.Clean);

            var updateWorkspacesSinceDate =
                new UpdateSinceDateState <IWorkspace>(database.SinceParameters);

            var detectNoWorkspaceState = new DetectNotHavingAccessToAnyWorkspaceState(dataSource);

            var persistWorkspaceFeatures =
                new PersistListState <IWorkspaceFeatureCollection, IDatabaseWorkspaceFeatureCollection, IThreadSafeWorkspaceFeatureCollection>(
                    dataSource.WorkspaceFeatures, WorkspaceFeatureCollection.From);

            var persistUser =
                new PersistSingletonState <IUser, IDatabaseUser, IThreadSafeUser>(dataSource.User, User.Clean);

            var noDefaultWorkspaceDetectingState = new DetectUserHavingNoDefaultWorkspaceSetState(dataSource, analyticsService);

            var trySetDefaultWorkspaceState = new TrySetDefaultWorkspaceState(timeService, dataSource);

            var persistTags =
                new PersistListState <ITag, IDatabaseTag, IThreadSafeTag>(dataSource.Tags, Tag.Clean);

            var updateTagsSinceDate = new UpdateSinceDateState <ITag>(database.SinceParameters);

            var persistClients =
                new PersistListState <IClient, IDatabaseClient, IThreadSafeClient>(dataSource.Clients, Client.Clean);

            var updateClientsSinceDate = new UpdateSinceDateState <IClient>(database.SinceParameters);

            var persistPreferences =
                new PersistSingletonState <IPreferences, IDatabasePreferences, IThreadSafePreferences>(dataSource.Preferences, Preferences.Clean);

            var persistProjects =
                new PersistListState <IProject, IDatabaseProject, IThreadSafeProject>(dataSource.Projects, Project.Clean);

            var updateProjectsSinceDate = new UpdateSinceDateState <IProject>(database.SinceParameters);

            var createProjectPlaceholders = new CreateArchivedProjectPlaceholdersState(dataSource.Projects, analyticsService);

            var persistTimeEntries =
                new PersistListState <ITimeEntry, IDatabaseTimeEntry, IThreadSafeTimeEntry>(dataSource.TimeEntries, TimeEntry.Clean);

            var updateTimeEntriesSinceDate = new UpdateSinceDateState <ITimeEntry>(database.SinceParameters);

            var persistTasks =
                new PersistListState <ITask, IDatabaseTask, IThreadSafeTask>(dataSource.Tasks, Task.Clean);

            var updateTasksSinceDate = new UpdateSinceDateState <ITask>(database.SinceParameters);

            var refetchInaccessibleProjects =
                new TryFetchInaccessibleProjectsState(dataSource.Projects, timeService, api.Projects);

            // start all the API requests first
            transitions.ConfigureTransition(entryPoint, fetchAllSince);

            // prevent overloading server with too many requests
            transitions.ConfigureTransition(fetchAllSince.PreventOverloadingServer, delayState);

            // detect gaining access to workspaces
            transitions.ConfigureTransition(fetchAllSince.Done, ensureFetchWorkspacesSucceeded);
            transitions.ConfigureTransition(ensureFetchWorkspacesSucceeded.Done, detectGainingAccessToWorkspaces);
            transitions.ConfigureTransition(detectGainingAccessToWorkspaces.Done, detectLosingAccessToWorkspaces);
            transitions.ConfigureTransition(detectGainingAccessToWorkspaces.NewWorkspacesDetected, resetSinceParams);
            transitions.ConfigureTransition(resetSinceParams.Done, persistNewWorkspaces);
            transitions.ConfigureTransition(persistNewWorkspaces.Done, fetchAllSince);

            // detect losing access to workspaces
            transitions.ConfigureTransition(detectLosingAccessToWorkspaces.Done, persistWorkspaces);
            transitions.ConfigureTransition(detectLosingAccessToWorkspaces.WorkspaceAccessLost, markWorkspacesAsInaccessible);
            transitions.ConfigureTransition(markWorkspacesAsInaccessible.Done, scheduleCleanUp);
            transitions.ConfigureTransition(scheduleCleanUp.Done, deleteRunningInaccessibleTimeEntry);
            transitions.ConfigureTransition(deleteRunningInaccessibleTimeEntry.Done, persistWorkspaces);

            // persist all the data pulled from the server
            transitions.ConfigureTransition(persistWorkspaces.Done, updateWorkspacesSinceDate);
            transitions.ConfigureTransition(updateWorkspacesSinceDate.Done, detectNoWorkspaceState);
            transitions.ConfigureTransition(detectNoWorkspaceState.Done, ensureFetchUserSucceeded);

            transitions.ConfigureTransition(ensureFetchUserSucceeded.Done, persistUser);
            transitions.ConfigureTransition(persistUser.Done, ensureFetchWorkspaceFeaturesSucceeded);

            transitions.ConfigureTransition(ensureFetchWorkspaceFeaturesSucceeded.Done, persistWorkspaceFeatures);
            transitions.ConfigureTransition(persistWorkspaceFeatures.Done, ensureFetchPreferencesSucceeded);

            transitions.ConfigureTransition(ensureFetchPreferencesSucceeded.Done, persistPreferences);
            transitions.ConfigureTransition(persistPreferences.Done, ensureFetchTagsSucceeded);

            transitions.ConfigureTransition(ensureFetchTagsSucceeded.Done, persistTags);
            transitions.ConfigureTransition(persistTags.Done, updateTagsSinceDate);
            transitions.ConfigureTransition(updateTagsSinceDate.Done, ensureFetchClientsSucceeded);

            transitions.ConfigureTransition(ensureFetchClientsSucceeded.Done, persistClients);
            transitions.ConfigureTransition(persistClients.Done, updateClientsSinceDate);
            transitions.ConfigureTransition(updateClientsSinceDate.Done, ensureFetchProjectsSucceeded);

            transitions.ConfigureTransition(ensureFetchProjectsSucceeded.Done, persistProjects);
            transitions.ConfigureTransition(persistProjects.Done, updateProjectsSinceDate);
            transitions.ConfigureTransition(updateProjectsSinceDate.Done, ensureFetchTasksSucceeded);

            transitions.ConfigureTransition(ensureFetchTasksSucceeded.Done, persistTasks);
            transitions.ConfigureTransition(persistTasks.Done, updateTasksSinceDate);
            transitions.ConfigureTransition(updateTasksSinceDate.Done, ensureFetchTimeEntriesSucceeded);

            transitions.ConfigureTransition(ensureFetchTimeEntriesSucceeded.Done, createProjectPlaceholders);
            transitions.ConfigureTransition(createProjectPlaceholders.Done, persistTimeEntries);
            transitions.ConfigureTransition(persistTimeEntries.Done, updateTimeEntriesSinceDate);
            transitions.ConfigureTransition(updateTimeEntriesSinceDate.Done, refetchInaccessibleProjects);
            transitions.ConfigureTransition(refetchInaccessibleProjects.FetchNext, refetchInaccessibleProjects);

            transitions.ConfigureTransition(refetchInaccessibleProjects.Done, noDefaultWorkspaceDetectingState);
            transitions.ConfigureTransition(noDefaultWorkspaceDetectingState.NoDefaultWorkspaceDetected, trySetDefaultWorkspaceState);
            transitions.ConfigureTransition(noDefaultWorkspaceDetectingState.Done, new DeadEndState());
            transitions.ConfigureTransition(trySetDefaultWorkspaceState.Done, new DeadEndState());

            // fail for server errors
            transitions.ConfigureTransition(ensureFetchWorkspacesSucceeded.ErrorOccured, new FailureState());
            transitions.ConfigureTransition(ensureFetchUserSucceeded.ErrorOccured, new FailureState());
            transitions.ConfigureTransition(ensureFetchWorkspaceFeaturesSucceeded.ErrorOccured, new FailureState());
            transitions.ConfigureTransition(ensureFetchPreferencesSucceeded.ErrorOccured, new FailureState());
            transitions.ConfigureTransition(ensureFetchTagsSucceeded.ErrorOccured, new FailureState());
            transitions.ConfigureTransition(ensureFetchClientsSucceeded.ErrorOccured, new FailureState());
            transitions.ConfigureTransition(ensureFetchProjectsSucceeded.ErrorOccured, new FailureState());
            transitions.ConfigureTransition(ensureFetchTasksSucceeded.ErrorOccured, new FailureState());
            transitions.ConfigureTransition(ensureFetchTimeEntriesSucceeded.ErrorOccured, new FailureState());
            transitions.ConfigureTransition(refetchInaccessibleProjects.ErrorOccured, new FailureState());

            // delay loop
            transitions.ConfigureTransition(delayState.Done, fetchAllSince);
        }