logo

[ELMA3] Новые возможности механизма генерации предпросмотра файлов

С версии системы ELMA 3.11 значительно расширен механизм генерации файлов предпросмотра. С целью повышения производительности и управляемости генерация предпросмотра файлов вынесена разделена на две части:

  1. Внутренний сервис ELMA, осуществляющий управление очередью генерации предпросмотра, запуск и остановку генерации, и взаимодействие с пользователем;
  2. Генераторы файлов предпросмотра, выполненные в виде исполняемых exe-файлов.

Рассмотрим данный механизм подробнее. Для реализации возможности использовать «внешние» генераторы добавлен новый интерфейс генератора файлов предпросмотра, который представлен ниже.


public interface IFilePreviewCreatorEx : IFilePreviewCreator
  {
        /// <summary>
        /// Полное наименование исполняемого файла внешнего генератора предпросмотра
        /// </summary>
        string ExternalCreatorFileName { get; }

        /// <summary>
        /// Требуется внешний генератор файла предпросмотра
        /// </summary>
        /// <returns><с>true</с>, если требуется внешний генератор файла предпросмотра</returns>
        bool RequiredExternalCreator { get; }

        /// <summary>
        /// Создать файл предпросмотра используя внешний генератор
        /// </summary>
        /// <param name="filePreviewDir">Путь до директории предпросмотра</param>
        /// <param name="file">Файл</param>
        /// <returns>Процесс внешнего генератора</returns>
        Process CreateWithExternalCreator(string filePreviewDir, BinaryFile file);
    }

На основе этого интерфейса реализован расширенный базовый класс генератора:

public abstract class BaseFilePreviewCreatorEx : BaseFilePreviewCreator, IFilePreviewCreatorEx  
  {
        /// <summary>
        /// Полное наименование исполняемого файла внешнего генератора предпросмотра
        /// </summary>
        public virtual string ExternalCreatorFileName
        {
            get
            {
                return string.Empty;
            }
        }

        /// <summary>
        /// Требуется внешний генератор файла предпросмотра
        /// </summary>
        /// <returns><с>true</с>, если требуется внешний генератор файла предпросмотра</returns>
        public virtual bool RequiredExternalCreator
        {
            get { return true; }
        }

        /// <summary>
        /// Создать файл предпросмотра используя внешний генератор
        /// </summary>
        /// <param name="filePreviewDir">Путь до директории предпросмотра</param>
        /// <param name="file">Файл</param>
        /// <returns>Процесс внешнего генератора</returns>
        public virtual Process CreateWithExternalCreator(string filePreviewDir, BinaryFile file)
        {
            var packageService = Locator.GetService<PackageService>();

            if (packageService == null)
            {
                return null;
            }
            packageService.CheckInitialized();

            var component = packageService.GetComponent("FilePreviewCreator");

            if (component == null)
            {
                return null;
            }

            var documentPath = GetMainFileName(filePreviewDir, file);

            if (ExternalCreatorFileName.IsNullOrEmpty() || documentPath.IsNullOrEmpty() || file.ContentFilePath.IsNullOrEmpty())
            {
                return null;
            }

            var externalCreator = new Process
            {
                StartInfo =
                {
                    FileName = Path.Combine(component.ComponentRoot, ExternalCreatorFileName),
                    Arguments = string.Format("\"{0}\" \"{1}\"", documentPath, file.ContentFilePath),
                    UseShellExecute = false
                }
            };

            if (externalCreator.Start())
            {
                return externalCreator;
            }

            return null;
        }
    }
}

Основной функцией данного базового класса, является Process CreateWithExternalCreator(string filePreviewDir, BinaryFile file), которая принимает два параметра: filePreviewDir – полный путь до директории, куда должен быть сохранен сгенерированный файл предросмотра, file – файл документа, для которого производится генерация. Возвращаемый результат – указатель на процесс «внешнего» генератора предпросмотра.

Как видно из кода данной функции, она производит запуск исполняемого exe-файла генератора, в который через командую строку передает два параметра: полный путь до генерируемого файла предпросмотра, полный путь до файла, для которого производится генерация файлов предпросмотра. Следует отметить, что данная функция является виртуальной, таким образом при реализации собственных генераторов предпросмотра, Вы можете переопределить ее функционал в Вашей реализации базового класса BaseFilePreviewCreatorEx.

В системе ELMA 3.11 присутствует стандартная реализация провайдера генерации предпросмотра, выполненная в виде отдельной сборки EleWise.ELMA.FilePreview.LocalService.

Следует отметить, что EleWise.ELMA.FilePreview.LocalService отслеживает использование ресурсов сервера внешними генераторами, а именно отслеживает время работы (maxTimeWork [c]) и объем используемой оперативной памяти (maxMemoryUsage [Мб]), лимиты которых задаются через файл конфигурации системы. Превышение данных параметров приводит к завершению работы процесса генератора предпросмотра. Ниже представлен стандартный конфигурационный файл системы:

<?xml version="1.0"?>
<configuration>
            <configSections>
                           <section name="main" type="EleWise.ELMA.Configuration.MainBaseSettingsSection, EleWise.ELMA.SDK" />
                           <section name="blobStore" type="EleWise.ELMA.Configuration.GenericProviderFeatureSection`1[[EleWise.ELMA.Runtime.Providers.BLOBStoreProviderManager, EleWise.ELMA.SDK]], EleWise.ELMA.SDK" />
                           <section name="settingsStore" type="EleWise.ELMA.Configuration.GenericProviderFeatureSection`1[[EleWise.ELMA.Runtime.Providers.SettingsStoreProviderManager, EleWise.ELMA.SDK]], EleWise.ELMA.SDK" />
                           <section name="fileStore" type="EleWise.ELMA.Configuration.GenericProviderFeatureSection`1[[EleWise.ELMA.Runtime.Providers.FileStoreProviderManager, EleWise.ELMA.SDK]], EleWise.ELMA.SDK" />
  <section name="filePreview" type="EleWise.ELMA.Configuration.GenericProviderFeatureSection`1[[EleWise.ELMA.Files.Previews.FilePreviewServiceProviderManager, EleWise.ELMA.SDK]], EleWise.ELMA.SDK" />
            </configSections>
            <connectionStrings>
                           <add name="MainDB" connectionString="Data Source=localhost; Initial Catalog={CONFIGDIR}\base.fdb; User ID=sysdba; Password=masterkey; Charset=UNICODE_FSS; Dialect=3; ServerType=0" />
            </connectionStrings>
            <main connectionStringName="MainDB" type="EleWise.ELMA.Extensions.Firebird.FirebirdProvider, EleWise.ELMA.Extensions.Firebird" />
            <blobStore defaultProvider="MemoryBLOBStoreProvider">
                           <providers>
                                           <clear />
                                           <add name="MemoryBLOBStoreProvider" type="EleWise.ELMA.Runtime.Providers.MemoryBLOBStoreProvider, EleWise.ELMA.SDK" />
                           </providers>
            </blobStore>
            <settingsStore defaultProvider="NHSettingsProvider">
                           <providers>
                                           <clear />
                                           <add name="NHSettingsProvider" type="EleWise.ELMA.Runtime.Providers.Impl.NHSettingsStoreProvider, EleWise.ELMA.SDK" />
                           </providers>
            </settingsStore>
            <fileStore defaultProvider="FSProvider">
                           <providers>
                                           <clear />
                                           <add name="FSProvider" type="EleWise.ELMA.Runtime.Providers.Impl.FileSystemFileStoreProvider, EleWise.ELMA.SDK" filesPath="Files" />
                           </providers>
            </fileStore>
  <filePreview defaultProvider="FPProvider">
  <providers>
    <clear />
    <add name="FPProvider" type="EleWise.ELMA.FilePreview.LocalService.Services.FilePreviewServiceLocal, EleWise.ELMA.FilePreview.LocalService" maxTimeWork="3600" maxMemoryUsage="500" />
    </providers>
  </filePreview>
</configuration>

Жирным отмечены блоки, которые необходимо добавить, для подключения Вашей реализации провайдера.

Вторая часть механизама генерации предпросмотра состоит из внешних исполняемых exe-файлов файлов генераторов, в которых реализуется логика формирования файла предпросмотра, для определенного формата документа.

Рассмотрим конкретную реализация генератора предпросмотра файлов формата TXT.

В первую очередь необходимо реализовать класс генератора на основе базового класса BaseFilePreviewCreatorEx:

    /// <summary>
    /// Отображение текстовых файлов
    /// </summary>
    [Component(Order = 100)]
    public class TextFilePreviewCreator : BaseFilePreviewCreatorEx
    {
        public static Guid UID = new Guid("{2C9D21C2-153F-4CD9-B004-84932C602D25}");

        public override Guid Uid
        {
            get { return UID; }
        } 

        public override string DisplayName
        {
            get { return SR.T("Текстовые файлы (.txt, .xml)"); }
        } 

        public override List<string> Extensions
        {
            get { return new List<string> { ".txt", ".xml" }; }
        } 

        public override string ExternalCreatorFileName
        {
            get { return "EleWise.ELMA.PreviewCreator.TextFile.exe"; }
        }
    }  

Как видно из примера, свойство ExternalCreatorFileName должно возвращать название файла внешнего генератора вместе с его расширением .exe. Данный файл необходимо запускать со следущими параметрами:

  1. Полный путь до генерируемого файла предпросмотра.
  2. Полный путь до файла, для которого генерируется предпросмотр.

Для создания исполняемого файла внешнего генератор необходимо в MS Visual Studio создать проект типа Console Application (рис. 1), который должен иметь следующую структуру (рис. 2).

Рисунок 1 – Создания проекта внешнего генератора предпросмотра

Рисунок 2 – Структура проекта внешнего генератора

Nuspec-файл Вашего генератора должен выглядеть следующим образом:

<?xml version="1.0"?>
<package>
  <metadata>
    <id>$id$</id>
    <title>Генератор предпросмотра для документов TXT</title>
    <version>$version$</version>
    <description>$description$</description>
    <authors>$author$</authors>
    <tags>[OwnerId:EleWise.ELMA.SDK] [Type:Module] [Component:FilePreviewCreator]</tags>
  </metadata>
</package>

Следует обязательно указать тип компонента FilePreviewCreator (выделено жирным шрифтом) для того, чтобы пакетный менеджер системы при установке компонента поместил внешний генератор в нужную директорию.

Ниже представлен пример реализации данного генератора:

namespace EleWise.ELMA.PreviewCreator.WordFile
{
    class Creator
    {
        static void Main(string[] args)
        {
            if (args.Length != 2)
            {
                return;
            } 

            string previewFilePath = args[0];
            string baseFilePath = args[1]; 

            using (var writer = new StreamWriter(previewFilePath))
            {
                using (var reader = new StreamReader(baseFilePath))
                {
                    var readStr = reader.ReadLine();
                    writer.Write("<HTML><BODY>" + readStr + "</BODY></HTML>");
                }
            }
        }
    }
}