rest-ftp-daemon 0.435.2 → 0.501.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +35 -29
- data/config.ru +1 -1
- data/defaults.yml +16 -12
- data/lib/rest-ftp-daemon.rb +1 -0
- data/lib/rest-ftp-daemon/api/config.rb +1 -2
- data/lib/rest-ftp-daemon/api/dashboard.rb +6 -4
- data/lib/rest-ftp-daemon/api/debug.rb +6 -5
- data/lib/rest-ftp-daemon/api/jobs.rb +1 -1
- data/lib/rest-ftp-daemon/api/root.rb +11 -10
- data/lib/rest-ftp-daemon/api/status.rb +1 -1
- data/lib/rest-ftp-daemon/constants.rb +12 -3
- data/lib/rest-ftp-daemon/counters.rb +1 -1
- data/lib/rest-ftp-daemon/entities/job.rb +1 -5
- data/lib/rest-ftp-daemon/entities/location.rb +4 -3
- data/lib/rest-ftp-daemon/entities/options.rb +1 -1
- data/lib/rest-ftp-daemon/exceptions.rb +1 -1
- data/lib/rest-ftp-daemon/helpers/api.rb +1 -1
- data/lib/rest-ftp-daemon/helpers/common.rb +1 -1
- data/lib/rest-ftp-daemon/helpers/views.rb +29 -10
- data/lib/rest-ftp-daemon/initialize.rb +1 -1
- data/lib/rest-ftp-daemon/job.rb +11 -13
- data/lib/rest-ftp-daemon/job_queue.rb +9 -10
- data/lib/rest-ftp-daemon/jobs/dummy.rb +1 -1
- data/lib/rest-ftp-daemon/jobs/errors.rb +13 -15
- data/lib/rest-ftp-daemon/jobs/transfer.rb +15 -15
- data/lib/rest-ftp-daemon/jobs/video.rb +7 -7
- data/lib/rest-ftp-daemon/launcher.rb +1 -1
- data/lib/rest-ftp-daemon/location.rb +91 -67
- data/lib/rest-ftp-daemon/metrics.rb +2 -2
- data/lib/rest-ftp-daemon/notification.rb +1 -1
- data/lib/rest-ftp-daemon/paginate.rb +1 -1
- data/lib/rest-ftp-daemon/remote/base.rb +8 -3
- data/lib/rest-ftp-daemon/remote/ftp.rb +18 -18
- data/lib/rest-ftp-daemon/remote/s3.rb +100 -41
- data/lib/rest-ftp-daemon/remote/sftp.rb +15 -15
- data/lib/rest-ftp-daemon/static/css/main.css +34 -4
- data/lib/rest-ftp-daemon/uri.rb +1 -1
- data/lib/rest-ftp-daemon/views/dashboard.haml +1 -1
- data/lib/rest-ftp-daemon/views/dashboard_counters.haml +1 -1
- data/lib/rest-ftp-daemon/views/dashboard_footer.haml +1 -1
- data/lib/rest-ftp-daemon/views/dashboard_header.haml +1 -1
- data/lib/rest-ftp-daemon/views/dashboard_jobs.haml +1 -2
- data/lib/rest-ftp-daemon/views/dashboard_rates.haml +1 -1
- data/lib/rest-ftp-daemon/views/dashboard_table.haml +8 -5
- data/lib/rest-ftp-daemon/views/dashboard_tokens.haml +1 -1
- data/lib/rest-ftp-daemon/views/dashboard_workers.haml +1 -1
- data/lib/rest-ftp-daemon/worker_pool.rb +2 -2
- data/lib/rest-ftp-daemon/workers/conchita.rb +1 -1
- data/lib/rest-ftp-daemon/workers/reporter.rb +1 -1
- data/lib/rest-ftp-daemon/workers/transfer.rb +3 -3
- data/lib/rest-ftp-daemon/workers/worker.rb +1 -1
- data/lib/shared/patch_file.rb +5 -0
- data/rest-ftp-daemon.gemspec +2 -2
- data/spec/spec_helper.rb +2 -1
- data/spec/support/request_helpers.rb +1 -1
- metadata +6 -5
@@ -4,76 +4,135 @@ require 'aws-sdk-resources'
|
|
4
4
|
module RestFtpDaemon
|
5
5
|
module Remote
|
6
6
|
class RemoteS3 < RemoteBase
|
7
|
-
|
8
|
-
MULTIPART_THRESHOLD_MB = 4
|
7
|
+
include CommonHelpers
|
9
8
|
|
10
9
|
# Class options
|
11
10
|
attr_reader :client
|
12
11
|
attr_reader :target
|
13
12
|
|
14
|
-
def prepare
|
15
|
-
|
16
|
-
log_debug "RemoteS3.prepare target[#{@target.inspect}] #{@multipart_threshold}"
|
17
|
-
end
|
13
|
+
# def prepare
|
14
|
+
# end
|
18
15
|
|
19
16
|
def connect
|
20
17
|
super
|
21
18
|
|
22
19
|
# Connect init
|
23
|
-
log_debug "
|
20
|
+
log_debug "connect region[#{target.aws_region}] id[#{target.aws_id}]"
|
24
21
|
|
25
22
|
# Connect remote server
|
26
|
-
@client = Aws::S3::
|
23
|
+
@client = Aws::S3::Client.new(
|
27
24
|
region: @target.aws_region,
|
28
25
|
credentials: Aws::Credentials.new(@target.aws_id, @target.aws_secret),
|
29
|
-
# thread_count: 4,
|
30
26
|
http_wire_trace: @debug
|
31
27
|
)
|
32
|
-
|
28
|
+
end
|
29
|
+
|
30
|
+
def size_if_exists target
|
31
|
+
log_debug "size_if_exists [#{target.path}]"
|
32
|
+
object = @client.get_object(bucket: target.aws_bucket, key: target.path)
|
33
|
+
rescue Aws::S3::Errors::NotFound => e
|
34
|
+
return false
|
35
|
+
else
|
36
|
+
return object.content_length
|
33
37
|
end
|
34
38
|
|
35
39
|
def upload source, target, use_temp_name = false, &callback
|
36
40
|
# Push init
|
37
41
|
raise RestFtpDaemon::AssertionFailed, "upload/client" if @client.nil?
|
38
|
-
log_debug "
|
39
|
-
|
40
|
-
# Update progress before
|
41
|
-
#yield 0, target.name
|
42
|
-
# Point to the right bucket and object
|
43
|
-
bucket = @client.bucket(target.aws_bucket)
|
44
|
-
object = bucket.object(target.name)
|
45
|
-
|
46
|
-
# Do the transfer
|
47
|
-
object.upload_file(source.path, {
|
48
|
-
multipart_threshold: @multipart_threshold
|
49
|
-
})
|
42
|
+
log_debug "upload bucket[#{target.aws_bucket}] path[#{target.path}]"
|
50
43
|
|
51
|
-
#
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
# puts response.data.inspect
|
59
|
-
# end
|
60
|
-
# log_debug "- progress[] #{waiter.inspect}"
|
44
|
+
# Do the transfer, passing the file to the best method
|
45
|
+
File.open(source.filepath, 'r', encoding: 'BINARY') do |file|
|
46
|
+
if file.size >= JOB_S3_MIN_PART
|
47
|
+
upload_multipart file, target.aws_bucket, target.path, target.name, &callback
|
48
|
+
else
|
49
|
+
upload_onefile file, target.aws_bucket, target.path, target.name, &callback
|
50
|
+
end
|
61
51
|
end
|
62
52
|
|
63
|
-
#
|
64
|
-
|
65
|
-
|
66
|
-
# Dump information about this file
|
67
|
-
log_debug "RemoteS3.upload url[#{object.public_url}]"
|
68
|
-
log_debug "RemoteS3.upload etag[#{object.etag}]"
|
69
|
-
set_info :target_aws_public_url, object.public_url
|
70
|
-
set_info :target_aws_etag, object.etag
|
53
|
+
# We're all set
|
54
|
+
log_debug "RemoteS3.upload done"
|
71
55
|
end
|
72
56
|
|
73
57
|
def connected?
|
74
58
|
!@client.nil?
|
75
59
|
end
|
76
60
|
|
61
|
+
private
|
62
|
+
|
63
|
+
def upload_onefile file, s3_bucket, s3_path, s3_name, &callback
|
64
|
+
log_debug "upload_onefile"
|
65
|
+
@client.put_object(bucket: s3_bucket, key: s3_path, body: file)
|
66
|
+
end
|
67
|
+
|
68
|
+
def upload_multipart file, s3_bucket, s3_path, s3_name, &callback
|
69
|
+
# Init
|
70
|
+
current_part = 1
|
71
|
+
|
72
|
+
# Compute parameters
|
73
|
+
file_size = file.size
|
74
|
+
parts_size = compute_parts_size(file_size)
|
75
|
+
parts_count = (file_size.to_f / parts_size).ceil
|
76
|
+
log_debug "upload_multipart", {
|
77
|
+
file_size: format_bytes(file_size, "B"),
|
78
|
+
parts_size: format_bytes(parts_size, "B"),
|
79
|
+
parts_count: parts_count
|
80
|
+
}
|
81
|
+
|
82
|
+
# Prepare basic opts
|
83
|
+
options = {
|
84
|
+
bucket: s3_bucket,
|
85
|
+
key: s3_path,
|
86
|
+
}
|
87
|
+
|
88
|
+
# Declare multipart upload
|
89
|
+
mpu_create_response = @client.create_multipart_upload(options)
|
90
|
+
options[:upload_id] = mpu_create_response.upload_id
|
91
|
+
log_debug "created multipart id[#{options[:upload_id]}]"
|
92
|
+
|
93
|
+
# Upload each part
|
94
|
+
file.each_part(parts_size) do |part|
|
95
|
+
# Prepare part upload
|
96
|
+
opts = options.merge({
|
97
|
+
body: part,
|
98
|
+
part_number: current_part,
|
99
|
+
})
|
100
|
+
log_debug "upload_part [#{current_part}/#{parts_count}]"
|
101
|
+
resp = @client.upload_part(opts)
|
102
|
+
|
103
|
+
# Send progress info upwards
|
104
|
+
yield parts_size, s3_name
|
105
|
+
|
106
|
+
# Increment part number
|
107
|
+
current_part += 1
|
108
|
+
end
|
109
|
+
|
110
|
+
# Retrieve parts and complete upload
|
111
|
+
log_debug "complete_multipart_upload"
|
112
|
+
parts_resp = @client.list_parts(options)
|
113
|
+
|
114
|
+
those_parts = parts_resp.parts.map do |part|
|
115
|
+
{ part_number: part.part_number, etag: part.etag }
|
116
|
+
end
|
117
|
+
opts = options.merge({
|
118
|
+
multipart_upload: {
|
119
|
+
parts: those_parts
|
120
|
+
}
|
121
|
+
})
|
122
|
+
mpu_complete_response = @client.complete_multipart_upload(opts)
|
123
|
+
end
|
124
|
+
|
125
|
+
def compute_parts_size filesize
|
126
|
+
# Initial part size is minimal
|
127
|
+
partsize_mini = JOB_S3_MIN_PART
|
128
|
+
|
129
|
+
# Other partsize if too many blocks
|
130
|
+
partsize_bigf = (filesize.to_f / JOB_S3_MAX_COUNT).ceil
|
131
|
+
|
132
|
+
# Decide
|
133
|
+
return [partsize_mini, partsize_bigf].max
|
134
|
+
end
|
135
|
+
|
77
136
|
end
|
78
137
|
end
|
79
|
-
end
|
138
|
+
end
|
@@ -8,14 +8,14 @@ module RestFtpDaemon
|
|
8
8
|
# Class options
|
9
9
|
attr_reader :sftp
|
10
10
|
|
11
|
-
def prepare
|
12
|
-
end
|
11
|
+
# def prepare
|
12
|
+
# end
|
13
13
|
|
14
14
|
def connect
|
15
15
|
super
|
16
16
|
|
17
17
|
# Connect init
|
18
|
-
log_debug "
|
18
|
+
log_debug "connect [#{@target.user}]@[#{@target.host}]:[#{@target.port}]"
|
19
19
|
|
20
20
|
# Debug level
|
21
21
|
verbosity = @debug ? Logger::DEBUG : false
|
@@ -30,9 +30,9 @@ module RestFtpDaemon
|
|
30
30
|
)
|
31
31
|
end
|
32
32
|
|
33
|
-
def
|
34
|
-
log_debug "
|
35
|
-
stat = @sftp.stat! target.
|
33
|
+
def size_if_exists target
|
34
|
+
log_debug "size_if_exists [#{target.name}]"
|
35
|
+
stat = @sftp.stat! target.filepath
|
36
36
|
|
37
37
|
rescue Net::SFTP::StatusException
|
38
38
|
return false
|
@@ -41,8 +41,8 @@ module RestFtpDaemon
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def remove! target
|
44
|
-
log_debug "
|
45
|
-
@sftp.remove target.
|
44
|
+
log_debug "remove! [#{target.name}]"
|
45
|
+
@sftp.remove target.filepath
|
46
46
|
|
47
47
|
rescue Net::SFTP::StatusException
|
48
48
|
log_debug "#{LOG_INDENT}[#{target.name}] file not found"
|
@@ -51,7 +51,7 @@ module RestFtpDaemon
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def mkdir directory
|
54
|
-
log_debug "
|
54
|
+
log_debug "mkdir [#{directory}]"
|
55
55
|
@sftp.mkdir! directory
|
56
56
|
|
57
57
|
rescue StandardError => ex
|
@@ -60,7 +60,7 @@ module RestFtpDaemon
|
|
60
60
|
|
61
61
|
def chdir_or_create directory, mkdir = false
|
62
62
|
# Init, extract my parent name and my own name
|
63
|
-
log_debug "
|
63
|
+
log_debug "chdir_or_create mkdir[#{mkdir}] dir[#{directory}]"
|
64
64
|
parent, _current = split_path(directory)
|
65
65
|
|
66
66
|
# Access this directory
|
@@ -98,8 +98,8 @@ module RestFtpDaemon
|
|
98
98
|
end
|
99
99
|
|
100
100
|
# Do the transfer
|
101
|
-
log_debug "
|
102
|
-
@sftp.upload! source.
|
101
|
+
log_debug "upload temp[#{use_temp_name}] name[#{dest.name}]"
|
102
|
+
@sftp.upload! source.filepath, dest.filepath do |event, _uploader, *args|
|
103
103
|
case event
|
104
104
|
when :open then
|
105
105
|
# args[0] : file metadata
|
@@ -124,8 +124,8 @@ module RestFtpDaemon
|
|
124
124
|
# Move the file back to its original name
|
125
125
|
if use_temp_name
|
126
126
|
flags = 0x00000001
|
127
|
-
log_debug "
|
128
|
-
@sftp.rename! dest.
|
127
|
+
log_debug "upload rename [#{dest.name}] > [#{target.name}]"
|
128
|
+
@sftp.rename! dest.filepath, target.filepath, flags
|
129
129
|
end
|
130
130
|
|
131
131
|
# progress:
|
@@ -143,4 +143,4 @@ module RestFtpDaemon
|
|
143
143
|
|
144
144
|
end
|
145
145
|
end
|
146
|
-
end
|
146
|
+
end
|
@@ -149,16 +149,46 @@ body {
|
|
149
149
|
|
150
150
|
|
151
151
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
152
|
.indicators .btn {
|
156
153
|
cursor: pointer;
|
157
154
|
opacity: 1;
|
158
155
|
filter: alpha(opacity=100);
|
156
|
+
}
|
157
|
+
|
158
|
+
.label-group .label {
|
159
|
+
/*border: 1px solid red;*/
|
160
|
+
}
|
161
|
+
|
162
|
+
.label-group>.label:not(:last-child) {
|
163
|
+
border-bottom-right-radius: 0;
|
164
|
+
border-top-right-radius: 0;
|
165
|
+
margin-right: 0;
|
166
|
+
}
|
167
|
+
|
168
|
+
.label-group>.label:not(:first-child) {
|
169
|
+
border-bottom-left-radius: 0;
|
170
|
+
border-top-left-radius: 0;
|
171
|
+
margin-left: 0;
|
172
|
+
}
|
173
|
+
|
174
|
+
.label.label-simple {
|
175
|
+
color: black;
|
176
|
+
border: 1px solid silver;
|
177
|
+
background-color: white;
|
178
|
+
}
|
179
|
+
/*
|
180
|
+
.label-group>.label:first-child:not(:last-child) {
|
181
|
+
border-bottom-right-radius: 0;
|
182
|
+
border-top-right-radius: 0;
|
183
|
+
}
|
184
|
+
|
185
|
+
.label-group>.label:last-child:not(:first-child) {
|
186
|
+
border-bottom-left-radius: 0;
|
187
|
+
border-top-left-radius: 0;
|
159
188
|
}
|
189
|
+
*/
|
160
190
|
|
161
191
|
.transfer-type {
|
162
|
-
width: 40px
|
192
|
+
/*width: 40px;*/
|
163
193
|
}
|
164
194
|
|
data/lib/rest-ftp-daemon/uri.rb
CHANGED
@@ -34,12 +34,15 @@
|
|
34
34
|
%td= job.label
|
35
35
|
|
36
36
|
%td
|
37
|
-
= location_label job.
|
38
|
-
=
|
37
|
+
= location_label job.source_loc
|
38
|
+
= job.source_uri.path
|
39
|
+
=# token_highlight job.source
|
39
40
|
|
40
41
|
%td
|
41
|
-
= location_label job.
|
42
|
-
=
|
42
|
+
= location_label job.target_loc
|
43
|
+
= job.target_uri.path
|
44
|
+
|
45
|
+
=# token_highlight job.target
|
43
46
|
|
44
47
|
%td
|
45
48
|
%span.push-status
|
@@ -85,4 +88,4 @@
|
|
85
88
|
.label.label-default.flag.worker-label= job.priority
|
86
89
|
|
87
90
|
%td
|
88
|
-
.label.flag.worker-label{class: job_tentatives_style(job.tentatives)}= job.tentatives
|
91
|
+
.label.flag.worker-label{class: job_tentatives_style(job.tentatives)}= job.tentatives
|
@@ -32,7 +32,7 @@ module RestFtpDaemon
|
|
32
32
|
if !(pools.is_a? Hash)
|
33
33
|
log_error "create_threads: one JobWorker is the minimum (#{pools.inspect}"
|
34
34
|
end
|
35
|
-
log_info "
|
35
|
+
log_info "creating all workers with #{pools.to_hash.inspect}"
|
36
36
|
|
37
37
|
# Start ConchitaWorker and ReporterWorker
|
38
38
|
create_thread ConchitaWorker, :conchita
|
@@ -101,4 +101,4 @@ module RestFtpDaemon
|
|
101
101
|
add_transaction_tracer :create_thread, category: :task
|
102
102
|
|
103
103
|
end
|
104
|
-
end
|
104
|
+
end
|
@@ -15,7 +15,7 @@ module RestFtpDaemon
|
|
15
15
|
return "invalid timeout" unless @config[:timeout].to_i > 0
|
16
16
|
|
17
17
|
# Log that
|
18
|
-
log_info "
|
18
|
+
log_info "worker_init", {
|
19
19
|
pool: @pool,
|
20
20
|
timeout: @config[:timeout]
|
21
21
|
}
|
@@ -80,7 +80,7 @@ module RestFtpDaemon
|
|
80
80
|
# If job status requires a retry, just restack it
|
81
81
|
if !job.error
|
82
82
|
# Processing successful
|
83
|
-
log_info "job_result: finished
|
83
|
+
log_info "job_result: finished successfully"
|
84
84
|
worker_status WORKER_STATUS_FINISHED, job
|
85
85
|
|
86
86
|
elsif error_not_eligible(job)
|
@@ -141,4 +141,4 @@ module RestFtpDaemon
|
|
141
141
|
end
|
142
142
|
|
143
143
|
end
|
144
|
-
end
|
144
|
+
end
|