private static ISyncChannel NullProcessorMethod(ISyncContext context, RecordConfiguration configuration, ISyncChannel channel, SyncProcessDelegate next)
        {
            ISyncChannel newChannel;

            if ((object)context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if ((object)configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            if ((object)channel == null)
            {
                throw new ArgumentNullException(nameof(channel));
            }

            Console.WriteLine("{1} (before next) processor: '{0}'", nameof(NullProcessor), nameof(NullProcessorMethod));

            if ((object)next != null)
            {
                newChannel = next(context, configuration, channel);
            }
            else
            {
                newChannel = channel;
            }

            Console.WriteLine("{1} (after next) processor: '{0}'", nameof(NullProcessor), nameof(NullProcessorMethod));

            return(newChannel);
        }
        protected override ISyncChannel ProduceInternal(ISyncContext context, RecordConfiguration configuration)
        {
            ISyncChannel channel;
            ISchema      schema;

            IEnumerable <IPayload>    payloads;
            IEnumerable <ISyncRecord> records;

            if ((object)context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if ((object)configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            this.AssertValidConfiguration();

            TTextualConnectorSpecificConfiguration fsConfig = this.Configuration.StageSpecificConfiguration;

            if (!context.LocalState.TryGetValue(this, out IDictionary <string, object> localState))
            {
                localState = new Dictionary <string, object>(StringComparer.OrdinalIgnoreCase);
                context.LocalState.Add(this, localState);
            }

            schema = localState[Constants.ContextComponentScopedSchema] as ISchema;

            if ((object)schema == null)
            {
                throw new SyncPremException(nameof(schema));
            }

            schema = localState[Constants.ContextComponentScopedSchema] as ISchema;

            if ((object)schema == null)
            {
                throw new SyncPremException(nameof(schema));
            }

            payloads = this.TextualReader.ReadRecords();

            if ((object)payloads == null)
            {
                throw new SyncPremException(nameof(payloads));
            }

            records = payloads.Select(rec => new DefaultSyncRecord(schema, rec, string.Empty, Partition.None, Offset.None));

            if ((object)records == null)
            {
                throw new SyncPremException(nameof(records));
            }

            channel = context.CreateChannel(records);

            return(channel);
        }
        protected override void ConsumeInternal(ISyncContext context, RecordConfiguration configuration, ISyncChannel channel)
        {
            IEnumerable <ISyncRecord> records;

            if ((object)context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if ((object)configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            if ((object)channel == null)
            {
                throw new ArgumentNullException(nameof(channel));
            }

            this.AssertValidConfiguration();

            records = channel.Records;

            if ((object)records == null)
            {
                throw new SyncPremException(nameof(records));
            }

            var payloads = channel.Records.Select(p => p.Payload);

            this.TextualWriter.WriteRecords(payloads);
        }
示例#4
0
        public LimitObserver(ITrackingService trackingService,
                             IRepository repository,
                             IAppChangedNotifier appChangedNotifier,
                             IMidnightNotifier midnightNotifier,
                             ILimitHandler limitHandler,
                             IAppDurationCalc appDurationCalc,
                             Mediator mediator,
                             ISyncContext syncContext)
        {
            this.trackingService    = trackingService;
            this.repository         = repository;
            this.appChangedNotifier = appChangedNotifier;
            this.midnightNotifier   = midnightNotifier;
            this.limitHandler       = limitHandler;
            this.appDurationCalc    = appDurationCalc;
            this.mediator           = mediator;

            limitNotifiers.Add(new LimitNotifier(syncContext, LimitSpan.Day));
            limitNotifiers.Add(new LimitNotifier(syncContext, LimitSpan.Week));

            foreach (var notifier in limitNotifiers)
            {
                notifier.LimitReached += OnLimitReached;
            }

            mediator.Register(MediatorMessages.APP_LIMITS_CHANGIING, LoadAppLimits);
        }
示例#5
0
        protected override void ConsumeInternal(ISyncContext context, RecordConfiguration configuration, ISyncChannel channel)
        {
            IEnumerable <IRecord> records;

            if ((object)context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if ((object)configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            if ((object)channel == null)
            {
                throw new ArgumentNullException(nameof(channel));
            }

            this.AssertValidConfiguration();

            records = channel.Records;

            if ((object)records == null)
            {
                throw new SyncPremException(nameof(records));
            }

            records.ForceEnumeration();             // force execution
        }
示例#6
0
        protected override void PreExecuteInternal(ISyncContext context, RecordConfiguration configuration)
        {
            ISchema schema;

            if ((object)context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if ((object)configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            this.AssertValidConfiguration();

            if (!context.LocalState.TryGetValue(this, out IDictionary <string, object> localState))
            {
                localState = new Dictionary <string, object>(StringComparer.OrdinalIgnoreCase);
                context.LocalState.Add(this, localState);
            }

            schema = Schema;

            if ((object)schema == null)
            {
                throw new SyncPremException(nameof(schema));
            }

            localState.Add(Constants.ContextComponentScopedSchema, schema);
        }
示例#7
0
        private async Task <ReadDeltaResult> ReadDelta(ISyncContext context, IDocumentStorageProvider storage, IClient dropbox, Func <Task> progressAction)
        {
            Entries delta;

            // we will load local state lazily upon first use
            var localState = new Lazy <LocalState>(() => new LocalState(storage.StateSnapshot));

            var numChangesProcessed = 0;
            var cursor = context.Cursor;

            do
            {
                delta = await dropbox.Core.Metadata.DeltaAsync(cursor, path_prefix : _options.Path, include_media_info : true);

                Debug.Assert(delta != null);
                Debug.Assert(delta.entries != null);

                // if this is a reset notification (or we start with an empty cursor),
                // we should reset local state and then restore it by iterating through delta
                if (delta.reset || String.IsNullOrEmpty(cursor))
                {
                    localState.Value.Reset();
                    numChangesProcessed++;
                }

                foreach (var entry in delta.entries.Where(IsDeleteOrAddFileDelta))
                {
                    numChangesProcessed++;

                    var path = entry.Item1.ToLowerInvariant();

                    if (entry.Item2 == null)
                    {
                        localState.Value.RemoveAtPath(path);
                    }
                    else if (!entry.Item2.is_dir)
                    {
                        localState.Value.AddAtPath(path, entry.Item2);
                    }
                }

                cursor = delta.cursor;

                if (progressAction != null)
                {
                    await progressAction();
                }
            } while (delta.has_more);

            context.Cursor = cursor;


            return(new ReadDeltaResult
            {
                ChangesProcessed = numChangesProcessed,
                PendingChanges = localState.IsValueCreated
                    ? localState.Value.ChangeList.Values
                    : null // no changes to process
            });
        }
示例#8
0
 public Synchronizer(IServerCommunicator serverCommunicator, IVaultRepositoryFactory vaultRepositoryFactory, IFileSystem fileSystem,
                     ISyncContext syncContext)
 {
     this.ServerCommunicator     = serverCommunicator;
     this.VaultRepositoryFactory = vaultRepositoryFactory;
     this.FileSystem             = fileSystem;
     this.SyncContext            = syncContext;
 }
示例#9
0
 public ScreenshotTracker(IScreenshotFactory screenshotFactory,
                          ISyncContext syncContext,
                          IRepository repository)
 {
     this.screenshotFactory = screenshotFactory;
     this.syncContext       = syncContext;
     this.repository        = repository;
 }
示例#10
0
 public IdleNotifier(ISyncContext syncContext, IAppSettingsService settingsService)
 {
     this.syncContext     = syncContext;
     this.settingsService = settingsService;
     keyboardHookCallback = new KeyboardHookCallback(KeyboardHookProc);
     mouseHookCallback    = new MouseHookCallback(MouseHookProc);
     idleTimer            = new Timer(CheckIdleState, null, TIMER_DELAY, TIMER_PERIOD);
 }
 /// <summary>
 /// Initializes the instance.
 /// </summary>
 /// <param name="writer">IKdbxWriter used to persist the document.</param>
 /// <param name="settings">Provider for database serialization settings.</param>
 /// <param name="candidate">Default location to save the document.</param>
 /// <param name="syncContext">ISyncContext for property change notifications.</param>
 /// <param name="canSave">Stupid dumb hack since StorageFiles suck on phone and have inaccurate attributes.</param>
 public DefaultFilePersistenceService(IKdbxWriter writer, IDatabaseSettingsProvider settings, IDatabaseCandidate candidate, ISyncContext syncContext, bool canSave)
 {
     this.saveSemaphore   = new SemaphoreSlim(1, 1);
     this.fileWriter      = writer ?? throw new ArgumentNullException(nameof(writer));
     this.settings        = settings ?? throw new ArgumentNullException(nameof(settings));
     this.defaultSaveFile = candidate ?? throw new ArgumentNullException(nameof(candidate));
     this.syncContext     = syncContext ?? throw new ArgumentNullException(nameof(syncContext));
     CanSave = canSave;
 }
 public VaultController(IVaultRepositoryFactory vaultRepositoryFactory, IVaultFactory vaultFactory, ISecureStringConverter secureStringConverter,
                        ISessionContext sessionContext, ISyncContext syncContext)
 {
     this.VaultRepositoryFactory = vaultRepositoryFactory;
     this.VaultFactory           = vaultFactory;
     this.SecureStringConverter  = secureStringConverter;
     this.SessionContext         = sessionContext;
     this.SyncContext            = syncContext;
 }
        // Gets a delegate that checks for application code trying to call into the SyncContext after
        // the request is already completed. The Action returned by this method could be null.
        public static Action GetSyncContextCheckDelegate(ISyncContext syncContext)
        {
            if (!IsAppVerifierEnabled)
            {
                return(null);
            }

            return(GetSyncContextCheckDelegateImpl(syncContext, HandleAppVerifierException));
        }
示例#14
0
        protected override void ProcessResponse(ISyncContext context, UserRequest request, UserResponse response)
        {
            AddNewUsers(context, response.users);
            context.DBVars()["LastUserRowVersion"] = response.lastRowVersion.ToHexString();

            var receiveUsers = response.users.Length;

            context.StatisticsContainer.AddValue(JanusATInfo.UsersStats, receiveUsers);
        }
        protected override void ConsumeMessageReader(ISyncContext context, RecordConfiguration configuration, DbDataReader sourceDataReader)
        {
            long _rowsCopied = 0;

            //SqlRowsCopiedEventHandler callback;

            if ((object)context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if ((object)configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            if ((object)sourceDataReader == null)
            {
                throw new ArgumentNullException(nameof(sourceDataReader));
            }

            this.AssertValidConfiguration();

            AdoNetConnectorSpecificConfiguration fsConfig = this.Configuration.StageSpecificConfiguration;

            if ((object)fsConfig.ExecuteCommand == null)
            {
                throw new InvalidOperationException(string.Format("Configuration missing: '{0}'.", nameof(fsConfig.ExecuteCommand)));
            }

            if (SolderFascadeAccessor.DataTypeFascade.IsNullOrWhiteSpace(fsConfig.ExecuteCommand.CommandText))
            {
                throw new InvalidOperationException(string.Format("Configuration missing: '{0}.{1}'.", nameof(fsConfig.ExecuteCommand), nameof(fsConfig.ExecuteCommand.CommandText)));
            }

            using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy((SqlConnection)this.DestinationUnitOfWork.Connection, SqlBulkCopyOptions.Default, (SqlTransaction)this.DestinationUnitOfWork.Transaction))
            {
                //callback = (sender, e) => Console.WriteLine(_rowsCopied = e.RowsCopied);

                foreach (FieldConfiguration columnConfiguration in configuration.ColumnConfigurations)
                {
                    sqlBulkCopy.ColumnMappings.Add(columnConfiguration.FieldName, columnConfiguration.FieldName);
                }

                sqlBulkCopy.EnableStreaming = true;
                sqlBulkCopy.BatchSize       = 2500;
                sqlBulkCopy.NotifyAfter     = 2500;
                //sqlBulkCopy.SqlRowsCopied += callback;
                sqlBulkCopy.DestinationTableName = fsConfig.ExecuteCommand.CommandText;

                sqlBulkCopy.WriteToServer(sourceDataReader);

                //sqlBulkCopy.SqlRowsCopied -= callback;
            }

            //rowsCopied = _rowsCopied;
        }
		protected override void PreExecuteInternal(ISyncContext context, RecordConfiguration configuration)
		{
			if ((object)context == null)
				throw new ArgumentNullException(nameof(context));

			if ((object)configuration == null)
				throw new ArgumentNullException(nameof(configuration));

			this.AssertValidConfiguration();
		}
 public VaultExplorerController(IVaultRepositoryFactory vaultRepositoryFactory, ISessionContext sessionContext,
                                IVaultManipulatorFactory vaultManipulatorFactory, ISyncContext syncContext,
                                IPasswordGenerator passwordGenerator)
 {
     this.VaultRepositoryFactory  = vaultRepositoryFactory;
     this.SessionContext          = sessionContext;
     this.VaultManipulatorFactory = vaultManipulatorFactory;
     this.SyncContext             = syncContext;
     this.PasswordGenerator       = passwordGenerator;
 }
 protected override void ProcessResponse(ISyncContext context, TopicRequest request, TopicResponse response)
 {
     MessagesSyncHelper.AddNewMessages(
         context,
         response.Messages,
         response.Rating,
         response.Moderate,
         _outboxManager.DownloadTopics.Clear,
         GetSyncConfig().SelfID);
 }
示例#19
0
        private IObject FindDirectory(IDirectoryObject directory, ISyncContext context)
        {
            var destination = new DirectoryObject(GetObjectPathRelativeToThisContainer(directory), context.ExecutionContext.ServiceContainer.Get <IFileSystem>());

            if (!destination.Exists)
            {
                return(null);
            }

            return(destination);
        }
示例#20
0
 private void PerformSyncProvider(ISyncContext context, Action <T> runner)
 {
     using (var svc = CreateAndInitService())
     {
         _serviceProvider.LogInfo(SyncResources.StartWith.FormatStr(svc.Url));
         InitTransferProgress(context, svc);
         runner(svc);
         AddTrafficStats(context, svc);
         OnSyncSessionFinished(svc);
     }
 }
示例#21
0
        private static void AddTrafficStats(ISyncContext ctx, T svc)
        {
            var notificator = svc as ITransferNotificator;

            if (notificator == null)
            {
                return;
            }
            ctx.AddUploadStats(notificator.TotalUploaded);
            ctx.AddDownloadStats(notificator.TotalDownloaded);
        }
示例#22
0
        private IEnumerable <IOperation> AddFile(IFileObject file, ISyncContext context)
        {
            var destination = new FileObject(GetObjectPathRelativeToThisContainer(file), context.ExecutionContext.ServiceContainer.Get <IFileSystem>());

            if (!destination.Parent.Exists)
            {
                yield return(new CreateDirectoryOperation((IDirectoryObject)destination.Parent, context.ExecutionContext.ServiceContainer.Get <IFileSystem>(), context.ExecutionContext));
            }

            yield return(new CopyFileOperation(file, destination, context.ExecutionContext.ServiceContainer.Get <IFileSystem>(), context.ExecutionContext));
        }
        protected override ForumRequest PrepareRequest(ISyncContext context)
        {
            var cfg = GetSyncConfig();

            return
                (new ForumRequest
            {
                userName = cfg.Login,
                password = cfg.Password,
                forumsRowVersion = context.DBVars()[_lastForumListRowVersion].FromHexString(),
            });
        }
示例#24
0
        public AppChangedNotifier(IWindowChangedNotifier windowChangedHook,
                                  ITitleChangedNotifier titleChangedHook,
                                  ISyncContext syncContext)
        {
            this.windowChangedHook = windowChangedHook;
            this.titleChangedHook  = titleChangedHook;
            this.syncContext       = syncContext;
            this.windowCheckTimer  = new Timer(OnTimerTick, null, 5 * 1000, 5 * 1000);

            windowChangedSubscription = CreateWindowChangedSubscription();
            titleChangedSubscription  = CreateTitleChangedSubscription();
        }
        /// <summary>
        /// Выполнить синхронизацию.
        /// </summary>
        public void Sync(
            ISyncContext context,
            TSvc svc,
            int retries,
            ITaskIndicator indicator)
        {
            if (context == null)
                throw new ArgumentNullException("context");
            if (svc == null)
                throw new ArgumentNullException("svc");
            if (indicator == null)
                throw new ArgumentNullException("indicator");

            indicator.SetTaskState(SyncTaskState.Sync);
            try
            {
                context.CheckState();

                indicator.SetStatusText(SyncResources.IndicatorPrepareRequest);
                var rq = PrepareRequest(context);
                if (rq == null)
                    return; // Nothing to do

                context.CheckState();

                indicator.SetStatusText(SyncResources.IndicatorMakeRequest);
                var rsp = context.CallWithRetries(rq, GetDisplayName(), retries,
                    () => MakeRequest(context, svc, rq));

                context.CheckState();

                indicator.SetStatusText(SyncResources.IndicatorProcessResponse);
                ProcessResponse(context, rq, rsp);

                context.CheckState();

                indicator.SetTaskState(SyncTaskState.Succeed);
                indicator.SetStatusText(SyncResources.IndicatorSuccessFinish);
            }
            // Отмену пользователем не трактуем как ошибку и выкидываем наверх
            catch (UserCancelledException)
            {
                throw;
            }
            catch (Exception ex)
            {
                indicator.SetTaskState(SyncTaskState.Failed);
                indicator.SetStatusText(ex.Message);
                context.TryAddSyncError(
                    new SyncErrorInfo(SyncErrorType.CriticalError, GetDisplayName(), ex.ToString()));
            }
        }
示例#26
0
        protected override UserRequest PrepareRequest(ISyncContext context)
        {
            var cfg = GetSyncConfig();

            return
                (new UserRequest
            {
                userName = cfg.Login,
                password = cfg.Password,
                lastRowVersion = context.DBVars()["LastUserRowVersion"].FromHexString(),
                maxOutput = cfg.MaxUsersPerSession
            });
        }
示例#27
0
        private IObject FindFile(IFileObject file, ISyncContext context)
        {
            // TODO: Detect moved/renamed files to avoid unnecessary delete/copy operations

            var destination = new FileObject(GetObjectPathRelativeToThisContainer(file), context.ExecutionContext.ServiceContainer.Get <IFileSystem>());

            if (!destination.Exists)
            {
                return(null);
            }

            return(destination);
        }
示例#28
0
        private static void ExecutePipeline(SemaphoreSlim semaphoreSlim, Type pipelineType, PipelineConfiguration configuration)
        {
            ISyncPipeline pipeline;

            try
            {
                if ((object)semaphoreSlim == null)
                {
                    throw new ArgumentNullException(nameof(semaphoreSlim));
                }

                if ((object)pipelineType == null)
                {
                    throw new ArgumentNullException(nameof(pipelineType));
                }

                if ((object)configuration == null)
                {
                    throw new ArgumentNullException(nameof(configuration));
                }

                pipeline = (ISyncPipeline)Activator.CreateInstance(pipelineType);

                if ((object)pipeline == null)
                {
                    throw new InvalidOperationException(nameof(pipeline));
                }

                using (pipeline)
                {
                    pipeline.Configuration = configuration;
                    pipeline.Create();

                    using (ISyncContext context = pipeline.CreateContext())
                    {
                        context.Create();

                        pipeline.Execute(context);
                    }
                }
            }
            finally
            {
                Thread.Sleep(10000);

                if ((object)semaphoreSlim != null)
                {
                    semaphoreSlim.Release();
                }
            }
        }
示例#29
0
        protected override void ConsumeInternal(ISyncContext context, RecordConfiguration configuration, ISyncChannel channel)
        {
            ISchema schema = null;
            IEnumerable <ISyncRecord> records;

            DbDataReader sourceDataReader;
            long         rowsCopied;

            if ((object)context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if ((object)configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            if ((object)channel == null)
            {
                throw new ArgumentNullException(nameof(channel));
            }

            this.AssertValidConfiguration();

            records = channel.Records;

            if ((object)records == null)
            {
                throw new SyncPremException(nameof(records));
            }

            sourceDataReader = null;             //new AdoNetStreamingPayloadDataReader(schema.Fields.Values, records.Select(r => r.Payload));

            try
            {
                this.ConsumeMessageReader(context, configuration, sourceDataReader);
            }
            finally
            {
                // just in case ConsumeMessageReader did not or could not enumerate to completion for disposal...
                do
                {
                    while (sourceDataReader.Read())
                    {
                        ;
                    }
                }while (sourceDataReader.NextResult())
                ;
            }
        }
示例#30
0
        public override IEnumerable <IOperation> AddObject(IObject obj, ISyncContext context)
        {
            if (obj is IFileObject)
            {
                return(AddFile((IFileObject)obj, context));
            }

            if (obj is IDirectoryObject)
            {
                return(AddDirectory((IDirectoryObject)obj, context));
            }

            throw new NotSupportedException();
        }
示例#31
0
		public static void AddNewMessages(
			ISyncContext context,
			JanusMessageInfo[] messages,
			JanusRatingInfo[] rates,
			JanusModerateInfo[] moderatorials,
			int selfID)
		{
			AddNewMessages(
				context,
				messages,
				rates,
				moderatorials,
				null,
				selfID);
		}
 internal AspNetSynchronizationContext(ISyncContext syncContext)
     : this(new State(new SynchronizationHelper(syncContext))) {
 }
示例#33
0
        private void PerformSyncProvider(
            ISyncContext context,
            string provName,
            string taskName)
        {
            var syncProv = _syncProvidersCache.GetExtension(provName);
            if (syncProv == null)
                throw new ArgumentException("Unknown provider.");

            if (taskName == null)
                syncProv.SyncPeriodicTasks(context);
            else
                syncProv.SyncTask(context, taskName);
        }
示例#34
0
 public static void Init(ISyncContext context)
 {
     Current = context;
 }
示例#35
0
		public static void AddNewMessages(
			ISyncContext context,
			JanusMessageInfo[] messages,
			JanusRatingInfo[] rates,
			JanusModerateInfo[] moderatorials,
			Action<IDataContext> afterProcessInTxHandler,
			int selfID)
		{
			if (messages == null)
				throw new ArgumentNullException(nameof(messages));
			if (rates == null)
				throw new ArgumentNullException(nameof(rates));
			if (messages.Length == 0 && rates.Length == 0)
				// Nothing to do
				return;

			context.LogInfo(Resources.ProcessMessages);

			var msgIds = Array<int>.Empty;
			// Затычка. Блокируем интерфейс на время обработки сообщений.
			using (context.GetRequiredService<IUIShell>().FreezeUI(context))
			using (context.GetRequiredService<IJanusDatabaseManager>().GetLock().GetWriterLock())
			{
				var dbMgr = context.GetRequiredService<IJanusDatabaseManager>();
				using (var db = dbMgr.CreateDBContext())
				using (var tx = db.BeginTransaction())
				{
					var tids = new HashSet<int>();
					var pgSvc = context.GetService<ISyncProgressVisualizer>();

					var topicIds = Array<int>.Empty;
					if (messages.Length > 0)
						AddMessages(
							context,
							db,
							messages,
							selfID,
							pgSvc != null
								? (total, current) =>
									{
										pgSvc.ReportProgress(total, current);
										pgSvc.SetProgressText(
											current
												.GetDeclension(
													Resources.NewMsgProcessingProgressText1,
													Resources.NewMsgProcessingProgressText2,
													Resources.NewMsgProcessingProgressText5)
												.FormatWith(current));
									}
								: (Action<int, int>) null,
							out topicIds,
							out msgIds);
					foreach (var msg in messages)
						tids.Add(msg.topicId != 0 ? msg.topicId : msg.messageId);
					foreach (var id in topicIds)
						tids.Add(id);

					AddNewRates(
						db,
						rates,
						pgSvc != null
							? (total, current) =>
								{
									pgSvc.ReportProgress(total, current);
									pgSvc.SetProgressText(
										current
											.GetDeclension(
												Resources.NewRatesProcessingProgress1,
												Resources.NewRatesProcessingProgress2,
												Resources.NewRatesProcessingProgress5)
											.FormatWith(current));
								}
							: (Action<int, int>) null);
					foreach (var rate in rates)
						tids.Add(rate.topicId != 0 ? rate.topicId : rate.messageId);

					AddModeratorials(db, moderatorials);

					// Вариант с получением топиков с сервера
					foreach (var tid in moderatorials.Select(
						mod => mod.topicId == 0 ? mod.messageId : mod.topicId))
						tids.Add(tid);

					context.GetRequiredService<IRsdnForumService>().UpdateForumAggregates(context, db, tids);

					afterProcessInTxHandler?.Invoke(db);

					tx.Commit();
					GC.KeepAlive(db);
				}
			}

			AddBrokenTopicRequests(context, messages);

			var searchSvc = context.GetRequiredService<ISearchService>();
			var addedCount =
				searchSvc.AddMessagesToIndex(
					messages.Select(
						svcMsg =>
							new MessageSearchInfo(
								svcMsg.messageId,
								svcMsg.messageDate,
								svcMsg.subject,
								svcMsg.message,
								svcMsg.forumId,
								svcMsg.userId,
								svcMsg.userNick)));
			context.StatisticsContainer.AddValue(JanusATInfo.IndexedMessagesStats, addedCount);

			context.LogInfo(
				Resources
					.DownloadTopicsStat
					.FormatWith(
						msgIds.Length,
						msgIds.Length.GetDeclension(
							Resources.Messages1,
							Resources.Messages2,
							Resources.Messages5)));

			context.StatisticsContainer.AddValue(JanusATInfo.MessagesStats, messages.Length);
			context.StatisticsContainer.AddValue(JanusATInfo.RatesStats, rates.Length);
			context.StatisticsContainer.AddValue(JanusATInfo.ModeratorialsStats, moderatorials.Length);
		}
        private readonly Action _appVerifierCallback; // for making sure that developers don't try calling us after the request has completed

        public SynchronizationHelper(ISyncContext syncContext) {
            _syncContext = syncContext;
            _appVerifierCallback = AppVerifier.GetSyncContextCheckDelegate(syncContext);
        }