rest-ftp-daemon 0.422.0 → 0.423.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|