2022-06-08 14:25:25 +00:00
|
|
|
|
// (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.Files.ThumbnailBuilder;
|
|
|
|
|
|
|
|
|
|
[Singletone(Additional = typeof(FileConverterQueueExtension))]
|
|
|
|
|
internal class FileConverterService<T> : BackgroundService
|
|
|
|
|
{
|
|
|
|
|
private readonly IServiceScopeFactory _serviceScopeFactory;
|
|
|
|
|
private readonly int _timerDelay = 1000;
|
2022-06-09 14:02:19 +00:00
|
|
|
|
private readonly ILogger<FileConverterService<T>> _logger;
|
2022-06-08 14:25:25 +00:00
|
|
|
|
|
|
|
|
|
public FileConverterService(
|
2022-06-09 14:02:19 +00:00
|
|
|
|
IServiceScopeFactory serviceScopeFactory,
|
|
|
|
|
ILogger<FileConverterService<T>> logger)
|
2022-06-08 14:25:25 +00:00
|
|
|
|
{
|
2022-06-09 14:02:19 +00:00
|
|
|
|
_logger = logger;
|
2022-06-08 14:25:25 +00:00
|
|
|
|
_serviceScopeFactory = serviceScopeFactory;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
|
|
|
{
|
2022-06-17 16:19:00 +00:00
|
|
|
|
_logger.DebugFileConverterServiceRuning();
|
|
|
|
|
|
2022-06-09 14:02:19 +00:00
|
|
|
|
stoppingToken.Register(() => _logger.DebugFileConverterServiceStopping());
|
|
|
|
|
|
2022-06-08 14:25:25 +00:00
|
|
|
|
while (!stoppingToken.IsCancellationRequested)
|
|
|
|
|
{
|
|
|
|
|
using var serviceScope = _serviceScopeFactory.CreateScope();
|
|
|
|
|
|
|
|
|
|
var registerInstanceService = serviceScope.ServiceProvider.GetService<IRegisterInstanceManager<FileConverterService<T>>>();
|
|
|
|
|
|
|
|
|
|
if (!await registerInstanceService.IsActive(RegisterInstanceWorkerService<FileConverterService<T>>.InstanceId))
|
|
|
|
|
{
|
|
|
|
|
await Task.Delay(1000, stoppingToken);
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await ExecuteCheckFileConverterStatus(serviceScope);
|
|
|
|
|
|
|
|
|
|
await Task.Delay(_timerDelay, stoppingToken);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task ExecuteCheckFileConverterStatus(IServiceScope scope)
|
|
|
|
|
{
|
|
|
|
|
TenantManager tenantManager;
|
|
|
|
|
UserManager userManager;
|
|
|
|
|
SecurityContext securityContext;
|
|
|
|
|
IDaoFactory daoFactory;
|
|
|
|
|
FileSecurity fileSecurity;
|
|
|
|
|
PathProvider pathProvider;
|
|
|
|
|
SetupInfo setupInfo;
|
|
|
|
|
FileUtility fileUtility;
|
|
|
|
|
DocumentServiceHelper documentServiceHelper;
|
|
|
|
|
DocumentServiceConnector documentServiceConnector;
|
|
|
|
|
EntryStatusManager entryManager;
|
|
|
|
|
FileConverter fileConverter;
|
|
|
|
|
FileConverterQueue<T> fileConverterQueue;
|
|
|
|
|
|
2022-06-17 16:19:00 +00:00
|
|
|
|
var logger = scope.ServiceProvider.GetService<ILogger<FileConverterQueue<T>>>();
|
|
|
|
|
|
2022-06-08 14:25:25 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
fileConverterQueue = scope.ServiceProvider.GetService<FileConverterQueue<T>>();
|
|
|
|
|
|
2022-06-09 14:38:27 +00:00
|
|
|
|
var _conversionQueue = fileConverterQueue.GetAllTask().ToList();
|
2022-06-08 14:25:25 +00:00
|
|
|
|
|
2022-06-09 14:02:19 +00:00
|
|
|
|
logger.DebugRunCheckConvertFilesStatus(_conversionQueue.Count);
|
2022-06-08 14:25:25 +00:00
|
|
|
|
|
|
|
|
|
var filesIsConverting = _conversionQueue
|
|
|
|
|
.Where(x => string.IsNullOrEmpty(x.Processed))
|
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
foreach (var converter in filesIsConverting)
|
2022-06-20 16:58:08 +00:00
|
|
|
|
{
|
|
|
|
|
converter.Processed = "1";
|
|
|
|
|
|
2022-06-08 14:25:25 +00:00
|
|
|
|
var fileId = JsonDocument.Parse(converter.Source).RootElement.GetProperty("id").Deserialize<T>();
|
|
|
|
|
var fileVersion = JsonDocument.Parse(converter.Source).RootElement.GetProperty("version").Deserialize<int>();
|
|
|
|
|
|
|
|
|
|
int operationResultProgress;
|
|
|
|
|
var password = converter.Password;
|
|
|
|
|
|
|
|
|
|
var commonLinkUtilitySettings = scope.ServiceProvider.GetService<CommonLinkUtilitySettings>();
|
2022-07-12 11:18:26 +00:00
|
|
|
|
commonLinkUtilitySettings.ServerUri = converter.ServerRootPath;
|
|
|
|
|
|
|
|
|
|
var scopeClass = scope.ServiceProvider.GetService<FileConverterQueueScope>();
|
|
|
|
|
(_, tenantManager, userManager, securityContext, daoFactory, fileSecurity, pathProvider, setupInfo, fileUtility, documentServiceHelper, documentServiceConnector, entryManager, fileConverter) = scopeClass;
|
2022-06-08 14:25:25 +00:00
|
|
|
|
|
|
|
|
|
tenantManager.SetCurrentTenant(converter.TenantId);
|
|
|
|
|
|
|
|
|
|
securityContext.AuthenticateMeWithoutCookie(converter.Account);
|
|
|
|
|
|
|
|
|
|
var file = await daoFactory.GetFileDao<T>().GetFileAsync(fileId, fileVersion);
|
|
|
|
|
var fileUri = file.Id.ToString();
|
|
|
|
|
|
|
|
|
|
string convertedFileUrl;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
var user = userManager.GetUsers(converter.Account);
|
|
|
|
|
|
|
|
|
|
var culture = string.IsNullOrEmpty(user.CultureName) ? tenantManager.GetCurrentTenant().GetCulture() : CultureInfo.GetCultureInfo(user.CultureName);
|
|
|
|
|
|
|
|
|
|
Thread.CurrentThread.CurrentCulture = culture;
|
|
|
|
|
Thread.CurrentThread.CurrentUICulture = culture;
|
|
|
|
|
|
2022-07-13 17:09:43 +00:00
|
|
|
|
if (!await fileSecurity.CanReadAsync(file) && file.RootFolderType != FolderType.BUNCH)
|
2022-06-08 14:25:25 +00:00
|
|
|
|
{
|
|
|
|
|
//No rights in CRM after upload before attach
|
|
|
|
|
throw new System.Security.SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ReadFile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (file.ContentLength > setupInfo.AvailableFileSize)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception(string.Format(FilesCommonResource.ErrorMassage_FileSizeConvert, FileSizeComment.FilesSizeToString(setupInfo.AvailableFileSize)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fileUri = pathProvider.GetFileStreamUrl(file);
|
|
|
|
|
|
|
|
|
|
var toExtension = fileUtility.GetInternalExtension(file.Title);
|
|
|
|
|
var fileExtension = file.ConvertedExtension;
|
|
|
|
|
var docKey = documentServiceHelper.GetDocKey(file);
|
|
|
|
|
|
|
|
|
|
fileUri = documentServiceConnector.ReplaceCommunityAdress(fileUri);
|
2022-07-13 17:09:43 +00:00
|
|
|
|
(operationResultProgress, convertedFileUrl) = await documentServiceConnector.GetConvertedUriAsync(fileUri, fileExtension, toExtension, docKey, password, CultureInfo.CurrentUICulture.Name, null, null, true);
|
2022-06-08 14:25:25 +00:00
|
|
|
|
}
|
|
|
|
|
catch (Exception exception)
|
|
|
|
|
{
|
|
|
|
|
var password1 = exception.InnerException is DocumentServiceException documentServiceException
|
|
|
|
|
&& documentServiceException.Code == DocumentServiceException.ErrorCode.ConvertPassword;
|
|
|
|
|
|
|
|
|
|
logger.ErrorConvertFileWithUrl(file.Id.ToString(), fileUri, exception);
|
|
|
|
|
|
|
|
|
|
var operationResult = converter;
|
|
|
|
|
|
|
|
|
|
if (operationResult.Delete)
|
|
|
|
|
{
|
|
|
|
|
_conversionQueue.Remove(operationResult);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
operationResult.Progress = 100;
|
|
|
|
|
operationResult.StopDateTime = DateTime.UtcNow;
|
|
|
|
|
operationResult.Error = exception.Message;
|
|
|
|
|
|
|
|
|
|
if (password1)
|
|
|
|
|
{
|
|
|
|
|
operationResult.Result = "password";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
operationResultProgress = Math.Min(operationResultProgress, 100);
|
|
|
|
|
|
|
|
|
|
if (operationResultProgress < 100)
|
|
|
|
|
{
|
|
|
|
|
var operationResult = converter;
|
|
|
|
|
|
2022-06-20 16:58:08 +00:00
|
|
|
|
if (DateTime.UtcNow - operationResult.StartDateTime > TimeSpan.FromMinutes(10))
|
2022-06-08 14:25:25 +00:00
|
|
|
|
{
|
|
|
|
|
operationResult.StopDateTime = DateTime.UtcNow;
|
|
|
|
|
operationResult.Error = FilesCommonResource.ErrorMassage_ConvertTimeout;
|
|
|
|
|
|
|
|
|
|
logger.ErrorCheckConvertFilesStatus(file.Id.ToString(), file.ContentLength);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
operationResult.Processed = "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
operationResult.Progress = operationResultProgress;
|
|
|
|
|
|
|
|
|
|
logger.DebugCheckConvertFilesStatusIterationContinue();
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
File<T> newFile = null;
|
|
|
|
|
|
|
|
|
|
var operationResultError = string.Empty;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2022-07-13 17:09:43 +00:00
|
|
|
|
newFile = await fileConverter.SaveConvertedFileAsync(file, convertedFileUrl);
|
2022-06-08 14:25:25 +00:00
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
operationResultError = e.Message;
|
|
|
|
|
|
|
|
|
|
logger.ErrorOperation(operationResultError, convertedFileUrl, fileUri, e);
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
var operationResult = converter;
|
|
|
|
|
|
|
|
|
|
if (operationResult.Delete)
|
|
|
|
|
{
|
|
|
|
|
_conversionQueue.Remove(operationResult);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (newFile != null)
|
|
|
|
|
{
|
|
|
|
|
var folderDao = daoFactory.GetFolderDao<T>();
|
2022-07-13 17:09:43 +00:00
|
|
|
|
var folder = await folderDao.GetFolderAsync(newFile.ParentId);
|
|
|
|
|
var folderTitle = await fileSecurity.CanReadAsync(folder) ? folder.Title : null;
|
2022-06-08 14:25:25 +00:00
|
|
|
|
|
|
|
|
|
operationResult.Result = fileConverterQueue.FileJsonSerializerAsync(entryManager, newFile, folderTitle).Result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
operationResult.Progress = 100;
|
|
|
|
|
operationResult.StopDateTime = DateTime.UtcNow;
|
|
|
|
|
operationResult.Processed = "1";
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(operationResultError))
|
|
|
|
|
{
|
|
|
|
|
operationResult.Error = operationResultError;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logger.DebugCheckConvertFilesStatusIterationEnd();
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-09 14:38:27 +00:00
|
|
|
|
fileConverterQueue.SetAllTask(_conversionQueue);
|
2022-06-08 14:25:25 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
catch (Exception exception)
|
|
|
|
|
{
|
|
|
|
|
logger.ErrorWithException(exception);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static class FileConverterQueueExtension
|
|
|
|
|
{
|
|
|
|
|
public static void Register(DIHelper services)
|
|
|
|
|
{
|
|
|
|
|
services.TryAdd<FileConverterQueueScope>();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Scope]
|
|
|
|
|
public class FileConverterQueueScope
|
|
|
|
|
{
|
|
|
|
|
private readonly ILogger _options;
|
|
|
|
|
private readonly TenantManager _tenantManager;
|
|
|
|
|
private readonly UserManager _userManager;
|
|
|
|
|
private readonly SecurityContext _securityContext;
|
|
|
|
|
private readonly IDaoFactory _daoFactory;
|
|
|
|
|
private readonly FileSecurity _fileSecurity;
|
|
|
|
|
private readonly PathProvider _pathProvider;
|
|
|
|
|
private readonly SetupInfo _setupInfo;
|
|
|
|
|
private readonly FileUtility _fileUtility;
|
|
|
|
|
private readonly DocumentServiceHelper _documentServiceHelper;
|
|
|
|
|
private readonly DocumentServiceConnector _documentServiceConnector;
|
|
|
|
|
private readonly EntryStatusManager _entryManager;
|
|
|
|
|
private readonly FileConverter _fileConverter;
|
|
|
|
|
|
|
|
|
|
public FileConverterQueueScope(
|
|
|
|
|
ILogger<FileConverterQueueScope> options,
|
|
|
|
|
TenantManager tenantManager,
|
|
|
|
|
UserManager userManager,
|
|
|
|
|
SecurityContext securityContext,
|
|
|
|
|
IDaoFactory daoFactory,
|
|
|
|
|
FileSecurity fileSecurity,
|
|
|
|
|
PathProvider pathProvider,
|
|
|
|
|
SetupInfo setupInfo,
|
|
|
|
|
FileUtility fileUtility,
|
|
|
|
|
DocumentServiceHelper documentServiceHelper,
|
|
|
|
|
DocumentServiceConnector documentServiceConnector,
|
|
|
|
|
EntryStatusManager entryManager,
|
|
|
|
|
FileConverter fileConverter)
|
|
|
|
|
{
|
|
|
|
|
_options = options;
|
|
|
|
|
_tenantManager = tenantManager;
|
|
|
|
|
_userManager = userManager;
|
|
|
|
|
_securityContext = securityContext;
|
|
|
|
|
_daoFactory = daoFactory;
|
|
|
|
|
_fileSecurity = fileSecurity;
|
|
|
|
|
_pathProvider = pathProvider;
|
|
|
|
|
_setupInfo = setupInfo;
|
|
|
|
|
_fileUtility = fileUtility;
|
|
|
|
|
_documentServiceHelper = documentServiceHelper;
|
|
|
|
|
_documentServiceConnector = documentServiceConnector;
|
|
|
|
|
_entryManager = entryManager;
|
|
|
|
|
_fileConverter = fileConverter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void Deconstruct(out ILogger optionsMonitor,
|
|
|
|
|
out TenantManager tenantManager,
|
|
|
|
|
out UserManager userManager,
|
|
|
|
|
out SecurityContext securityContext,
|
|
|
|
|
out IDaoFactory daoFactory,
|
|
|
|
|
out FileSecurity fileSecurity,
|
|
|
|
|
out PathProvider pathProvider,
|
|
|
|
|
out SetupInfo setupInfo,
|
|
|
|
|
out FileUtility fileUtility,
|
|
|
|
|
out DocumentServiceHelper documentServiceHelper,
|
|
|
|
|
out DocumentServiceConnector documentServiceConnector,
|
|
|
|
|
out EntryStatusManager entryManager,
|
|
|
|
|
out FileConverter fileConverter)
|
|
|
|
|
{
|
|
|
|
|
optionsMonitor = _options;
|
|
|
|
|
tenantManager = _tenantManager;
|
|
|
|
|
userManager = _userManager;
|
|
|
|
|
securityContext = _securityContext;
|
|
|
|
|
daoFactory = _daoFactory;
|
|
|
|
|
fileSecurity = _fileSecurity;
|
|
|
|
|
pathProvider = _pathProvider;
|
|
|
|
|
setupInfo = _setupInfo;
|
|
|
|
|
fileUtility = _fileUtility;
|
|
|
|
|
documentServiceHelper = _documentServiceHelper;
|
|
|
|
|
documentServiceConnector = _documentServiceConnector;
|
|
|
|
|
entryManager = _entryManager;
|
|
|
|
|
fileConverter = _fileConverter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|