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:



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

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.



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

def jps_client
  @jps_client
end

Instance Method Details

#upload_file(file_path:) ⇒ String?

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

Parameters:

  • file_path (String)

    文件路径

Returns:

  • (String, nil)

    成功返回 URL,失败返回 nil



155
156
157
158
# File 'lib/jpsclient/upload/upload_media_client.rb', line 155

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: 失败数



49
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/jpsclient/upload/upload_media_client.rb', line 49

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 = []

  # 准备任务队列
  @tasks_queue = Queue.new
  @worker_threads = []
  @expected_files = valid_files.size
  @active_tasks = 0

  # 获取并发和重试配置
  concurrent_workers = [@upload_config.concurrent_workers, valid_files.size].min
  retry_count = @upload_config.max_retry_times

  puts "准备上传 #{valid_files.size} 个文件"
  puts "并发上传线程数: #{concurrent_workers}"
  puts "失败重试次数: #{retry_count}"
  puts

  # 创建文件上传任务
  valid_files.each do |file_path|
    task_item = {
      "file_path" => file_path,
      "retry_count" => retry_count
    }
    @tasks_queue.push(task_item)
  end

  # 开始并发上传
  Logger.instance.fancyinfo_start("开始上传...")

  begin
    concurrent_upload(concurrency: concurrent_workers)
  ensure
    cleanup_worker_threads
  end

  # 收集结果
  @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