// (c) Copyright Ascensio System SIA 2010-2022 // // This program is a free software product. // You can redistribute it and/or modify it under the terms // of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software // Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended // to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of // any third-party rights. // // This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see // the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html // // You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021. // // The interactive user interfaces in modified source and object code versions of the Program must // display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3. // // Pursuant to Section 7(b) of the License you must retain the original Product logo when // distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under // trademark law for use of our trademarks. // // All the Product's GUI elements, including illustrations and icon sets, as well as technical writing // content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode namespace ASC.Data.Storage; [Singletone] public class StorageUploader { protected readonly DistributedTaskQueue _queue; private static readonly object _locker; private readonly IServiceProvider _serviceProvider; private readonly TempStream _tempStream; private readonly ICacheNotify _cacheMigrationNotify; private readonly ILogger _logger; static StorageUploader() { _locker = new object(); } public StorageUploader( IServiceProvider serviceProvider, TempStream tempStream, ICacheNotify cacheMigrationNotify, IDistributedTaskQueueFactory queueFactory, ILogger logger) { _serviceProvider = serviceProvider; _tempStream = tempStream; _cacheMigrationNotify = cacheMigrationNotify; _logger = logger; _queue = queueFactory.CreateQueue(); } public void Start(int tenantId, StorageSettings newStorageSettings, StorageFactoryConfig storageFactoryConfig) { lock (_locker) { var id = GetCacheKey(tenantId); if (_queue.GetAllTasks().Any(x => x.Id == id)) { return; } var migrateOperation = new MigrateOperation(_serviceProvider, _cacheMigrationNotify, id, tenantId, newStorageSettings, storageFactoryConfig, _tempStream, _logger); _queue.EnqueueTask(migrateOperation); } } public MigrateOperation GetProgress(int tenantId) { lock (_locker) { return _queue.PeekTask(GetCacheKey(tenantId)); } } public void Stop() { foreach (var task in _queue.GetAllTasks(DistributedTaskQueue.INSTANCE_ID).Where(r => r.Status == DistributedTaskStatus.Running)) { _queue.DequeueTask(task.Id); } } private static string GetCacheKey(int tenantId) { return typeof(MigrateOperation).FullName + tenantId; } } [Transient] public class MigrateOperation : DistributedTaskProgress { private static readonly string _configPath; private readonly ILogger _logger; private readonly IEnumerable _modules; private readonly StorageSettings _settings; private readonly int _tenantId; private readonly IServiceProvider _serviceProvider; private readonly StorageFactoryConfig _storageFactoryConfig; private readonly TempStream _tempStream; private readonly ICacheNotify _cacheMigrationNotify; static MigrateOperation() { _configPath = string.Empty; } public MigrateOperation( IServiceProvider serviceProvider, ICacheNotify cacheMigrationNotify, string id, int tenantId, StorageSettings settings, StorageFactoryConfig storageFactoryConfig, TempStream tempStream, ILogger logger) { Id = id; Status = DistributedTaskStatus.Created; _serviceProvider = serviceProvider; _cacheMigrationNotify = cacheMigrationNotify; _tenantId = tenantId; _settings = settings; _storageFactoryConfig = storageFactoryConfig; _tempStream = tempStream; _modules = storageFactoryConfig.GetModuleList(_configPath, true); StepCount = _modules.Count(); _logger = logger; } public object Clone() { return MemberwiseClone(); } protected override void DoJob() { try { _logger.DebugTenant(_tenantId); Status = DistributedTaskStatus.Running; using var scope = _serviceProvider.CreateScope(); var tempPath = scope.ServiceProvider.GetService(); var scopeClass = scope.ServiceProvider.GetService(); var (tenantManager, securityContext, storageFactory, options, storageSettingsHelper, settingsManager) = scopeClass; var tenant = tenantManager.GetTenant(_tenantId); tenantManager.SetCurrentTenant(tenant); securityContext.AuthenticateMeWithoutCookie(tenant.OwnerId); foreach (var module in _modules) { var oldStore = storageFactory.GetStorage(_configPath, _tenantId.ToString(), module); var store = storageFactory.GetStorageFromConsumer(_configPath, _tenantId.ToString(), module, storageSettingsHelper.DataStoreConsumer(_settings)); var domains = _storageFactoryConfig.GetDomainList(_configPath, module).ToList(); var crossModuleTransferUtility = new CrossModuleTransferUtility(options, _tempStream, tempPath, oldStore, store); string[] files; foreach (var domain in domains) { //Status = module + domain; _logger.DebugDomain(domain); files = oldStore.ListFilesRelativeAsync(domain, "\\", "*.*", true).ToArrayAsync().Result; foreach (var file in files) { _logger.DebugFile(file); crossModuleTransferUtility.CopyFileAsync(domain, file, domain, file).Wait(); } } files = oldStore.ListFilesRelativeAsync(string.Empty, "\\", "*.*", true).ToArrayAsync().Result .Where(path => domains.All(domain => !path.Contains(domain + "/"))) .ToArray(); foreach (var file in files) { _logger.DebugFile(file); crossModuleTransferUtility.CopyFileAsync("", file, "", file).Wait(); } StepDone(); MigrationPublish(); } settingsManager.Save(_settings); tenant.SetStatus(TenantStatus.Active); tenantManager.SaveTenant(tenant); Status = DistributedTaskStatus.Completed; } catch (Exception e) { Status = DistributedTaskStatus.Failted; Exception = e; _logger.ErrorMigrateOperation(e); } MigrationPublish(); } private void MigrationPublish() { _cacheMigrationNotify.Publish(new MigrationProgress { TenantId = _tenantId, Progress = Percentage, Error = Exception.ToString(), IsCompleted = IsCompleted }, CacheNotifyAction.Insert); } } public class MigrateOperationScope { private readonly TenantManager _tenantManager; private readonly SecurityContext _securityContext; private readonly StorageFactory _storageFactory; private readonly ILogger _options; private readonly StorageSettingsHelper _storageSettingsHelper; private readonly SettingsManager _settingsManager; public MigrateOperationScope(TenantManager tenantManager, SecurityContext securityContext, StorageFactory storageFactory, ILogger options, StorageSettingsHelper storageSettingsHelper, SettingsManager settingsManager) { _tenantManager = tenantManager; _securityContext = securityContext; _storageFactory = storageFactory; _options = options; _storageSettingsHelper = storageSettingsHelper; _settingsManager = settingsManager; } public void Deconstruct(out TenantManager tenantManager, out SecurityContext securityContext, out StorageFactory storageFactory, out ILogger options, out StorageSettingsHelper storageSettingsHelper, out SettingsManager settingsManager) { tenantManager = _tenantManager; securityContext = _securityContext; storageFactory = _storageFactory; options = _options; storageSettingsHelper = _storageSettingsHelper; settingsManager = _settingsManager; } }