defmodule DaProductApp.Workers.FileDownloadWorker do @moduledoc """ Oban worker for handling scheduled file download jobs. """ use Oban.Worker, queue: :file_download, max_attempts: 3 require Logger alias DaProductApp.TerminalManagement.FileDownloadService @impl Oban.Worker def perform(%Oban.Job{args: %{"type" => "single_download", "device_serial" => device_serial, "download_params" => download_params}}) do Logger.info("Processing file download job for device: #{device_serial}") case FileDownloadService.send_file_download_command(device_serial, download_params) do {:ok, message} -> Logger.info("File download command successful for #{device_serial}: #{message}") :ok {:error, reason} -> Logger.error("File download command failed for #{device_serial}: #{reason}") {:error, reason} end end def perform(%Oban.Job{args: %{"type" => "batch_download", "device_serials" => device_serials, "download_params" => download_params}}) do Logger.info("Processing batch file download job for #{length(device_serials)} devices") results = Enum.map(device_serials, fn device_serial -> # Add unique request_id per device for batch operations device_params = Map.put(download_params, "request_id", "#{download_params["request_id"]}_#{device_serial}") case FileDownloadService.send_file_download_command(device_serial, device_params) do {:ok, message} -> {device_serial, :ok, message} {:error, reason} -> {device_serial, :error, reason} end end) successes = Enum.count(results, fn {_, status, _} -> status == :ok end) failures = Enum.count(results, fn {_, status, _} -> status == :error end) Logger.info("Batch file download completed: #{successes} successful, #{failures} failed") if failures == 0 do :ok else Logger.warning("Batch file download had #{failures} failures out of #{length(device_serials)} devices") :ok # Don't retry whole batch, individual failures are logged end end def perform(%Oban.Job{args: %{"type" => "logo_download", "device_serial" => device_serial, "logo_url" => logo_url, "file_name" => file_name}}) do Logger.info("Processing logo download job for device: #{device_serial}") case FileDownloadService.create_logo_download_command(device_serial, logo_url, file_name) do {:ok, message} -> Logger.info("Logo download command successful for #{device_serial}: #{message}") :ok {:error, reason} -> Logger.error("Logo download command failed for #{device_serial}: #{reason}") {:error, reason} end end def perform(%Oban.Job{args: %{"type" => "firmware_download", "device_serial" => device_serial, "firmware_url" => firmware_url, "file_name" => file_name}}) do Logger.info("Processing firmware download job for device: #{device_serial}") case FileDownloadService.create_firmware_download_command(device_serial, firmware_url, file_name) do {:ok, message} -> Logger.info("Firmware download command successful for #{device_serial}: #{message}") :ok {:error, reason} -> Logger.error("Firmware download command failed for #{device_serial}: #{reason}") {:error, reason} end end def perform(%Oban.Job{args: %{"type" => "application_download", "device_serial" => device_serial, "app_url" => app_url, "file_name" => file_name}}) do Logger.info("Processing application download job for device: #{device_serial}") case FileDownloadService.create_application_download_command(device_serial, app_url, file_name) do {:ok, message} -> Logger.info("Application download command successful for #{device_serial}: #{message}") :ok {:error, reason} -> Logger.error("Application download command failed for #{device_serial}: #{reason}") {:error, reason} end end @doc """ Schedules a file download job for a single device. """ def schedule_file_download(device_serial, download_params, opts \\ []) do schedule_at = Keyword.get(opts, :schedule_at, DateTime.utc_now()) %{ type: "single_download", device_serial: device_serial, download_params: download_params } |> new(scheduled_at: schedule_at) |> Oban.insert() end @doc """ Schedules a batch file download job for multiple devices. """ def schedule_batch_file_download(device_serials, download_params, opts \\ []) do schedule_at = Keyword.get(opts, :schedule_at, DateTime.utc_now()) %{ type: "batch_download", device_serials: device_serials, download_params: download_params } |> new(scheduled_at: schedule_at) |> Oban.insert() end @doc """ Schedules a logo download job. """ def schedule_logo_download(device_serial, logo_url, file_name \\ "merchant_logo.png", opts \\ []) do schedule_at = Keyword.get(opts, :schedule_at, DateTime.utc_now()) %{ type: "logo_download", device_serial: device_serial, logo_url: logo_url, file_name: file_name } |> new(scheduled_at: schedule_at) |> Oban.insert() end @doc """ Schedules a firmware download job. """ def schedule_firmware_download(device_serial, firmware_url, file_name, opts \\ []) do schedule_at = Keyword.get(opts, :schedule_at, DateTime.utc_now()) %{ type: "firmware_download", device_serial: device_serial, firmware_url: firmware_url, file_name: file_name } |> new(scheduled_at: schedule_at) |> Oban.insert() end @doc """ Schedules an application download job. """ def schedule_application_download(device_serial, app_url, file_name, opts \\ []) do schedule_at = Keyword.get(opts, :schedule_at, DateTime.utc_now()) %{ type: "application_download", device_serial: device_serial, app_url: app_url, file_name: file_name } |> new(scheduled_at: schedule_at) |> Oban.insert() end end