Class: Dratools::ExternalCommandRunner

Inherits:
Object
  • Object
show all
Defined in:
lib/dratools/external_command_runner.rb

Overview

curl, wget, aria2c のいずれかを使って URL の確認とダウンロードを行うラッパー。

probe は短時間・無出力で済ませ、download は外部コマンドの進捗を端末へ流す。 巨大ファイルを扱うため、download には総時間制限ではなく失速検知を使う。

Constant Summary collapse

CURL_COMMAND =
'curl'
WGET_COMMAND =
'wget'
ARIA2_COMMAND =
'aria2c'
AUTO_COMMANDS =
[CURL_COMMAND, WGET_COMMAND].freeze
SUPPORTED_COMMANDS =
[*AUTO_COMMANDS, ARIA2_COMMAND].freeze
COMMAND_NOT_FOUND_MESSAGE =
'curl または wget が見つかりません'
PREFERRED_COMMAND_NOT_FOUND_MESSAGE =
'指定されたダウンロードコマンドが見つかりません'
UNSUPPORTED_COMMAND_MESSAGE =
'未対応のダウンロードコマンドです'
DEFAULT_PROBE_TIMEOUT_SECONDS =
5
PROBE_BYTE_RANGE =
'0-0'
SINGLE_ATTEMPT_COUNT =
1
CURL_PROBE_OPTIONS =

リダイレクト、HTTP エラー、静かな probe、範囲取得。

['--location', '--fail', '--silent', '--show-error', '--range'].freeze
CURL_TIMEOUT_OPTION =

probe 全体のタイムアウト。

'--max-time'
CURL_CONNECT_TIMEOUT_OPTION =
'--connect-timeout'
CURL_SPEED_LIMIT_OPTION =

失速判定に使う最低転送速度。

'--speed-limit'
CURL_SPEED_TIME_OPTION =

最低速度を下回ってよい秒数。

'--speed-time'
CURL_RETRY_OPTION =
'--retry'
CURL_OUTPUT_OPTION =
'--output'
CURL_DOWNLOAD_OPTIONS =

部分ファイルがあれば続きから再開。

['--location', '--fail', '--continue-at', '-'].freeze
WGET_PROBE_OPTIONS =

probe でファイルを保存しない。

['--spider'].freeze
WGET_TIMEOUT_OPTION =

probe 全体のタイムアウト。

'--timeout'
WGET_CONNECT_TIMEOUT_OPTION =
'--connect-timeout'
WGET_READ_TIMEOUT_OPTION =

wget で失速検知に近い意味で使う。

'--read-timeout'
WGET_TRIES_OPTION =

probe では 1 回だけにする。

'--tries'
WGET_WAITRETRY_OPTION =
'--waitretry'
WGET_CONTINUE_OPTION =

部分ファイルがあれば続きから再開。

'--continue'
WGET_OUTPUT_OPTION =
'--output-document'
ARIA2_PROBE_OPTIONS =

probe で保存せず、通常出力も抑える。

['--dry-run=true', '--quiet=true'].freeze
ARIA2_CONNECT_TIMEOUT_OPTION =
'--connect-timeout'
ARIA2_TIMEOUT_OPTION =

aria2c で失速検知に近い意味で使う。

'--timeout'
ARIA2_LOWEST_SPEED_LIMIT_OPTION =

curl の --speed-limit に相当する最低転送速度。

'--lowest-speed-limit'
ARIA2_MAX_TRIES_OPTION =
'--max-tries'
ARIA2_RETRY_WAIT_OPTION =
'--retry-wait'
ARIA2_CONTINUE_OPTION =

部分ファイルがあれば続きから再開。

'--continue=true'
ARIA2_DIR_OPTION =

aria2c は保存先をディレクトリとファイル名に分ける。

'--dir'
ARIA2_OUT_OPTION =
'--out'
ARIA2_SINGLE_CONNECTION_OPTIONS =

既定では並列取得しない。

['--split=1', '--max-connection-per-server=1'].freeze

Instance Method Summary collapse

Constructor Details

#initialize(preferred: Config.download_command) ⇒ ExternalCommandRunner

Returns a new instance of ExternalCommandRunner.



74
75
76
# File 'lib/dratools/external_command_runner.rb', line 74

def initialize(preferred: Config.download_command)
  @preferred = preferred
end

Instance Method Details

#available_commandObject



78
79
80
81
# File 'lib/dratools/external_command_runner.rb', line 78

def available_command
  candidates = @preferred ? [@preferred] : AUTO_COMMANDS
  candidates.find { |command_name| executable_command?(command_name) }
end

#download_url(url, output_path) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/dratools/external_command_runner.rb', line 109

def download_url(url, output_path)
  tool = available_command || raise(CommandError, command_not_found_message)
  command =
    case File.basename(tool)
    when CURL_COMMAND
      # curl の低速検知は「指定秒数のあいだ指定速度を下回ったら失敗」。
      # ネットワークが完全に切れず低速で固まるケースを、総時間制限なしで検出する。
      # 例: curl --location --fail --continue-at - --connect-timeout 30
      #          --speed-limit 1024 --speed-time 60 --retry 3 --output OUT URL
      [tool, *CURL_DOWNLOAD_OPTIONS,
       CURL_CONNECT_TIMEOUT_OPTION, Config.download_connect_timeout_seconds.to_s,
       CURL_SPEED_LIMIT_OPTION, Config.download_stall_speed_bytes_per_second.to_s,
       CURL_SPEED_TIME_OPTION, Config.download_stall_timeout_seconds.to_s,
       CURL_RETRY_OPTION, Config.download_retry_count.to_s,
       CURL_OUTPUT_OPTION, output_path, url]
    when WGET_COMMAND
      # wget では --read-timeout を失速検知に近い意味で使う。
      # --continue は部分ファイルの続きから再開し、--output-document は保存先を固定する。
      # 例: wget --continue --connect-timeout=30 --read-timeout=60
      #          --tries=4 --waitretry=5 --output-document OUT URL
      [tool, WGET_CONTINUE_OPTION,
       "#{WGET_CONNECT_TIMEOUT_OPTION}=#{Config.download_connect_timeout_seconds}",
       "#{WGET_READ_TIMEOUT_OPTION}=#{Config.download_stall_timeout_seconds}",
       "#{WGET_TRIES_OPTION}=#{download_attempt_count}",
       "#{WGET_WAITRETRY_OPTION}=#{Config.download_retry_wait_seconds}",
       WGET_OUTPUT_OPTION, output_path, url]
    when ARIA2_COMMAND
      # aria2c は保存先をディレクトリとファイル名に分けて指定する。
      # --continue=true は部分ファイルがあれば続きから再開する。
      # 例: aria2c --continue=true --split=1 --max-connection-per-server=1
      #          --connect-timeout=30 --timeout=60 --lowest-speed-limit=1024
      #          --max-tries=4 --retry-wait=5 --dir DIR --out FILE URL
      [tool, ARIA2_CONTINUE_OPTION, *ARIA2_SINGLE_CONNECTION_OPTIONS,
       "#{ARIA2_CONNECT_TIMEOUT_OPTION}=#{Config.download_connect_timeout_seconds}",
       "#{ARIA2_TIMEOUT_OPTION}=#{Config.download_stall_timeout_seconds}",
       "#{ARIA2_LOWEST_SPEED_LIMIT_OPTION}=#{Config.download_stall_speed_bytes_per_second}",
       "#{ARIA2_MAX_TRIES_OPTION}=#{download_attempt_count}",
       "#{ARIA2_RETRY_WAIT_OPTION}=#{Config.download_retry_wait_seconds}",
       "#{ARIA2_DIR_OPTION}=#{File.dirname(output_path)}",
       "#{ARIA2_OUT_OPTION}=#{File.basename(output_path)}", url]
    else
      unsupported_command!(tool)
    end
  run_streaming(command)
end

#probe_url(url, timeout: DEFAULT_PROBE_TIMEOUT_SECONDS) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/dratools/external_command_runner.rb', line 83

def probe_url(url, timeout: DEFAULT_PROBE_TIMEOUT_SECONDS)
  tool = available_command || raise(CommandError, command_not_found_message)
  # 巨大ファイルを落とさないよう、短時間・最小範囲の確認に留める。
  command =
    case File.basename(tool)
    when CURL_COMMAND
      # 例: curl --location --fail --silent --show-error --range 0-0
      #          --max-time 5 --output /dev/null URL
      [tool, *CURL_PROBE_OPTIONS, PROBE_BYTE_RANGE, CURL_TIMEOUT_OPTION, timeout.to_s,
       CURL_OUTPUT_OPTION, null_device, url]
    when WGET_COMMAND
      # 例: wget --spider --timeout=5 --tries=1 URL
      [tool, *WGET_PROBE_OPTIONS, "#{WGET_TIMEOUT_OPTION}=#{timeout}",
       "#{WGET_TRIES_OPTION}=#{SINGLE_ATTEMPT_COUNT}", url]
    when ARIA2_COMMAND
      # 例: aria2c --dry-run=true --quiet=true --connect-timeout=5 --timeout=5 --max-tries=1 URL
      [tool, *ARIA2_PROBE_OPTIONS,
       "#{ARIA2_CONNECT_TIMEOUT_OPTION}=#{timeout}",
       "#{ARIA2_TIMEOUT_OPTION}=#{timeout}",
       "#{ARIA2_MAX_TRIES_OPTION}=#{SINGLE_ATTEMPT_COUNT}", url]
    else
      unsupported_command!(tool)
    end
  run_quietly(command)
end