Class: Service::QiniumService
- Inherits:
-
Service
- Object
- Service
- Service::QiniumService
- Defined in:
- lib/active_storage/service/qinium_service.rb
Instance Attribute Summary collapse
-
#qiniu ⇒ Object
readonly
Returns the value of attribute qiniu.
Class Method Summary collapse
Instance Method Summary collapse
- #copy(source_bucket, source_key, target_bucket, target_key) ⇒ Object
- #delete(key) ⇒ Object
- #delete_prefixed(prefix) ⇒ Object
- #download(key) ⇒ Object
- #download_chunk(key, range) ⇒ Object
- #exist?(key) ⇒ Boolean
- #fetch(target_url, key) ⇒ Object
- #form_data_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:) ⇒ Object
- #http_method_for_direct_upload ⇒ Object
- #http_response_type_for_direct_upload ⇒ Object
-
#initialize(options) ⇒ QiniumService
constructor
A new instance of QiniumService.
- #update_metadata(key, **metadata) ⇒ Object
- #upload(key, io, checksum: nil, content_type: nil) ⇒ Object
- #url(key, **options) ⇒ Object
- #url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:, custom_metadata:) ⇒ Object
Constructor Details
#initialize(options) ⇒ QiniumService
Returns a new instance of QiniumService.
16 17 18 |
# File 'lib/active_storage/service/qinium_service.rb', line 16 def initialize() @qiniu = Qinium.new() end |
Instance Attribute Details
#qiniu ⇒ Object (readonly)
Returns the value of attribute qiniu.
5 6 7 |
# File 'lib/active_storage/service/qinium_service.rb', line 5 def qiniu @qiniu end |
Class Method Details
.analyzers ⇒ Object
12 13 14 |
# File 'lib/active_storage/service/qinium_service.rb', line 12 def self.analyzers @analyzers ||= [ActiveStorage::Analyzer::QiniumImageAnalyzer] end |
Instance Method Details
#copy(source_bucket, source_key, target_bucket, target_key) ⇒ Object
119 120 121 122 123 124 |
# File 'lib/active_storage/service/qinium_service.rb', line 119 def copy(source_bucket, source_key, target_bucket, target_key) instrument :fetch, source_bucket: source_bucket, source_key: source_key, target_bucket: target_bucket, target_key: target_key do qiniu.object.copy(source_bucket, source_key, target_bucket, target_key) end end |
#delete(key) ⇒ Object
101 102 103 104 105 |
# File 'lib/active_storage/service/qinium_service.rb', line 101 def delete(key) instrument :delete, key: key do qiniu.object.delete(key) end end |
#delete_prefixed(prefix) ⇒ Object
107 108 109 110 111 |
# File 'lib/active_storage/service/qinium_service.rb', line 107 def delete_prefixed(prefix) instrument :delete_prefixed, prefix: prefix do items_for(prefix).each { |item| delete item["key"] } end end |
#download(key) ⇒ Object
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/active_storage/service/qinium_service.rb', line 75 def download(key) if block_given? instrument :streaming_download, key: key do URI.open(url(key, disposition: :attachment)) do |file| while data = file.read(64.kilobytes) yield data end end end else instrument :download, key: key do URI.open(url(key, disposition: :attachment)).read end end end |
#download_chunk(key, range) ⇒ Object
91 92 93 94 95 96 97 98 99 |
# File 'lib/active_storage/service/qinium_service.rb', line 91 def download_chunk(key, range) instrument :download_chunk, key: key, range: range do uri = URI(url(key, disposition: :attachment)) Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |client| client.get(uri, "Range" => "bytes=#{range.begin}-#{range.exclude_end? ? range.end - 1 : range.end}").body end end end |
#exist?(key) ⇒ Boolean
126 127 128 129 130 131 132 |
# File 'lib/active_storage/service/qinium_service.rb', line 126 def exist?(key) instrument :exist, key: key do |payload| answer = items_for(key).any? payload[:exist] = answer answer end end |
#fetch(target_url, key) ⇒ Object
113 114 115 116 117 |
# File 'lib/active_storage/service/qinium_service.rb', line 113 def fetch(target_url, key) instrument :fetch, target_url: target_url, key: key do qiniu.object.fetch(target_url, key) end end |
#form_data_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:) ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/active_storage/service/qinium_service.rb', line 36 def form_data_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:, **) put_policy = Qinium::PutPolicy.new(config, key: key, expires_in: expires_in) put_policy.fsize_limit = content_length.to_i + 1000 # OPTIMIZE: 暂时关闭文件类型限制,避免 xmind 文件无法上传 put_policy.mime_limit = nil put_policy.detect_mime = 1 put_policy.insert_only = 1 { key: key, token: put_policy.to_token, ':file': "file" } end |
#http_method_for_direct_upload ⇒ Object
28 29 30 |
# File 'lib/active_storage/service/qinium_service.rb', line 28 def http_method_for_direct_upload "POST" end |
#http_response_type_for_direct_upload ⇒ Object
32 33 34 |
# File 'lib/active_storage/service/qinium_service.rb', line 32 def http_response_type_for_direct_upload "json" end |
#update_metadata(key, **metadata) ⇒ Object
73 |
# File 'lib/active_storage/service/qinium_service.rb', line 73 def (key, **); end |
#upload(key, io, checksum: nil, content_type: nil) ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/active_storage/service/qinium_service.rb', line 50 def upload(key, io, checksum: nil, content_type: nil, **) instrument :upload, key: key, checksum: checksum do io = File.open(io) unless io.respond_to?(:read) put_policy = Qinium::PutPolicy.new(config, key: key, expires_in: .expires_in) up_token = put_policy.to_token blocks = [] file_size = 0 host = nil while (blk = io.read(config.block_size)) data = upload_blk(blk, token: up_token, host: host) ctx = data.fetch("ctx") host = data.fetch("host") file_size += blk.size blocks.push(ctx) end _code, data, _headers = qiniu.object.mkfile(token: up_token, file_size: file_size, key: key, mime_type: content_type, blocks: blocks) data end end |
#url(key, **options) ⇒ Object
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/active_storage/service/qinium_service.rb', line 134 def url(key, **) instrument :url, key: key do |payload| # 根据七牛云文档:https://developer.qiniu.com/kodo/1659/download-setting # 1. 使用 attname 参数可以让浏览器下载而不是打开 # 2. 使用 response-content-disposition 参数可以自定义 Content-Disposition 响应头 # 3. 使用 response-content-type 参数可以自定义 Content-Type 响应头 # 4. 使用 response-cache-control 参数可以自定义 Cache-Control 响应头 # 5. 使用 response-content-encoding 参数可以自定义 Content-Encoding 响应头 # 6. 使用 response-content-language 参数可以自定义 Content-Language 响应头 # 7. 使用 response-expires 参数可以自定义 Expires 响应头 # 8. 使用 X-Qiniu-Traffic-Limit 参数可以限制下载速度 disposition = [:disposition] content_type = [:content_type] # 构建查询参数 query_params = [] # 内容预处理(图片处理、视频处理等) query_params << [:fop] if [:fop].present? # 处理 disposition 相关参数 if disposition.to_s == "attachment" # 下载附件 # attname:触发「下载」行为;部分节点仍用对象 key 填 Content-Disposition,须同时传 response-content-disposition。 # 文档:https://developer.qiniu.com/kodo/1659/download-setting display_name = ([:filename].presence || File.basename(key)).to_s query_params << "attname=#{URI.encode_www_form_component(display_name)}" # cd = ActionDispatch::Http::ContentDisposition.format( # disposition: "attachment", # filename: ActiveStorage::Filename.new(display_name).sanitized # ) # query_params << "response-content-disposition=#{ERB::Util.url_encode(cd)}" # elsif disposition.to_s == "inline" # 预览(inline) # # 明确设置 Content-Disposition 为 inline,确保浏览器预览而不是下载 # query_params << "response-content-disposition=inline" end # 自定义响应头参数 # 注意:这些参数只有请求成功(即返回码为 200 OK)才会生效 # 且不支持在匿名访问的下载请求中自定义标准响应头 if [:response_content_type].present? || content_type.present? value = [:response_content_type] || content_type query_params << "response-content-type=#{URI.encode_www_form_component(value)}" end if [:response_cache_control].present? query_params << "response-cache-control=#{URI.encode_www_form_component([:response_cache_control])}" end if [:response_content_disposition].present? query_params << "response-content-disposition=#{ERB::Util.url_encode([:response_content_disposition])}" end if [:response_content_encoding].present? query_params << "response-content-encoding=#{URI.encode_www_form_component([:response_content_encoding])}" end if [:response_content_language].present? query_params << "response-content-language=#{URI.encode_www_form_component([:response_content_language])}" end if [:response_expires].present? query_params << "response-expires=#{URI.encode_www_form_component([:response_expires])}" end # 下载限速:X-Qiniu-Traffic-Limit # 取值范围为 819200 ~ 838860800,单位为 bit/s query_params << "X-Qiniu-Traffic-Limit=#{[:traffic_limit].to_i}" if [:traffic_limit].present? # 构建 URL url = if config.public url_encoded_key = key.split("/").map { |x| CGI.escape(x) }.join("/") base_url = "#{protocol}://#{domain}/#{url_encoded_key}" query_params.any? ? "#{base_url}?#{query_params.join("&")}" : base_url else expires_in = [:expires_in] || Rails.application.config.active_storage.service_urls_expire_in || 3600 # 对于私有资源,需要将查询参数传递给授权 URL 生成 fop = query_params.join("&") if query_params.any? Qinium::Auth.(domain, key, access_key, secret_key, schema: protocol, fop: fop, expires_in: expires_in) end payload[:url] = url url end end |
#url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:, custom_metadata:) ⇒ Object
20 21 22 23 24 25 26 |
# File 'lib/active_storage/service/qinium_service.rb', line 20 def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:, custom_metadata:) instrument :url, key: key do |payload| url = config.up_host payload[:url] = url url end end |