rest-ftp-daemon 0.422.0 → 0.423.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 +1 -1
- data/Gemfile.lock +9 -4
- data/README.md +1 -1
- data/lib/rest-ftp-daemon/api/debug.rb +1 -1
- data/lib/rest-ftp-daemon/api/entities/job.rb +40 -42
- data/lib/rest-ftp-daemon/api/entities/location.rb +25 -0
- data/lib/rest-ftp-daemon/api/entities/options.rb +5 -7
- data/lib/rest-ftp-daemon/api/jobs.rb +33 -19
- data/lib/rest-ftp-daemon/api/root-real.rb +1 -1
- data/lib/rest-ftp-daemon/api/root-test.rb +1 -1
- data/lib/rest-ftp-daemon/constants.rb +5 -3
- data/lib/rest-ftp-daemon/job.rb +60 -90
- data/lib/rest-ftp-daemon/job_queue.rb +1 -2
- data/lib/rest-ftp-daemon/jobs/transfer.rb +12 -12
- data/lib/rest-ftp-daemon/jobs/video.rb +9 -12
- data/lib/rest-ftp-daemon/location.rb +6 -3
- data/lib/rest-ftp-daemon/remote.rb +0 -1
- data/lib/rest-ftp-daemon/remote_ftp.rb +1 -1
- data/lib/rest-ftp-daemon/remote_s3.rb +26 -11
- data/lib/rest-ftp-daemon/uri.rb +6 -6
- data/lib/rest-ftp-daemon/views/dashboard_table.haml +12 -10
- data/lib/rest-ftp-daemon.rb +1 -0
- data/rest-ftp-daemon.gemspec +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee5c41955196c0b319075e59701f5a4632239c7d
|
4
|
+
data.tar.gz: 7821497a1f9810b6c555e4f60c3c5e5ff5fa87c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 456fe58b0004eae8d1cca760dd19f9455ef6012c9352bcabcdb4e9431862c8e6a7ac673b5219b5769bbe780a05a6400f9aa694eb51813d8bbdc6b99855fbf072
|
7
|
+
data.tar.gz: 5aa70020d1461e97c256071281e616c6f10c297428d4111203fe624fb83c12ccc6d08c24109f3e311b3dd2035b44154601972788c4329573e792f3a1d687afd4
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,13 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../bmc-daemon-lib
|
3
|
+
specs:
|
4
|
+
bmc-daemon-lib (0.3.4)
|
5
|
+
chamber (~> 2.9)
|
6
|
+
|
1
7
|
PATH
|
2
8
|
remote: .
|
3
9
|
specs:
|
4
|
-
rest-ftp-daemon (0.
|
10
|
+
rest-ftp-daemon (0.423.0)
|
5
11
|
activesupport (~> 4.2)
|
6
12
|
api-auth
|
7
13
|
aws-sdk-resources (~> 2)
|
@@ -47,8 +53,6 @@ GEM
|
|
47
53
|
descendants_tracker (~> 0.0.4)
|
48
54
|
ice_nine (~> 0.11.0)
|
49
55
|
thread_safe (~> 0.3, >= 0.3.1)
|
50
|
-
bmc-daemon-lib (0.3.4)
|
51
|
-
chamber (~> 2.9)
|
52
56
|
builder (3.2.2)
|
53
57
|
chamber (2.9.1)
|
54
58
|
hashie (~> 3.3)
|
@@ -144,7 +148,7 @@ GEM
|
|
144
148
|
rspec-core (~> 3.5.0)
|
145
149
|
rspec-expectations (~> 3.5.0)
|
146
150
|
rspec-mocks (~> 3.5.0)
|
147
|
-
rspec-core (3.5.
|
151
|
+
rspec-core (3.5.3)
|
148
152
|
rspec-support (~> 3.5.0)
|
149
153
|
rspec-expectations (3.5.0)
|
150
154
|
diff-lcs (>= 1.2.0, < 2.0)
|
@@ -189,6 +193,7 @@ PLATFORMS
|
|
189
193
|
ruby
|
190
194
|
|
191
195
|
DEPENDENCIES
|
196
|
+
bmc-daemon-lib!
|
192
197
|
bundler (~> 1.6)
|
193
198
|
http
|
194
199
|
pry
|
data/README.md
CHANGED
@@ -353,7 +353,7 @@ Known bugs
|
|
353
353
|
|
354
354
|
* As this project is based on Chamber, and it considers hyphens in filename as namespaces, the global /etc/rest-ftp-daemon.yml config file is not parsed (and thus, ignored). Until this is worked around, please specify a config filename on the commandline.
|
355
355
|
|
356
|
-
* If you get ```fatal error: 'openssl/ssl.h' file not found when installing
|
356
|
+
* If you get ```fatal error: 'openssl/ssl.h' file not found when installing eventmachine``` on OSX El Capitan, you can try with:
|
357
357
|
```
|
358
358
|
gem install eventmachine -v '1.0.8' -- --with-cppflags=-I/usr/local/opt/openssl/include
|
359
359
|
bundle install
|
@@ -24,7 +24,7 @@ module RestFtpDaemon
|
|
24
24
|
me[:error] = job.error.encoding.to_s unless job.error.nil?
|
25
25
|
me[:status] = job.status.encoding.to_s unless job.status.nil?
|
26
26
|
|
27
|
-
RestFtpDaemon::Job::
|
27
|
+
RestFtpDaemon::Job::IMPORTED.each do |name|
|
28
28
|
value = job.send(name)
|
29
29
|
me[name] = value.encoding.to_s if value.is_a? String
|
30
30
|
end
|
@@ -1,59 +1,57 @@
|
|
1
1
|
require "grape-entity"
|
2
2
|
|
3
3
|
module RestFtpDaemon
|
4
|
-
module
|
5
|
-
|
6
|
-
class Job < Grape::Entity
|
4
|
+
module Entities
|
5
|
+
class Job < Grape::Entity
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
RestFtpDaemon::Job::FIELDS.each { |name| expose name }
|
13
|
-
|
14
|
-
# Technical fields
|
15
|
-
expose :wid, unless: lambda { |object, _options| object.wid.nil? }
|
16
|
-
|
17
|
-
# expose :error
|
18
|
-
expose :json_error, as: :error
|
19
|
-
expose :json_status, as: :status
|
20
|
-
#expose :json_target, as: :target_method
|
7
|
+
# Some formatters
|
8
|
+
format_with(:utf8_filter) do |thing|
|
9
|
+
thing.to_s.encode("UTF-8") if thing
|
10
|
+
end
|
21
11
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
expose :finished_at
|
12
|
+
# Job-execution related
|
13
|
+
expose :id
|
14
|
+
expose :wid, unless: lambda { |object, _options| object.wid.nil? }
|
26
15
|
|
27
|
-
|
28
|
-
|
29
|
-
expose
|
16
|
+
# Attributes from API
|
17
|
+
RestFtpDaemon::Job::IMPORTED.each do |field|
|
18
|
+
expose field
|
19
|
+
end
|
30
20
|
|
31
|
-
|
32
|
-
|
21
|
+
# Work-specific options
|
22
|
+
expose :overwrite
|
23
|
+
expose :mkdir
|
24
|
+
expose :tempfile
|
25
|
+
expose :video_custom
|
33
26
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
# expose :video_custom
|
27
|
+
# Job/Video options
|
28
|
+
expose :video_options
|
29
|
+
#, using: Entities::VideoOptions
|
38
30
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
# end
|
31
|
+
# Status and error
|
32
|
+
expose :status, format_with: :utf8_filter
|
33
|
+
expose :error, format_with: :utf8_filter
|
43
34
|
|
44
|
-
|
45
|
-
|
35
|
+
# Time stamps
|
36
|
+
expose :queued_at
|
37
|
+
expose :updated_at
|
38
|
+
expose :started_at
|
39
|
+
expose :finished_at
|
46
40
|
|
47
|
-
|
48
|
-
|
49
|
-
|
41
|
+
# Computed fields
|
42
|
+
expose :age #, safe: true
|
43
|
+
expose :exectime
|
50
44
|
|
51
|
-
|
45
|
+
# Infos
|
46
|
+
expose :infos, unless: :hide_infos
|
52
47
|
|
53
|
-
|
54
|
-
|
48
|
+
# Source and target #, :unless => Proc.new {|g| g.source_loc.nil?}
|
49
|
+
expose :source_loc, using: Entities::Location#, as: :source
|
50
|
+
expose :target_loc, using: Entities::Location#, as: :target
|
55
51
|
|
56
|
-
|
52
|
+
# expose :slots do |station,options|
|
53
|
+
# station.slots.map{ |slot| SlotEntity.new(slot).serializable_hash }
|
54
|
+
# end
|
57
55
|
end
|
58
56
|
end
|
59
57
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "grape-entity"
|
2
|
+
|
3
|
+
module RestFtpDaemon
|
4
|
+
module Entities
|
5
|
+
class Location < Grape::Entity
|
6
|
+
|
7
|
+
expose :original, as: '_'
|
8
|
+
expose :uri
|
9
|
+
expose :scheme
|
10
|
+
|
11
|
+
expose :host, unless: Proc.new {|obj| obj.host.nil?}
|
12
|
+
expose :user, unless: Proc.new {|obj| obj.user.nil?}
|
13
|
+
expose :port, if: Proc.new {|obj| !obj.port.nil?}
|
14
|
+
|
15
|
+
expose :dir
|
16
|
+
expose :name
|
17
|
+
expose :path
|
18
|
+
|
19
|
+
expose :aws_region ,unless: Proc.new {|obj| obj.aws_region.nil?}
|
20
|
+
expose :aws_bucket, unless: Proc.new {|obj| obj.aws_bucket.nil?}
|
21
|
+
expose :aws_id, unless: Proc.new {|obj| obj.aws_id.nil?}
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,15 +1,13 @@
|
|
1
1
|
require "grape-entity"
|
2
2
|
|
3
3
|
module RestFtpDaemon
|
4
|
-
module
|
5
|
-
|
6
|
-
class Options < Grape::Entity
|
4
|
+
module Entities
|
5
|
+
class Options < Grape::Entity
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
# expose :opt1, documentation: { type: 'Boolean', desc: 'opt UN', required: false }
|
8
|
+
expose :opt2
|
9
|
+
# expose :opt6
|
11
10
|
|
12
|
-
end
|
13
11
|
end
|
14
12
|
end
|
15
13
|
end
|
@@ -33,7 +33,7 @@ module RestFtpDaemon
|
|
33
33
|
|
34
34
|
else
|
35
35
|
status 200
|
36
|
-
present job, with: RestFtpDaemon::
|
36
|
+
present job, with: RestFtpDaemon::Entities::Job, type: "complete"
|
37
37
|
|
38
38
|
end
|
39
39
|
end
|
@@ -53,7 +53,7 @@ module RestFtpDaemon
|
|
53
53
|
|
54
54
|
else
|
55
55
|
status 200
|
56
|
-
present jobs, with: RestFtpDaemon::
|
56
|
+
present jobs, with: RestFtpDaemon::Entities::Job
|
57
57
|
|
58
58
|
end
|
59
59
|
end
|
@@ -63,30 +63,45 @@ module RestFtpDaemon
|
|
63
63
|
requires :source, type: String, desc: "Source file pattern"
|
64
64
|
requires :target, type: String, desc: "Target remote path"
|
65
65
|
|
66
|
-
optional :label, type: String, desc: "Descriptive label
|
66
|
+
optional :label, type: String, desc: "Descriptive label (info only)"
|
67
67
|
optional :notify, type: String, desc: "URL to get POST'ed notifications back"
|
68
|
-
optional :priority, type: Integer, desc: "Priority level of the job (lower is stronger)"
|
69
|
-
optional :pool, type: String, desc: "Pool of worker to be used"
|
70
68
|
optional :type,
|
71
69
|
type: String,
|
72
70
|
desc: "Type of job",
|
73
71
|
default: JOB_TYPE_TRANSFER,
|
74
72
|
values: {value: JOB_TYPES, message: "should be one of: #{JOB_TYPES.join', '}"},
|
75
73
|
allow_blank: { value: false, message: 'cannot be empty' }
|
76
|
-
|
77
|
-
optional :video_vc,
|
78
|
-
type: String,
|
79
|
-
desc: "video: video codec",
|
80
|
-
default: nil
|
81
|
-
optional :video_ac,
|
74
|
+
optional :pool,
|
82
75
|
type: String,
|
83
|
-
desc: "
|
84
|
-
default:
|
76
|
+
desc: "Pool of worker to be used",
|
77
|
+
default: DEFAULT_POOL
|
78
|
+
optional :priority,
|
79
|
+
type: Integer,
|
80
|
+
desc: "Priority level of the job (lower is stronger)",
|
81
|
+
default: 0
|
82
|
+
|
83
|
+
# optional :video_options,
|
84
|
+
# type: Hash,
|
85
|
+
# type: Entities::VideoOptions,
|
86
|
+
# desc: "Video: standard options passed to FFMPEG encoder",
|
87
|
+
# default: {}
|
88
|
+
|
89
|
+
optional :video_options, type: Hash, desc: "Options passed to FFMPEG encoder" do
|
90
|
+
optional :video_codec, type: String
|
91
|
+
optional :video_bitrate, type: String
|
92
|
+
optional :video_bitrate_tolerance, type: String
|
93
|
+
optional :frame_rate, type: Integer
|
94
|
+
optional :resolution, type: String
|
95
|
+
optional :aspect, type: String
|
96
|
+
optional :keyframe_interval, type: String
|
97
|
+
optional :x264_vprofile, type: String
|
98
|
+
optional :x264_preset, type: String
|
99
|
+
optional :audio_codec, type: String
|
100
|
+
optional :audio_bitrate, type: String
|
101
|
+
optional :audio_sample_rate, type: Integer
|
102
|
+
optional :audio_channels, type: String
|
103
|
+
end
|
85
104
|
|
86
|
-
optional :video_options,
|
87
|
-
type: Hash,
|
88
|
-
desc: "Video: standard options passed to FFMPEG encoder",
|
89
|
-
default: {}
|
90
105
|
optional :video_custom,
|
91
106
|
type: Hash,
|
92
107
|
desc: "video: custom options passed to FFMPEG encoder",
|
@@ -104,7 +119,6 @@ module RestFtpDaemon
|
|
104
119
|
type: Boolean,
|
105
120
|
desc: "Upload to a temp file before renaming it to the target filename",
|
106
121
|
default: Conf.at(:transfer, :tempfile)
|
107
|
-
# optional :options, desc: "Options passed to FFMPEG (video jobs)", type: API::Entities::Options
|
108
122
|
end
|
109
123
|
|
110
124
|
post "/" do
|
@@ -130,7 +144,7 @@ module RestFtpDaemon
|
|
130
144
|
|
131
145
|
else
|
132
146
|
status 201
|
133
|
-
present job, with: RestFtpDaemon::
|
147
|
+
present job, with: RestFtpDaemon::Entities::Job, hide_params: true
|
134
148
|
|
135
149
|
end
|
136
150
|
end
|
@@ -4,10 +4,8 @@ DEFAULT_SFTP_TIMEOUT = 600 # 10mn
|
|
4
4
|
DEFAULT_FTP_CHUNK = 1024 # 1 MB
|
5
5
|
DEFAULT_PAGE_SIZE = 50 # 50 lines
|
6
6
|
DEFAULT_RETRY_AFTER = 10 # 10s
|
7
|
-
|
8
7
|
TARGET_BLANK = "_blank"
|
9
8
|
|
10
|
-
|
11
9
|
# Internal job constants
|
12
10
|
JOB_RANDOM_LEN = 8
|
13
11
|
JOB_IDENT_LEN = 4
|
@@ -17,9 +15,13 @@ JOB_UPDATE_INTERVAL = 1
|
|
17
15
|
JOB_FFMPEG_THREADS = 2
|
18
16
|
JOB_FFMPEG_ATTRIBUTES = [:video_codec, :video_bitrate, :video_bitrate_tolerance, :frame_rate, :resolution, :aspect, :keyframe_interval, :x264_vprofile, :x264_preset, :audio_codec, :audio_bitrate, :audio_sample_rate, :audio_channels]
|
19
17
|
|
18
|
+
# Internal job infos
|
19
|
+
INFO_PROGRESS = :work_progress
|
20
|
+
INFO_BITRATE = :transfer_bitrate
|
21
|
+
|
20
22
|
# Constants: logger
|
21
23
|
LOG_ROTATION = "daily"
|
22
|
-
LOG_FORMAT_PROGNAME
|
24
|
+
LOG_FORMAT_PROGNAME = "%d\t%s"
|
23
25
|
LOG_HEADER_TIME = "%Y-%m-%d %H:%M:%S"
|
24
26
|
LOG_HEADER_FORMAT = "%s \t%d\t%-8s %-10s "
|
25
27
|
LOG_MESSAGE_TRIM = 200
|
data/lib/rest-ftp-daemon/job.rb
CHANGED
@@ -14,15 +14,14 @@ module RestFtpDaemon
|
|
14
14
|
attr_reader :logger
|
15
15
|
include BmcDaemonLib::LoggerHelper
|
16
16
|
|
17
|
-
#
|
18
|
-
|
19
|
-
:overwrite, :mkdir, :tempfile,
|
20
|
-
:video_options, :video_custom
|
21
|
-
]
|
17
|
+
# Fields to be imported from params
|
18
|
+
IMPORTED = %w(type priority pool label priority source target overwrite mkdir tempfile video_options video_custom)
|
22
19
|
|
23
20
|
# Class options
|
24
21
|
attr_accessor :wid
|
25
|
-
|
22
|
+
|
23
|
+
attr_reader :source_loc
|
24
|
+
attr_reader :target_loc
|
26
25
|
|
27
26
|
attr_reader :id
|
28
27
|
attr_reader :error
|
@@ -35,12 +34,14 @@ module RestFtpDaemon
|
|
35
34
|
attr_reader :finished_at
|
36
35
|
|
37
36
|
attr_reader :infos
|
38
|
-
attr_reader :
|
37
|
+
#attr_reader :config
|
39
38
|
|
40
|
-
|
39
|
+
# delegate :type, :pool, :label, :priority,
|
40
|
+
# to: :params
|
41
41
|
|
42
|
-
|
43
|
-
|
42
|
+
# Define readers from imported fields
|
43
|
+
IMPORTED.each do |field|
|
44
|
+
attr_reader field
|
44
45
|
end
|
45
46
|
|
46
47
|
def initialize job_id = nil, params = {}
|
@@ -52,14 +53,14 @@ module RestFtpDaemon
|
|
52
53
|
return if job_id.nil?
|
53
54
|
|
54
55
|
# Init context
|
55
|
-
@id
|
56
|
-
|
57
|
-
@
|
58
|
-
@
|
59
|
-
@error
|
60
|
-
@status
|
61
|
-
@runs
|
62
|
-
@wid
|
56
|
+
@id = job_id.to_s
|
57
|
+
@started_at = nil
|
58
|
+
@finished_at = nil
|
59
|
+
@updated_at = nil
|
60
|
+
@error = nil
|
61
|
+
@status = nil
|
62
|
+
@runs = 0
|
63
|
+
@wid = nil
|
63
64
|
|
64
65
|
# Prepare configuration
|
65
66
|
@config = Conf[:transfer] || {}
|
@@ -67,27 +68,33 @@ module RestFtpDaemon
|
|
67
68
|
@pools = Conf[:pools] || {}
|
68
69
|
|
69
70
|
# Logger
|
70
|
-
@logger
|
71
|
+
@logger = BmcDaemonLib::LoggerPool.instance.get :transfer
|
71
72
|
|
72
73
|
# Import query params
|
73
|
-
|
74
|
-
|
74
|
+
set_info :params, params
|
75
|
+
IMPORTED.each do |field|
|
76
|
+
instance_variable_set "@#{field}", params[field]
|
75
77
|
end
|
76
78
|
|
77
79
|
# Check if pool name exists
|
78
|
-
|
79
|
-
@pool = params[:pool].to_s
|
80
|
-
else
|
81
|
-
@pool = DEFAULT_POOL
|
82
|
-
end
|
80
|
+
@pool = DEFAULT_POOL unless @pools.keys.include?(@pool)
|
83
81
|
|
84
82
|
# Prepare sources/target
|
85
|
-
|
86
|
-
|
83
|
+
raise RestFtpDaemon::AttributeMissing, "source" unless params[:source]
|
84
|
+
@source_loc = Location.new(params[:source])
|
85
|
+
#set_info :location_source, params[:source]
|
86
|
+
log_info "Job.initialize source #{@source_loc.uri}"
|
87
|
+
|
88
|
+
raise RestFtpDaemon::AttributeMissing, "target" unless params[:target]
|
89
|
+
@target_loc = Location.new(params[:target])
|
90
|
+
#set_info :location_target, params[:target]
|
91
|
+
log_info "Job.initialize target #{@target_loc.uri}"
|
87
92
|
|
88
93
|
# Handle exceptions
|
89
|
-
rescue RestFtpDaemon::
|
90
|
-
|
94
|
+
# rescue RestFtpDaemon::UnresolvedTokens => exception
|
95
|
+
# return oops :started, exception
|
96
|
+
# rescue RestFtpDaemon::UnsupportedScheme => exception
|
97
|
+
# return oops :started, exception
|
91
98
|
end
|
92
99
|
|
93
100
|
def reset
|
@@ -101,8 +108,6 @@ module RestFtpDaemon
|
|
101
108
|
# Job has been prepared, reset infos
|
102
109
|
set_status JOB_STATUS_PREPARED
|
103
110
|
@infos = {}
|
104
|
-
set_info_location :source, @source_loc
|
105
|
-
set_info_location :target, @target_loc
|
106
111
|
|
107
112
|
# Update job status, send first notification
|
108
113
|
set_status JOB_STATUS_QUEUED
|
@@ -156,11 +161,11 @@ module RestFtpDaemon
|
|
156
161
|
end
|
157
162
|
|
158
163
|
def source_uri
|
159
|
-
@source_loc.uri
|
164
|
+
@source_loc.uri if @source_loc
|
160
165
|
end
|
161
166
|
|
162
167
|
def target_uri
|
163
|
-
@target_loc.uri
|
168
|
+
@target_loc.uri if @target_loc
|
164
169
|
end
|
165
170
|
|
166
171
|
def weight
|
@@ -190,41 +195,20 @@ module RestFtpDaemon
|
|
190
195
|
end
|
191
196
|
|
192
197
|
def targethost
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
# def json_target
|
197
|
-
# utf8 get_info(:target, :method)
|
198
|
-
# end
|
199
|
-
|
200
|
-
def json_error
|
201
|
-
utf8 @error unless @error.nil?
|
202
|
-
end
|
203
|
-
|
204
|
-
def json_status
|
205
|
-
utf8 @status unless @status.nil?
|
198
|
+
@target_loc.host unless @target_loc.nil?
|
199
|
+
#get_info :target_host
|
206
200
|
end
|
207
201
|
|
208
|
-
|
202
|
+
def get_info name
|
209
203
|
@mutex.synchronize do
|
210
|
-
|
211
|
-
@infos[level1][level2] if @infos[level1].is_a? Hash
|
204
|
+
@infos[name]
|
212
205
|
end
|
213
206
|
end
|
214
207
|
|
215
|
-
def set_info
|
208
|
+
def set_info name, value
|
216
209
|
@mutex.synchronize do
|
217
210
|
@infos || {}
|
218
|
-
@infos[
|
219
|
-
|
220
|
-
# Force strings to UTF8
|
221
|
-
if value.is_a? Symbol
|
222
|
-
@infos[level1][level2] = value.to_s.force_encoding(Encoding::UTF_8)
|
223
|
-
elsif value.is_a? String
|
224
|
-
@infos[level1][level2] = value.dup.force_encoding(Encoding::UTF_8)
|
225
|
-
else
|
226
|
-
@infos[level1][level2] = value
|
227
|
-
end
|
211
|
+
@infos[name] = debug_value_utf8(value)
|
228
212
|
end
|
229
213
|
touch_job
|
230
214
|
end
|
@@ -235,28 +219,6 @@ module RestFtpDaemon
|
|
235
219
|
log_error "Job PLACEHOLDER METHOD CALLED"
|
236
220
|
end
|
237
221
|
|
238
|
-
def prepare_source
|
239
|
-
raise RestFtpDaemon::AttributeMissing, "source" unless @source
|
240
|
-
@source_loc = Location.new @source
|
241
|
-
log_info "Job.prepare_source #{@source_loc.uri}"
|
242
|
-
end
|
243
|
-
|
244
|
-
def prepare_target
|
245
|
-
raise RestFtpDaemon::AttributeMissing, "target" unless @target
|
246
|
-
@target_loc = Location.new @target
|
247
|
-
log_info "Job.prepare_target #{@target_loc.uri}"
|
248
|
-
end
|
249
|
-
|
250
|
-
def set_info_location prefix, location
|
251
|
-
return unless location.is_a? Location
|
252
|
-
fields = [:uri, :scheme, :user, :host, :port, :dir, :name, :path, :aws_region, :aws_bucket, :aws_id]
|
253
|
-
|
254
|
-
# Add each field to @infos
|
255
|
-
fields.each do |what|
|
256
|
-
set_info prefix, "loc_#{what}".to_sym, location.send(what)
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
222
|
private
|
261
223
|
|
262
224
|
def log_prefix
|
@@ -269,6 +231,18 @@ module RestFtpDaemon
|
|
269
231
|
Thread.current.thread_variable_set :updated_at, now
|
270
232
|
end
|
271
233
|
|
234
|
+
# Force strings to UTF8
|
235
|
+
def debug_value_utf8 value
|
236
|
+
case value
|
237
|
+
when Symbol
|
238
|
+
return value.to_s.force_encoding(Encoding::UTF_8)
|
239
|
+
when String
|
240
|
+
return value.dup.force_encoding(Encoding::UTF_8) if value.is_a? String
|
241
|
+
else
|
242
|
+
return value
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
272
246
|
def set_error value
|
273
247
|
@mutex.synchronize do
|
274
248
|
@error = value
|
@@ -283,10 +257,6 @@ module RestFtpDaemon
|
|
283
257
|
touch_job
|
284
258
|
end
|
285
259
|
|
286
|
-
def utf8 value
|
287
|
-
value.to_s.encode("UTF-8")
|
288
|
-
end
|
289
|
-
|
290
260
|
def flag_prepare name
|
291
261
|
# build the flag instance var name
|
292
262
|
variable = "@#{name}"
|
@@ -339,13 +309,13 @@ module RestFtpDaemon
|
|
339
309
|
# Update job's internal status
|
340
310
|
set_status JOB_STATUS_FAILED
|
341
311
|
set_error error
|
342
|
-
set_info :
|
343
|
-
set_info :
|
312
|
+
set_info :error_exception, exception.class.to_s
|
313
|
+
set_info :error_message, exception.message
|
344
314
|
|
345
315
|
# Build status stack
|
346
316
|
notif_status = nil
|
347
317
|
if include_backtrace
|
348
|
-
set_info :
|
318
|
+
set_info :error_backtrace, exception.backtrace
|
349
319
|
notif_status = {
|
350
320
|
backtrace: exception.backtrace,
|
351
321
|
}
|
@@ -102,10 +102,9 @@ module RestFtpDaemon
|
|
102
102
|
next unless job.status == JOB_STATUS_UPLOADING
|
103
103
|
|
104
104
|
# Extract current rate, next if not available
|
105
|
-
rate = job.get_info
|
105
|
+
rate = job.get_info INFO_BITRATE
|
106
106
|
next if rate.nil?
|
107
107
|
|
108
|
-
|
109
108
|
# Add its current rate
|
110
109
|
result[group] ||= 0
|
111
110
|
result[group] += rate
|
@@ -13,7 +13,7 @@ module RestFtpDaemon
|
|
13
13
|
|
14
14
|
# Some init
|
15
15
|
@transfer_sent = 0
|
16
|
-
set_info :
|
16
|
+
set_info :source_processed, 0
|
17
17
|
|
18
18
|
# Ensure source is FILE
|
19
19
|
raise RestFtpDaemon::SourceNotSupported, @source_loc.scheme unless @source_loc.is? URI::FILE
|
@@ -48,8 +48,8 @@ module RestFtpDaemon
|
|
48
48
|
# Scan local source files from disk
|
49
49
|
set_status JOB_STATUS_CHECKING_SRC
|
50
50
|
sources = @source_loc.scan_files
|
51
|
-
set_info :
|
52
|
-
set_info :
|
51
|
+
set_info :source_count, sources.size
|
52
|
+
set_info :source_files, sources.collect(&:name)
|
53
53
|
log_info "JobTransfer.work sources #{sources.collect(&:name)}"
|
54
54
|
raise RestFtpDaemon::SourceNotFound if sources.empty?
|
55
55
|
|
@@ -66,7 +66,7 @@ module RestFtpDaemon
|
|
66
66
|
|
67
67
|
# Compute total files size
|
68
68
|
@transfer_total = sources.collect(&:size).sum
|
69
|
-
set_info :
|
69
|
+
set_info :transfer_total, @transfer_total
|
70
70
|
|
71
71
|
# Reset counters
|
72
72
|
@last_data = 0
|
@@ -85,10 +85,10 @@ module RestFtpDaemon
|
|
85
85
|
|
86
86
|
# Add it to transferred target names
|
87
87
|
targets << target.name
|
88
|
-
set_info :
|
88
|
+
set_info :target_files, targets
|
89
89
|
|
90
90
|
# Update counters
|
91
|
-
set_info :
|
91
|
+
set_info :source_processed, source_processed += 1
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
@@ -116,7 +116,7 @@ module RestFtpDaemon
|
|
116
116
|
|
117
117
|
# Use source filename if target path provided none (typically with multiple sources)
|
118
118
|
log_info "JobTransfer.remote_upload [#{source.name}]: [#{source.path}] > [#{target.path}]"
|
119
|
-
set_info :
|
119
|
+
set_info :source_current, source.name
|
120
120
|
|
121
121
|
# Remove any existing version if present, or check if it's there
|
122
122
|
if @overwrite
|
@@ -145,10 +145,10 @@ module RestFtpDaemon
|
|
145
145
|
|
146
146
|
# Compute final bitrate
|
147
147
|
global_transfer_bitrate = get_bitrate @transfer_total, (Time.now - transfer_started_at)
|
148
|
-
set_info :
|
148
|
+
set_info :transfer_bitrate, global_transfer_bitrate.round(0)
|
149
149
|
|
150
150
|
# Done
|
151
|
-
set_info :
|
151
|
+
set_info :source_current, nil
|
152
152
|
end
|
153
153
|
|
154
154
|
def update_progress transferred, name = ""
|
@@ -158,17 +158,17 @@ module RestFtpDaemon
|
|
158
158
|
|
159
159
|
# Update counters
|
160
160
|
@transfer_sent += transferred
|
161
|
-
set_info :
|
161
|
+
set_info :work_sent, @transfer_sent
|
162
162
|
|
163
163
|
# Update job info
|
164
164
|
percent0 = (100.0 * @transfer_sent / @transfer_total).round(0)
|
165
|
-
set_info
|
165
|
+
set_info INFO_PROGRESS, percent0
|
166
166
|
|
167
167
|
# Update job status after each NOTIFY_UPADE_STATUS
|
168
168
|
progressed_ago = (now.to_f - @progress_at.to_f)
|
169
169
|
if (!JOB_UPDATE_INTERVAL.to_f.zero?) && (progressed_ago > JOB_UPDATE_INTERVAL.to_f)
|
170
170
|
@current_bitrate = running_bitrate @transfer_sent
|
171
|
-
set_info :
|
171
|
+
set_info :transfer_bitrate, @current_bitrate.round(0)
|
172
172
|
|
173
173
|
# Log progress
|
174
174
|
stack = []
|
@@ -42,29 +42,26 @@ module RestFtpDaemon
|
|
42
42
|
FileUtils.mkdir_p @target_loc.dir
|
43
43
|
|
44
44
|
# Do the work, for each file
|
45
|
-
set_info :
|
45
|
+
set_info :source_current, @source_loc.name
|
46
46
|
ffmpeg_command @source_loc, target_final
|
47
47
|
|
48
48
|
# Done
|
49
|
-
set_info :
|
49
|
+
set_info :source_current, nil
|
50
50
|
end
|
51
51
|
|
52
52
|
def do_after
|
53
53
|
# Done
|
54
|
-
set_info :
|
54
|
+
set_info :source_current, nil
|
55
55
|
end
|
56
56
|
|
57
57
|
def ffmpeg_command source, target
|
58
|
-
set_info :
|
58
|
+
set_info :source_current, source.name
|
59
59
|
|
60
60
|
# Read info about source file
|
61
61
|
movie = FFMPEG::Movie.new(source.path)
|
62
|
-
set_info :
|
63
|
-
set_info :
|
64
|
-
set_info :
|
65
|
-
|
66
|
-
|
67
|
-
|
62
|
+
set_info :ffmpeg_size, movie.size
|
63
|
+
set_info :ffmpeg_duration, movie.duration
|
64
|
+
set_info :ffmpeg_resolution, movie.resolution
|
68
65
|
|
69
66
|
# Build options
|
70
67
|
options = {
|
@@ -74,7 +71,7 @@ module RestFtpDaemon
|
|
74
71
|
JOB_FFMPEG_ATTRIBUTES.each do |name|
|
75
72
|
options[name] = @video_options[name] unless @video_options[name].nil?
|
76
73
|
end
|
77
|
-
set_info :
|
74
|
+
set_info :work_ffmpeg_options, options
|
78
75
|
|
79
76
|
# Announce context
|
80
77
|
log_info "JobVideo.ffmpeg_command [#{FFMPEG.ffmpeg_binary}] [#{source.name}] > [#{target.name}]", options
|
@@ -82,7 +79,7 @@ module RestFtpDaemon
|
|
82
79
|
# Build command
|
83
80
|
movie.transcode(target.path, options) do |ffmpeg_progress|
|
84
81
|
# set_info :work, :ffmpeg_progress, ffmpeg_progress
|
85
|
-
set_info
|
82
|
+
set_info INFO_PROGRESS, (100.0 * ffmpeg_progress).round(1)
|
86
83
|
log_debug "progress #{ffmpeg_progress}"
|
87
84
|
end
|
88
85
|
end
|
@@ -8,6 +8,7 @@ module RestFtpDaemon
|
|
8
8
|
# Accessors
|
9
9
|
attr_accessor :name
|
10
10
|
|
11
|
+
attr_reader :original
|
11
12
|
attr_reader :uri
|
12
13
|
attr_reader :scheme
|
13
14
|
attr_reader :dir
|
@@ -25,9 +26,10 @@ module RestFtpDaemon
|
|
25
26
|
delegate :scheme, :host, :port, :user, :password, :to_s,
|
26
27
|
to: :uri
|
27
28
|
|
28
|
-
def initialize
|
29
|
+
def initialize original
|
29
30
|
# Strip spaces before/after, copying original "path" at the same time
|
30
|
-
|
31
|
+
@original = original
|
32
|
+
location_uri = original.strip
|
31
33
|
|
32
34
|
# Replace tokens, fix scheme for local paths
|
33
35
|
resolve_tokens! location_uri
|
@@ -60,6 +62,7 @@ module RestFtpDaemon
|
|
60
62
|
return @name if @dir.nil?
|
61
63
|
File.join(@dir.to_s, @name.to_s)
|
62
64
|
end
|
65
|
+
alias :to_s :path
|
63
66
|
|
64
67
|
def scan_files
|
65
68
|
Dir.glob(path).collect do |file|
|
@@ -114,7 +117,7 @@ module RestFtpDaemon
|
|
114
117
|
@uri = URI.parse path # rescue nil
|
115
118
|
raise RestFtpDaemon::LocationParseError, location_path unless @uri
|
116
119
|
|
117
|
-
#
|
120
|
+
# Path cleanup
|
118
121
|
cleaned = @uri.path.clone
|
119
122
|
|
120
123
|
# remove_leading_slashes
|
@@ -4,12 +4,15 @@ require 'aws-sdk-resources'
|
|
4
4
|
module RestFtpDaemon
|
5
5
|
class RemoteS3 < Remote
|
6
6
|
|
7
|
+
MULTIPART_THRESHOLD_MB = 4
|
8
|
+
|
7
9
|
# Class options
|
8
10
|
attr_reader :client
|
9
11
|
attr_reader :target
|
10
12
|
|
11
13
|
def prepare
|
12
|
-
|
14
|
+
@multipart_threshold = MULTIPART_THRESHOLD_MB.to_i * 1024 * 1024
|
15
|
+
log_debug "RemoteS3.prepare target[#{@target.inspect}] #{@multipart_threshold}"
|
13
16
|
end
|
14
17
|
|
15
18
|
def connect
|
@@ -18,14 +21,13 @@ module RestFtpDaemon
|
|
18
21
|
# Connect init
|
19
22
|
log_debug "RemoteS3.connect region[#{target.aws_region}] id[#{target.aws_id}]"
|
20
23
|
|
21
|
-
# Debug level
|
22
|
-
verbosity = @debug ? Logger::DEBUG : false
|
23
|
-
|
24
24
|
# Connect remote server
|
25
25
|
@client = Aws::S3::Resource.new(
|
26
26
|
region: @target.aws_region,
|
27
|
-
credentials: Aws::Credentials.new(@target.aws_id, @target.aws_secret)
|
27
|
+
credentials: Aws::Credentials.new(@target.aws_id, @target.aws_secret),
|
28
|
+
http_wire_trace: @debug
|
28
29
|
)
|
30
|
+
#s3 = Aws::S3::Client.new(http_wire_trace: true)
|
29
31
|
end
|
30
32
|
|
31
33
|
def upload source, target, use_temp_name = false, &callback
|
@@ -35,12 +37,25 @@ module RestFtpDaemon
|
|
35
37
|
|
36
38
|
# Update progress before
|
37
39
|
#yield 0, target.name
|
38
|
-
|
39
|
-
# Do the transfer
|
40
|
+
# Point to the right bucket and object
|
40
41
|
bucket = @client.bucket(target.aws_bucket)
|
41
42
|
object = bucket.object(target.name)
|
42
|
-
|
43
|
-
|
43
|
+
|
44
|
+
# Do the transfer
|
45
|
+
object.upload_file(source.path, {
|
46
|
+
multipart_threshold: @multipart_threshold
|
47
|
+
})
|
48
|
+
|
49
|
+
# Wait for transfer to complete
|
50
|
+
object.wait_until_exists do |waiter|
|
51
|
+
# waiter.delay = 1
|
52
|
+
# # log_debug "- progress[#{progress}] total[#{total}]"
|
53
|
+
# waiter.before_wait do |attempts, response|
|
54
|
+
# puts "#{attempts} made"
|
55
|
+
# puts response.error.inspect
|
56
|
+
# puts response.data.inspect
|
57
|
+
# end
|
58
|
+
# log_debug "- progress[] #{waiter.inspect}"
|
44
59
|
end
|
45
60
|
|
46
61
|
# Update progress after
|
@@ -49,8 +64,8 @@ module RestFtpDaemon
|
|
49
64
|
# Dump information about this file
|
50
65
|
log_debug "RemoteS3.upload url[#{object.public_url}]"
|
51
66
|
log_debug "RemoteS3.upload etag[#{object.etag}]"
|
52
|
-
set_info :
|
53
|
-
set_info :
|
67
|
+
set_info :target_aws_public_url, object.public_url
|
68
|
+
set_info :target_aws_etag, object.etag
|
54
69
|
end
|
55
70
|
|
56
71
|
def connected?
|
data/lib/rest-ftp-daemon/uri.rb
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
module URI
|
2
2
|
|
3
|
+
class FILE < Generic
|
4
|
+
end
|
5
|
+
|
6
|
+
class S3 < Generic
|
7
|
+
end
|
8
|
+
|
3
9
|
class FTPS < Generic
|
4
10
|
DEFAULT_PORT = 21
|
5
11
|
end
|
@@ -12,12 +18,6 @@ module URI
|
|
12
18
|
DEFAULT_PORT = 22
|
13
19
|
end
|
14
20
|
|
15
|
-
class S3 < Generic
|
16
|
-
end
|
17
|
-
|
18
|
-
class FILE < Generic
|
19
|
-
DEFAULT_PORT = 22
|
20
|
-
end
|
21
21
|
|
22
22
|
@@schemes["FTPS"] = FTPS
|
23
23
|
@@schemes["FTPES"] = FTPES
|
@@ -1,12 +1,14 @@
|
|
1
1
|
-# coding: utf-8
|
2
2
|
- jobs.each do |job|
|
3
|
-
- work_progress = job.get_info(
|
4
|
-
-
|
5
|
-
-
|
3
|
+
- work_progress = job.get_info(INFO_PROGRESS)
|
4
|
+
- error_message = job.get_info(:error_message)
|
5
|
+
- transfer_total = job.get_info(:transfer_total)
|
6
|
+
- transfer_bitrate = job.get_info(:transfer_bitrate)
|
7
|
+
- work_sent = job.get_info(:work_sent)
|
6
8
|
|
7
|
-
- source_count = job.get_info(:
|
8
|
-
- source_processed = job.get_info(:
|
9
|
-
- source_current = job.get_info(:
|
9
|
+
- source_count = job.get_info(:source_count) || 0
|
10
|
+
- source_processed = job.get_info(:source_processed) || 0
|
11
|
+
- source_current = job.get_info(:source_current)
|
10
12
|
|
11
13
|
- job_working = [JOB_STATUS_UPLOADING, JOB_STATUS_TRANSFORMING].include? job.status
|
12
14
|
|
@@ -59,16 +61,16 @@
|
|
59
61
|
= "#{work_progress} %"
|
60
62
|
|
61
63
|
- else
|
62
|
-
.error{title:
|
64
|
+
.error{title: error_message}
|
63
65
|
= text_or_empty(job.error)
|
64
66
|
|
65
67
|
%td.nobr.text-right
|
66
|
-
= format_bytes(
|
68
|
+
= format_bytes(transfer_total, "B")
|
67
69
|
|
68
70
|
%td.nobr.text-right{title: "time: #{job.exectime} s"}
|
69
|
-
- if
|
71
|
+
- if transfer_bitrate
|
70
72
|
%span.push-bitrate
|
71
|
-
= format_bytes(
|
73
|
+
= format_bytes(transfer_bitrate, "bps")
|
72
74
|
|
73
75
|
%td
|
74
76
|
- unless job.wid.nil?
|
data/lib/rest-ftp-daemon.rb
CHANGED
@@ -50,6 +50,7 @@ require_relative "rest-ftp-daemon/workers/reporter"
|
|
50
50
|
require_relative "rest-ftp-daemon/workers/transfer"
|
51
51
|
|
52
52
|
# API
|
53
|
+
require_relative "rest-ftp-daemon/api/entities/location"
|
53
54
|
require_relative "rest-ftp-daemon/api/entities/options"
|
54
55
|
require_relative "rest-ftp-daemon/api/entities/job"
|
55
56
|
require_relative "rest-ftp-daemon/api/jobs"
|
data/rest-ftp-daemon.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rest-ftp-daemon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.423.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bruno MEDICI
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-09-
|
11
|
+
date: 2016-09-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -413,6 +413,7 @@ files:
|
|
413
413
|
- lib/rest-ftp-daemon/api/dashboard.rb
|
414
414
|
- lib/rest-ftp-daemon/api/debug.rb
|
415
415
|
- lib/rest-ftp-daemon/api/entities/job.rb
|
416
|
+
- lib/rest-ftp-daemon/api/entities/location.rb
|
416
417
|
- lib/rest-ftp-daemon/api/entities/options.rb
|
417
418
|
- lib/rest-ftp-daemon/api/jobs.rb
|
418
419
|
- lib/rest-ftp-daemon/api/root-real.rb
|