private static IStateResult configurePushSingleton <TModel, TThreadsafe>(
            ITransitionConfigurator transitions,
            IStateResult entryPoint,
            ISingletonDataSource <TThreadsafe> dataSource,
            IAnalyticsService analyticsService,
            IUpdatingApiClient <TModel> updatingApi,
            Func <TModel, TThreadsafe> toClean,
            Func <TThreadsafe, string, TThreadsafe> toUnsyncable,
            ITogglApi api,
            IScheduler scheduler,
            IObservable <Unit> delayCancellation)
            where TModel : class
            where TThreadsafe : class, TModel, IThreadSafeModel, IDatabaseSyncable
        {
            var rnd         = new Random();
            var apiDelay    = new RetryDelayService(rnd);
            var statusDelay = new RetryDelayService(rnd);

            var push    = new PushSingleState <TThreadsafe>(dataSource);
            var pushOne = new PushOneEntityState <TThreadsafe>();
            var update  = new UpdateEntityState <TModel, TThreadsafe>(updatingApi, 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.UpdateEntity, update);

            transitions.ConfigureTransition(pushOne.CreateEntity, new InvalidTransitionState($"Creating 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(update.ClientError, tryResolveClientError);
            transitions.ConfigureTransition(update.ServerError, checkServerStatus);
            transitions.ConfigureTransition(update.UnknownError, checkServerStatus);

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

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

            transitions.ConfigureTransition(update.UpdatingSucceeded, finished);

            transitions.ConfigureTransition(finished.Continue, push);

            return(push.NothingToPush);
        }
Пример #2
0
        public UpdateEntityState(
            IUpdatingApiClient <TModel> api,
            IBaseDataSource <TThreadsafeModel> dataSource,
            Func <TModel, TThreadsafeModel> convertToThreadsafeModel)
            : base(dataSource)
        {
            Ensure.Argument.IsNotNull(api, nameof(api));
            Ensure.Argument.IsNotNull(dataSource, nameof(dataSource));
            Ensure.Argument.IsNotNull(convertToThreadsafeModel, nameof(convertToThreadsafeModel));

            this.api        = api;
            this.dataSource = dataSource;
            this.convertToThreadsafeModel = convertToThreadsafeModel;
        }
Пример #3
0
        private static LookForSingletonChangeToPushState <TThreadsafe> configurePushSingleton <TModel, TThreadsafe>(
            ITransitionConfigurator transitions,
            IStateResult entryPoint,
            ISingletonDataSource <TThreadsafe> dataSource,
            IAnalyticsService analyticsService,
            IUpdatingApiClient <TModel> updatingApi,
            ILeakyBucket minutesLeakyBucket,
            IRateLimiter rateLimiter,
            WaitForAWhileState waitForAWhileState,
            Func <TModel, TThreadsafe> toClean,
            Func <TThreadsafe, string, TThreadsafe> toUnsyncable)
            where TModel : class
            where TThreadsafe : class, TModel, IThreadSafeModel, IDatabaseSyncable, IIdentifiable
        {
            var lookForChange      = new LookForSingletonChangeToPushState <TThreadsafe>(dataSource);
            var chooseOperation    = new ChooseSyncOperationState <TThreadsafe>();
            var update             = new UpdateEntityState <TModel, TThreadsafe>(updatingApi, 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.UpdateEntity, update);

            transitions.ConfigureTransition(chooseOperation.CreateEntity, new InvalidTransitionState($"Creating 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(update.ClientError, processClientError);
            transitions.ConfigureTransition(update.ServerError, new FailureState());
            transitions.ConfigureTransition(update.UnknownError, new FailureState());

            transitions.ConfigureTransition(update.PreventOverloadingServer, waitForAWhileState);

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

            transitions.ConfigureTransition(update.Done, lookForChange);
            transitions.ConfigureTransition(unsyncable.Done, lookForChange);
            transitions.ConfigureTransition(update.EntityChanged, lookForChange);

            return(lookForChange);
        }
Пример #4
0
        public UpdateEntityState(
            IUpdatingApiClient <TModel> api,
            IBaseDataSource <TThreadsafeModel> dataSource,
            IAnalyticsService analyticsService,
            ILeakyBucket leakyBucket,
            IRateLimiter limiter,
            Func <TModel, TThreadsafeModel> convertToThreadsafeModel)
            : base(analyticsService)
        {
            Ensure.Argument.IsNotNull(api, nameof(api));
            Ensure.Argument.IsNotNull(dataSource, nameof(dataSource));
            Ensure.Argument.IsNotNull(convertToThreadsafeModel, nameof(convertToThreadsafeModel));
            Ensure.Argument.IsNotNull(leakyBucket, nameof(leakyBucket));
            Ensure.Argument.IsNotNull(limiter, nameof(limiter));

            this.api        = api;
            this.dataSource = dataSource;
            this.convertToThreadsafeModel = convertToThreadsafeModel;
            this.leakyBucket = leakyBucket;
            this.limiter     = limiter;
        }
        private static IStateResult configurePush <TModel, TDatabase, TThreadsafe>(
            ITransitionConfigurator transitions,
            IStateResult entryPoint,
            IDataSource <TThreadsafe, TDatabase> dataSource,
            IAnalyticsService analyticsService,
            ICreatingApiClient <TModel> creatingApi,
            IUpdatingApiClient <TModel> updatingApi,
            IDeletingApiClient <TModel> deletingApi,
            Func <TModel, TThreadsafe> toClean,
            Func <TThreadsafe, string, TThreadsafe> toUnsyncable,
            ITogglApi api,
            IRetryDelayService apiDelay,
            IScheduler scheduler,
            IObservable <Unit> delayCancellation)
            where TModel : class, IIdentifiable, ILastChangedDatable
            where TDatabase : class, TModel, IDatabaseSyncable
            where TThreadsafe : class, TDatabase, IThreadSafeModel
        {
            var rnd         = new Random();
            var statusDelay = new RetryDelayService(rnd);

            var push                  = new PushState <TDatabase, TThreadsafe>(dataSource);
            var pushOne               = new PushOneEntityState <TThreadsafe>();
            var create                = new CreateEntityState <TModel, TThreadsafe>(creatingApi, dataSource, analyticsService, toClean);
            var update                = new UpdateEntityState <TModel, TThreadsafe>(updatingApi, dataSource, analyticsService, toClean);
            var delete                = new DeleteEntityState <TModel, TDatabase, TThreadsafe>(deletingApi, dataSource, analyticsService);
            var deleteLocal           = new DeleteLocalEntityState <TDatabase, TThreadsafe>(dataSource);
            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, update);
            transitions.ConfigureTransition(pushOne.DeleteEntity, delete);
            transitions.ConfigureTransition(pushOne.DeleteEntityLocally, deleteLocal);

            transitions.ConfigureTransition(create.ClientError, tryResolveClientError);
            transitions.ConfigureTransition(update.ClientError, tryResolveClientError);
            transitions.ConfigureTransition(delete.ClientError, tryResolveClientError);

            transitions.ConfigureTransition(create.ServerError, checkServerStatus);
            transitions.ConfigureTransition(update.ServerError, checkServerStatus);
            transitions.ConfigureTransition(delete.ServerError, checkServerStatus);

            transitions.ConfigureTransition(create.UnknownError, checkServerStatus);
            transitions.ConfigureTransition(update.UnknownError, checkServerStatus);
            transitions.ConfigureTransition(delete.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.CreatingFinished, finished);
            transitions.ConfigureTransition(update.UpdatingSucceeded, finished);
            transitions.ConfigureTransition(delete.DeletingFinished, finished);
            transitions.ConfigureTransition(deleteLocal.Deleted, finished);
            transitions.ConfigureTransition(deleteLocal.DeletingFailed, finished);

            transitions.ConfigureTransition(finished.Continue, push);

            return(push.NothingToPush);
        }
Пример #6
0
        private static LookForChangeToPushState <TDatabase, TThreadsafe> configurePush <TModel, TDatabase, TThreadsafe>(
            ITransitionConfigurator transitions,
            IStateResult entryPoint,
            IDataSource <TThreadsafe, TDatabase> dataSource,
            IAnalyticsService analyticsService,
            ICreatingApiClient <TModel> creatingApi,
            IUpdatingApiClient <TModel> updatingApi,
            IDeletingApiClient <TModel> deletingApi,
            ILeakyBucket minutesLeakyBucket,
            IRateLimiter rateLimiter,
            WaitForAWhileState waitForAWhileState,
            Func <TModel, TThreadsafe> toClean,
            Func <TThreadsafe, string, TThreadsafe> toUnsyncable)
            where TModel : class, 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 update             = new UpdateEntityState <TModel, TThreadsafe>(updatingApi, dataSource, analyticsService, minutesLeakyBucket, rateLimiter, toClean);
            var delete             = new DeleteEntityState <TModel, TDatabase, TThreadsafe>(deletingApi, analyticsService, dataSource, minutesLeakyBucket, rateLimiter);
            var deleteLocal        = new DeleteLocalEntityState <TDatabase, TThreadsafe>(dataSource);
            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, update);
            transitions.ConfigureTransition(chooseOperation.DeleteEntity, delete);
            transitions.ConfigureTransition(chooseOperation.DeleteEntityLocally, deleteLocal);

            transitions.ConfigureTransition(create.ClientError, processClientError);
            transitions.ConfigureTransition(update.ClientError, processClientError);
            transitions.ConfigureTransition(delete.ClientError, processClientError);

            transitions.ConfigureTransition(create.ServerError, new FailureState());
            transitions.ConfigureTransition(update.ServerError, new FailureState());
            transitions.ConfigureTransition(delete.ServerError, new FailureState());

            transitions.ConfigureTransition(create.UnknownError, new FailureState());
            transitions.ConfigureTransition(update.UnknownError, new FailureState());
            transitions.ConfigureTransition(delete.UnknownError, new FailureState());

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

            transitions.ConfigureTransition(create.EntityChanged, lookForChange);
            transitions.ConfigureTransition(update.EntityChanged, lookForChange);

            transitions.ConfigureTransition(create.PreventOverloadingServer, waitForAWhileState);
            transitions.ConfigureTransition(update.PreventOverloadingServer, waitForAWhileState);
            transitions.ConfigureTransition(delete.PreventOverloadingServer, waitForAWhileState);

            transitions.ConfigureTransition(create.Done, lookForChange);
            transitions.ConfigureTransition(update.Done, lookForChange);
            transitions.ConfigureTransition(delete.Done, lookForChange);
            transitions.ConfigureTransition(deleteLocal.Done, lookForChange);
            transitions.ConfigureTransition(deleteLocal.DeletingFailed, lookForChange);
            transitions.ConfigureTransition(unsyncable.Done, lookForChange);

            return(lookForChange);
        }