Class: JPSClient::UploadMediaClient

Inherits:
Object
  • Object
show all
Defined in:
lib/jpsclient/upload/upload_media_client.rb

Overview

Media 文件上传客户端 用于并发上传多个小文件(图片、视频等)到 S3 与 UploadClient 的区别:

  • UploadClient: 单个大文件 → 分片 → 并发上传分片
  • UploadMediaClient: 多个小文件 → 并发上传文件

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(jps_client) ⇒ UploadMediaClient

Returns a new instance of UploadMediaClient.

Raises:



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/jpsclient/upload/upload_media_client.rb', line 18

def initialize(jps_client)
  raise ExceptionError, "必须提供 Client 实例" unless jps_client

  @jps_client = jps_client

  # 从 Client 获取配置
  config_json = @jps_client.config_json

  # 加载上传配置
  @upload_config = UploadConfig.from_json(config_json["upload_config"])
  unless @upload_config
    raise ExceptionError, "上传配置无效或不完整"
  end

  # 线程安全的互斥锁
  @results_mutex = Mutex.new
  @tasks_queue_mutex = Mutex.new
  @active_tasks_mutex = Mutex.new
  @upload_failed_mutex = Mutex.new
  @upload_failed = false
end

Instance Attribute Details

#jps_clientObject (readonly)

Returns the value of attribute jps_client.



16
17
18
# File 'lib/jpsclient/upload/upload_media_client.rb', line 16

def jps_client
  @jps_client
end

Instance Method Details

#upload_file(file_path:) ⇒ String?

上传单个文件(便捷方法)

Parameters:

  • file_path (String)

    文件路径

Returns:

  • (String, nil)

    成功返回 URL,失败返回 nil



131
132
133
134
# File 'lib/jpsclient/upload/upload_media_client.rb', line 131

def upload_file(file_path:)
  result = upload_files(file_paths: [file_path])
  result["success_urls"].first
end

#upload_files(file_paths:) ⇒ Hash

并发上传多个 media 文件

Parameters:

  • file_paths (Array<String>)

    要上传的文件路径列表

Returns:

  • (Hash)

    上传结果

    • results: 每个文件的上传结果数组
    • success_urls: 成功上传的 URL 列表
    • failed_files: 上传失败的文件路径列表
    • total: 总文件数
    • success_count: 成功数
    • failed_count: 失败数


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/jpsclient/upload/upload_media_client.rb', line 50

def upload_files(file_paths:)
  result = {
    "results" => [],
    "success_urls" => [],
    "failed_files" => [],
    "total" => 0,
    "success_count" => 0,
    "failed_count" => 0
  }

  # 验证参数
  if file_paths.nil? || file_paths.empty?
    Logger.instance.fancyinfo_error("未提供要上传的文件")
    return result
  end

  # 过滤有效文件
  valid_files = file_paths.select { |f| File.exist?(f) }
  invalid_files = file_paths - valid_files

  # 记录无效文件
  invalid_files.each do |f|
    result["results"] << {
      "file_path" => f,
      "url" => nil,
      "success" => false,
      "error" => "文件不存在"
    }
    result["failed_files"] << f
  end

  if valid_files.empty?
    result["total"] = file_paths.size
    result["failed_count"] = invalid_files.size
    Logger.instance.fancyinfo_error("没有有效的文件可上传")
    return result
  end

  result["total"] = file_paths.size

  # 重置状态
  @upload_failed = false
  @upload_results = []

  # 按分片大小分流:装不满一个分片的文件一次 PUT 传完,超出的走分片上传
  # 大文件不并发,是因为分片上传自身已经并发传分片,再套一层会让线程数和进度条都失控
  chunk_size = @upload_config.chunk_size_bytes
  small_files, large_files = valid_files.partition { |f| File.size(f) <= chunk_size }

  upload_small_files(small_files) if small_files.any?
  large_files.each { |file_path| upload_large_file(file_path) }

  # 收集结果
  @upload_results.each do |item|
    result["results"] << item
    if item["success"]
      result["success_urls"] << item["url"]
      result["success_count"] += 1
    else
      result["failed_files"] << item["file_path"]
      result["failed_count"] += 1
    end
  end

  # 加上之前的无效文件
  result["failed_count"] += invalid_files.size

  # 输出统计
  if result["success_count"] > 0
    Logger.instance.fancyinfo_success("上传完成! 成功: #{result["success_count"]}, 失败: #{result["failed_count"]}")
  else
    Logger.instance.fancyinfo_error("上传失败! 成功: #{result["success_count"]}, 失败: #{result["failed_count"]}")
  end

  return result
end