Как загрузить и распаковать/извлечь конкретные файлы, выбранные пользователем в списке компонентов

Вопрос или проблема

Надеюсь, название уже достаточно ясное, но чтобы объяснить лучше: у меня есть большой выбор опций на странице Выбор компонентов (около 1.4 ГБ файлов .png), и моя цель – уменьшить размер сборки для установщика, заставив его загружать файлы в {tmp} и устанавливать их после распаковки. К сожалению, у меня возникли некоторые проблемы при попытке следовать ответам на другие вопросы.

  1. Ссылка на скачивание моих файлов видна на странице загрузки, что меня невероятно беспокоит в отношении проблем с безопасностью.
  2. Все файлы загружаются независимо от того, какие компоненты выбрал пользователь, что приводит к большому количеству времени, потраченного на извлечение, к тому же, к сожалению, нет индикатора прогресса, чтобы дать обратную связь пользователю.
  3. Попытка отменить загрузку полностью замораживает установщик, требуя от пользователя использовать Диспетчер задач для выхода из установки.

———————————————————————————————————————————

В настоящее время весь [Code] для моего установщика (извините, это много)

[Files]
// Тест
Source: "{tmp}\packs\Sapphic_icons\Dead by Daylight\DeadByDaylight\Content\UI\Icons\README.txt"; DestDir: "{app}"; Components: sapphic; Flags: ignoreversion recursesubdirs createallsubdirs external; Check: ExtractedFileNeedsInstallation

[Types]
Name: "sapphic"; Description: "Sapphic Pack";
Name: "custom"; Description: "Индивидуализированный"; Flags: iscustom;

[Components]  
Name: "sapphic"; Description: "Sapphic Pack - В процессе*"; Types: custom sapphic;

[Code]
{ —————————— Логирование извлечения ———————————————————————————————————————— }
const
  NO_PROGRESS_BOX = 4;
  RESPOND_YES_TO_ALL = 16;
procedure UnZip(ZipPath, FileName, TargetPath: string); 
var
  Shell: Variant;
  ZipFile: Variant;
  Item: Variant;
  TargetFolder: Variant;
begin
  Shell := CreateOleObject('Shell.Application');

  ZipFile := Shell.NameSpace(ZipPath);
  if VarIsClear(ZipFile) then
    RaiseException(Format('Не удается открыть ZIP-файл "%s" или он не существует', [ZipPath]));

  Item := ZipFile.ParseName(FileName);
  if VarIsClear(Item) then
    RaiseException(Format('Не удается найти "%s" в ZIP-файле "%s"', [FileName, ZipPath]));

  TargetFolder := Shell.NameSpace(TargetPath);
  if VarIsClear(TargetFolder) then
    RaiseException(Format('Целевой путь "%s" не существует', [TargetPath]));

  TargetFolder.CopyHere(Item, NO_PROGRESS_BOX or RESPOND_YES_TO_ALL);
end; // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
{ —————————— Обработка извлечения ———————————————————————————————————————— }
function ExtractedFileNeedsInstallation: Boolean;
var 
  TargetPath: String; 
begin  
  TargetPath := ExpandConstant('{userappdata}')+'\App\packs';
  Result := not FileExists(TargetPath);
  Log(Format('ExtractedFileNeedsInstallation: %d', [Result]));  
end; // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
{ —————————— Прогресс загрузки ———————————————————————————————————————— }
var
  DownloadPage: TDownloadWizardPage;
function OnDownloadProgress(const Url, FileName: String; const Progress, ProgressMax: Int64): Boolean;
begin
  if Progress = ProgressMax then
    Log(Format('Файл успешно загружен в {tmp}: %s', [FileName]));
  Result := True;
end; // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
{ —————————— Мастер установки ———————————————————————————————————————— }
procedure InitializeWizard();
begin
{ Страница загрузки }
  DownloadPage := CreateDownloadPage(SetupMessage(msgWizardPreparing), SetupMessage(msgPreparingDesc), @OnDownloadProgress);
end; // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
{ —————————— Обработка загрузки ———————————————————————————————————————— } 
function NextButtonClick(CurPageID: Integer): Boolean;
var  
  Temp: String;
begin
  if CurPageID = wpReady then begin
      if (not ExtractedFileNeedsInstallation) then
      begin
          Result := True;
      end
      else
      begin
          DownloadPage.Clear;
          DownloadPage.Add('https://www.dropbox.com/scl/fi/fautmpacdsl22h6y41jrv/packs.zip?rlkey=ul3kl1f9o3258yguitprisx6c&st=wwry4esv&dl=1', 'packs.zip', '');
          DownloadPage.Show;
          try
            try
              DownloadPage.Download;
              Temp := ExpandConstant('{tmp}');
              UnZip(Temp+'\packs.zip', 'packs', Temp);
              Result := True;
            except
              SuppressibleMsgBox(AddPeriod(GetExceptionMessage), mbCriticalError, MB_OK, IDOK);
              Result := False;
            end;
          finally
            DownloadPage.Hide;
          end;
      end;
  end else
    Result := True;
end; // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //

———————————————————————————————————————————

Ответ или решение

Для решения проблемы скачивания и извлечения специфических файлов, выбранных пользователем на странице выбора компонентов, необходимо внести ряд изменений и улучшений в предоставленный код вашего установщика. Это обеспечит безопасность, оптимизирует процесс скачивания и предоставит пользователю необходимую обратную связь. Рассмотрим ключевые шаги более детально.

1. Повышение уровня безопасности

Для устранения проблемы с видимостью ссылок на скачивание желательно использовать подход, при котором ссылка будет недоступна напрямую. Можно реализовать механизм генерации временных ссылок на сервере или использовать API для получения файла. В качестве альтернативы можно рассмотреть использование хеширования для проверки подлинности файлов.

2. Фильтрация скачиваемых файлов

Текущая реализация загружает все файлы, игнорируя выбор пользователя. Чтобы это исправить, необходимо создать логику, которая будет проверять выбранные компоненты и скачивать только соответствующие файлы.

Примерно это может выглядеть следующим образом:

function ComponentsToDownload: TStringList;
var
  Components: TStringList;
begin
  Components := TStringList.Create;
  try
    if IsComponentSelected('sapphic') then
      Components.Add('sapphic_files.zip'); // Добавьте соответствующие файлы для скачивания
    // Добавьте проверки для дополнительных компонентов
    Result := Components;
  finally
    Components.Free;
  end;
end;

// В функции NextButtonClick
var
  FilesToDownload: TStringList;
begin
  FilesToDownload := ComponentsToDownload;
  try
    for FileName in FilesToDownload do
    begin
      DownloadPage.Add('http://yourserver.com/' + FileName, FileName, '');
    end;
    ...
  finally
    FilesToDownload.Free;
  end;

3. Отображение прогресса загрузки

Для улучшения взаимодействия с пользователем добавьте прогресс-бар при загрузке файлов. Это можно реализовать через обновление пользовательского интерфейса на этапе загрузки.

4. Обработка отмены загрузки

Для предотвращения зависания установщика при попытке отмены загрузки следует реализовать специальный метод обработки прерывания загрузки. Например, добавьте кнопку "Отмена", которая прекращает выполнение потока загрузки и возвращает пользователя к предыдущему экрану.

5. Извлечение только нужных файлов

Для извлечения конкретных файлов из ZIP-архива в соответствии с выбором пользователя обновите процедуру UnZip.

procedure UnZipSelective(ZipPath: string; TargetPath: string; FileNames: TStringList);
var
  Shell: Variant;
  ZipFile: Variant;
  TargetFolder: Variant;
  I: Integer;
begin
  Shell := CreateOleObject('Shell.Application');
  ZipFile := Shell.NameSpace(ZipPath);
  if VarIsClear(ZipFile) then
    RaiseException(Format('Cannot open ZIP file "%s"', [ZipPath]));

  TargetFolder := Shell.NameSpace(TargetPath);
  if VarIsClear(TargetFolder) then
    RaiseException(Format('Target path "%s" does not exist', [TargetPath]));

  for I := 0 to FileNames.Count - 1 do
  begin
    var Item := ZipFile.ParseName(FileNames[I]);
    if not VarIsClear(Item) then
      TargetFolder.CopyHere(Item, NO_PROGRESS_BOX or RESPOND_YES_TO_ALL);
  end;
end;

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...