rest-ftp-daemon 0.101 → 0.103.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/rest-ftp-daemon/api/job_presenter.rb +2 -5
- data/lib/rest-ftp-daemon/api/jobs.rb +8 -5
- data/lib/rest-ftp-daemon/constants.rb +2 -1
- data/lib/rest-ftp-daemon/job.rb +86 -69
- data/lib/rest-ftp-daemon/worker_pool.rb +2 -2
- data/rest-ftp-daemon.gemspec +1 -1
- data/rest-ftp-daemon.yml.sample +5 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c059a568b0a22503a734c966807a19c8ff426333
|
4
|
+
data.tar.gz: a3d2443af653af100e642e86ba7144a2b9985495
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 07afa716bc8b3b701377cfe1a9452e22238cc8e82af287f544e499cc2a4d263bd266e3d83f8a2aa53ca37381653d1fff961bdbff6bf9446167cf1276fb8bddf8
|
7
|
+
data.tar.gz: 31fb4ea27d1e64278563eb3e2e93375c24d1f9794e632acd7afbeb897dc0a6d88024fe2dd3c4393648fa151b1f54c35432323f45cd90b4f9d368feeb208078a1
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@ rest-ftp-daemon
|
|
2
2
|
====================================================================================
|
3
3
|
|
4
4
|
|
5
|
-
This is a pretty simple FTP client daemon, controlled through a
|
5
|
+
This is a pretty simple FTP client daemon, controlled through a RESTful API.
|
6
6
|
|
7
7
|
API documentation is [maintained on Apiary](http://docs.restftpdaemon.apiary.io/)
|
8
8
|
|
@@ -6,11 +6,8 @@ module RestFtpDaemon
|
|
6
6
|
# Job ID
|
7
7
|
expose :id
|
8
8
|
|
9
|
-
# Job specific attributes
|
10
|
-
Job::FIELDS.each
|
11
|
-
expose field
|
12
|
-
#expose field, unless: lambda { |object, options| object.instance_variable_get("@#{field}").nil? }
|
13
|
-
end
|
9
|
+
# Job specific attributes and flags
|
10
|
+
Job::FIELDS.each { |name| expose name }
|
14
11
|
|
15
12
|
# Technical fields
|
16
13
|
expose :wid, unless: lambda { |object, options| object.wid.nil? }
|
@@ -63,10 +63,13 @@ module RestFtpDaemon
|
|
63
63
|
optional :label, type: String, desc: "Descriptive label for this job"
|
64
64
|
optional :notify, type: String, desc: "URL to get POST'ed notifications back"
|
65
65
|
optional :priority, type: Integer, desc: "Priority level of the job (lower is stronger)"
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
66
|
+
|
67
|
+
optional :overwrite, type: Boolean, desc: "overwrites files at target server",
|
68
|
+
default: Settings.transfer[:overwrite]
|
69
|
+
optional :mkdir, type: Boolean, desc: "create missing directories on target server",
|
70
|
+
default: Settings.transfer[:mkdir]
|
71
|
+
optional :tempfile, type: Boolean, desc: "upload to a temp file before renaming it to the target filename",
|
72
|
+
default: Settings.transfer[:tempfile]
|
70
73
|
end
|
71
74
|
|
72
75
|
post '/jobs/' do
|
@@ -95,7 +98,7 @@ module RestFtpDaemon
|
|
95
98
|
api_error exception
|
96
99
|
else
|
97
100
|
status 201
|
98
|
-
present job, :with => RestFtpDaemon::API::Entities::JobPresenter
|
101
|
+
present job, :with => RestFtpDaemon::API::Entities::JobPresenter, hide_params: true
|
99
102
|
end
|
100
103
|
end
|
101
104
|
|
@@ -1,11 +1,12 @@
|
|
1
1
|
# Terrific constants
|
2
2
|
APP_NAME = "rest-ftp-daemon"
|
3
|
-
APP_VER = "0.
|
3
|
+
APP_VER = "0.103.1"
|
4
4
|
|
5
5
|
# Some global constants
|
6
6
|
IDENT_JOB_LEN = 4
|
7
7
|
IDENT_NOTIF_LEN = 4
|
8
8
|
IDENT_RANDOM_LEN = 8
|
9
|
+
IDENT_TEMPFILE_LEN = 8
|
9
10
|
DEFAULT_LOGS_PIPE_LEN = 15
|
10
11
|
DEFAULT_LOGS_ID_LEN = 8
|
11
12
|
|
data/lib/rest-ftp-daemon/job.rb
CHANGED
@@ -6,35 +6,32 @@ require 'timeout'
|
|
6
6
|
module RestFtpDaemon
|
7
7
|
class Job
|
8
8
|
|
9
|
-
FIELDS = [:source, :target, :label, :priority, :notify, :overwrite, :mkdir]
|
9
|
+
FIELDS = [:source, :target, :label, :priority, :notify, :overwrite, :mkdir, :tempfile]
|
10
10
|
|
11
|
-
attr_reader :id
|
12
11
|
attr_accessor :wid
|
13
12
|
|
13
|
+
attr_reader :id
|
14
14
|
attr_reader :error
|
15
15
|
attr_reader :status
|
16
16
|
|
17
17
|
attr_reader :queued_at
|
18
18
|
attr_reader :updated_at
|
19
|
-
|
20
19
|
attr_reader :started_at
|
21
20
|
attr_reader :finished_at
|
22
21
|
|
23
22
|
attr_reader :params
|
24
23
|
|
25
|
-
FIELDS.each do |
|
26
|
-
attr_reader
|
24
|
+
FIELDS.each do |name|
|
25
|
+
attr_reader name
|
27
26
|
end
|
28
27
|
|
28
|
+
|
29
29
|
def initialize job_id, params={}
|
30
30
|
# Call super
|
31
31
|
# super()
|
32
32
|
|
33
33
|
# Init context
|
34
34
|
@id = job_id.to_s
|
35
|
-
FIELDS.each do |field|
|
36
|
-
instance_variable_set("@#{field.to_s}", params[field])
|
37
|
-
end
|
38
35
|
@params = {}
|
39
36
|
@updated_at = nil
|
40
37
|
@started_at = nil
|
@@ -44,25 +41,30 @@ module RestFtpDaemon
|
|
44
41
|
@wid = nil
|
45
42
|
|
46
43
|
# Logger
|
47
|
-
# @logger = RestFtpDaemon::Logger.new(:workers, "JOB #{id}")
|
48
44
|
@logger = RestFtpDaemon::LoggerPool.instance.get :workers
|
49
45
|
|
50
46
|
# Protect with a mutex
|
51
47
|
@mutex = Mutex.new
|
52
48
|
|
49
|
+
# Import query params
|
50
|
+
FIELDS.each do |name|
|
51
|
+
instance_variable_set "@#{name.to_s}", params[name]
|
52
|
+
end
|
53
|
+
|
54
|
+
# Set super-default flags
|
55
|
+
flag_default :mkdir, false
|
56
|
+
flag_default :overwrite, false
|
57
|
+
flag_default :tempfile, false
|
58
|
+
|
53
59
|
# Flag current job
|
54
60
|
@queued_at = Time.now
|
55
61
|
@status = :created
|
56
62
|
|
57
63
|
# Send first notification
|
58
|
-
#info "Job.initialize/notify"
|
59
64
|
info "Job.initialized"
|
60
65
|
client_notify "rftpd.queued"
|
61
66
|
end
|
62
67
|
|
63
|
-
def close
|
64
|
-
end
|
65
|
-
|
66
68
|
def process
|
67
69
|
# Update job's status
|
68
70
|
@error = nil
|
@@ -74,31 +76,31 @@ module RestFtpDaemon
|
|
74
76
|
prepare
|
75
77
|
|
76
78
|
rescue RestFtpDaemon::JobMissingAttribute => exception
|
77
|
-
return oops "rftpd.started", exception, :
|
79
|
+
return oops "rftpd.started", exception, :missing_attribute
|
78
80
|
|
79
81
|
# rescue RestFtpDaemon::JobSourceNotFound => exception
|
80
82
|
# return oops "rftpd.started", exception, :job_source_not_found
|
81
83
|
|
82
84
|
rescue RestFtpDaemon::JobUnresolvedTokens => exception
|
83
|
-
return oops "rftpd.started", exception, :
|
85
|
+
return oops "rftpd.started", exception, :unresolved_tokens
|
84
86
|
|
85
87
|
rescue RestFtpDaemon::JobTargetUnparseable => exception
|
86
|
-
return oops "rftpd.started", exception, :
|
88
|
+
return oops "rftpd.started", exception, :target_unparseable
|
87
89
|
|
88
90
|
rescue RestFtpDaemon::JobTargetUnsupported => exception
|
89
|
-
return oops "rftpd.started", exception, :
|
91
|
+
return oops "rftpd.started", exception, :target_unsupported
|
92
|
+
|
93
|
+
rescue URI::InvalidURIError => exception
|
94
|
+
return oops "rftpd.started", exception, :target_invalid
|
90
95
|
|
91
96
|
rescue RestFtpDaemon::JobAssertionFailed => exception
|
92
|
-
return oops "rftpd.started", exception, :
|
97
|
+
return oops "rftpd.started", exception, :assertion_failed
|
93
98
|
|
94
99
|
rescue RestFtpDaemon::RestFtpDaemonException => exception
|
95
|
-
return oops "rftpd.started", exception, :
|
96
|
-
|
97
|
-
rescue URI::InvalidURIError => exception
|
98
|
-
return oops "rftpd.started", exception, :job_target_invalid
|
100
|
+
return oops "rftpd.started", exception, :prepare_failed
|
99
101
|
|
100
102
|
rescue Exception => exception
|
101
|
-
return oops "rftpd.started", exception, :
|
103
|
+
return oops "rftpd.started", exception, :prepare_unhandled, true
|
102
104
|
|
103
105
|
else
|
104
106
|
# Prepare done !
|
@@ -113,47 +115,47 @@ module RestFtpDaemon
|
|
113
115
|
@status = :starting
|
114
116
|
transfer
|
115
117
|
|
118
|
+
rescue SocketError => exception
|
119
|
+
return oops "rftpd.ended", exception, :conn_socket_error
|
120
|
+
|
116
121
|
rescue Errno::EHOSTDOWN => exception
|
117
|
-
return oops "rftpd.ended", exception, :
|
122
|
+
return oops "rftpd.ended", exception, :conn_host_is_down
|
118
123
|
|
119
124
|
rescue Errno::ENOTCONN => exception
|
120
|
-
return oops "rftpd.ended", exception, :
|
125
|
+
return oops "rftpd.ended", exception, :conn_failed
|
121
126
|
|
122
127
|
rescue Errno::ECONNREFUSED => exception
|
123
|
-
return oops "rftpd.ended", exception, :
|
124
|
-
|
125
|
-
rescue SocketError => exception
|
126
|
-
return oops "rftpd.ended", exception, :job_socket_error
|
128
|
+
return oops "rftpd.ended", exception, :conn_refused
|
127
129
|
|
128
130
|
rescue Timeout::Error, Errno::ETIMEDOUT => exception
|
129
|
-
return oops "rftpd.ended", exception, :
|
130
|
-
|
131
|
-
rescue Net::FTPPermError => exception
|
132
|
-
return oops "rftpd.ended", exception, :job_perm_error
|
131
|
+
return oops "rftpd.ended", exception, :conn_timeout
|
133
132
|
|
134
133
|
rescue OpenSSL::SSL::SSLError => exception
|
135
|
-
return oops "rftpd.ended", exception, :
|
134
|
+
return oops "rftpd.ended", exception, :conn_openssl_error
|
135
|
+
|
136
|
+
rescue Net::FTPPermError => exception
|
137
|
+
return oops "rftpd.ended", exception, :perm_error
|
136
138
|
|
137
139
|
rescue Errno::EMFILE => exception
|
138
|
-
return oops "rftpd.ended", exception, :
|
140
|
+
return oops "rftpd.ended", exception, :too_many_open_files
|
139
141
|
|
140
142
|
rescue RestFtpDaemon::JobSourceNotFound => exception
|
141
|
-
return oops "rftpd.ended", exception, :
|
143
|
+
return oops "rftpd.ended", exception, :source_not_found
|
142
144
|
|
143
145
|
rescue RestFtpDaemon::JobTargetFileExists => exception
|
144
|
-
return oops "rftpd.ended", exception, :
|
146
|
+
return oops "rftpd.ended", exception, :target_file_exists
|
145
147
|
|
146
148
|
rescue RestFtpDaemon::JobTargetShouldBeDirectory => exception
|
147
|
-
return oops "rftpd.ended", exception, :
|
149
|
+
return oops "rftpd.ended", exception, :target_not_directory
|
148
150
|
|
149
151
|
rescue RestFtpDaemon::JobAssertionFailed => exception
|
150
|
-
return oops "rftpd.started", exception, :
|
152
|
+
return oops "rftpd.started", exception, :assertion_failed
|
151
153
|
|
152
154
|
rescue RestFtpDaemon::RestFtpDaemonException => exception
|
153
|
-
return oops "rftpd.ended", exception, :
|
155
|
+
return oops "rftpd.ended", exception, :transfer_failed
|
154
156
|
|
155
157
|
rescue Exception => exception
|
156
|
-
return oops "rftpd.ended", exception, :
|
158
|
+
return oops "rftpd.ended", exception, :transfer_unhandled, true
|
157
159
|
|
158
160
|
else
|
159
161
|
# All done !
|
@@ -187,19 +189,6 @@ module RestFtpDaemon
|
|
187
189
|
(@finished_at - @started_at).round(2)
|
188
190
|
end
|
189
191
|
|
190
|
-
def wander time
|
191
|
-
info "Job.wander #{time}"
|
192
|
-
@wander_for = time
|
193
|
-
@wander_started = Time.now
|
194
|
-
sleep time
|
195
|
-
info "Job.wandered ok"
|
196
|
-
end
|
197
|
-
|
198
|
-
def wandering_time
|
199
|
-
return if @wander_started.nil? || @wander_for.nil?
|
200
|
-
@wander_for.to_f - (Time.now - @wander_started)
|
201
|
-
end
|
202
|
-
|
203
192
|
def set attribute, value
|
204
193
|
@mutex.synchronize do
|
205
194
|
@params || {}
|
@@ -300,10 +289,11 @@ module RestFtpDaemon
|
|
300
289
|
# Scheme-aware config
|
301
290
|
ftp_init
|
302
291
|
|
303
|
-
# Connect remote server
|
304
|
-
|
292
|
+
# Connect to remote server and login
|
293
|
+
ftp_connect
|
294
|
+
ftp_login
|
305
295
|
|
306
|
-
#
|
296
|
+
# Change to the right path
|
307
297
|
path = Helpers.extract_dirname(@target_url.path).to_s
|
308
298
|
ftp_chdir_or_buildpath path
|
309
299
|
|
@@ -344,10 +334,10 @@ module RestFtpDaemon
|
|
344
334
|
def oops signal_name, exception, error_name = nil, include_backtrace = false
|
345
335
|
# Log this error
|
346
336
|
error_name = exception.class if error_name.nil?
|
347
|
-
info "Job.oops si[#{signal_name}] er[#{error_name.to_s}] ex[#{exception.class}]"
|
337
|
+
info "Job.oops si[#{signal_name}] er[#{error_name.to_s}] ex[#{exception.class}] #{exception.message}"
|
348
338
|
|
349
339
|
# Close ftp connexion if open
|
350
|
-
@ftp.close unless @ftp.nil?
|
340
|
+
@ftp.close unless @ftp.welcome.nil?
|
351
341
|
|
352
342
|
# Update job's internal status
|
353
343
|
@status = :failed
|
@@ -374,6 +364,17 @@ module RestFtpDaemon
|
|
374
364
|
client_notify signal_name, error_name, notif_status
|
375
365
|
end
|
376
366
|
|
367
|
+
def flag_default name, default
|
368
|
+
# build the flag instance var name
|
369
|
+
variable = "@#{name.to_s}"
|
370
|
+
|
371
|
+
# If it's true or false, that's ok
|
372
|
+
return if [true, false].include? instance_variable_get(variable)
|
373
|
+
|
374
|
+
# Otherwise, set it to the default value
|
375
|
+
instance_variable_set variable, default
|
376
|
+
end
|
377
|
+
|
377
378
|
def ftp_init
|
378
379
|
# Method assertions
|
379
380
|
info "Job.ftp_init asserts"
|
@@ -398,19 +399,20 @@ module RestFtpDaemon
|
|
398
399
|
@ftp.passive = true
|
399
400
|
end
|
400
401
|
|
401
|
-
def
|
402
|
-
#@status = :ftp_connect
|
403
|
-
# connect_timeout_sec = (Settings.transfer.connect_timeout_sec rescue nil) || DEFAULT_CONNECT_TIMEOUT_SEC
|
404
|
-
|
405
|
-
# Method assertions
|
406
|
-
host = @target_url.host
|
407
|
-
info "Job.ftp_connect connect [#{host}]"
|
402
|
+
def ftp_connect
|
408
403
|
@status = :ftp_connect
|
404
|
+
host = @target_url.host
|
405
|
+
info "Job.ftp_connect [#{host}]"
|
409
406
|
raise RestFtpDaemon::JobAssertionFailed if @ftp.nil? || @target_url.nil?
|
407
|
+
|
410
408
|
@ftp.connect(host)
|
409
|
+
end
|
411
410
|
|
411
|
+
def ftp_login
|
412
412
|
@status = :ftp_login
|
413
|
-
info "Job.
|
413
|
+
info "Job.ftp_login [#{@target_url.user}]"
|
414
|
+
raise RestFtpDaemon::JobAssertionFailed if @ftp.nil? || @target_url.user.nil? || @target_url.password.nil?
|
415
|
+
|
414
416
|
@ftp.login @target_url.user, @target_url.password
|
415
417
|
end
|
416
418
|
|
@@ -504,7 +506,6 @@ module RestFtpDaemon
|
|
504
506
|
else
|
505
507
|
# won't overwrite then stop here
|
506
508
|
info "Job.ftp_transfer failed: target file exists"
|
507
|
-
@ftp.close
|
508
509
|
raise RestFtpDaemon::JobTargetFileExists
|
509
510
|
end
|
510
511
|
end
|
@@ -513,12 +514,19 @@ module RestFtpDaemon
|
|
513
514
|
update_every_kb = (Settings.transfer.update_every_kb rescue nil) || DEFAULT_UPDATE_EVERY_KB
|
514
515
|
notify_after_sec = Settings.transfer.notify_after_sec rescue nil
|
515
516
|
|
517
|
+
# Compute temp target name
|
518
|
+
target_real = target_name
|
519
|
+
if @tempfile
|
520
|
+
target_real = "#{target_name}.#{Helpers.identifier(IDENT_TEMPFILE_LEN)}-temp"
|
521
|
+
info "Job.ftp_transfer target_real [#{target_real}]"
|
522
|
+
end
|
523
|
+
|
516
524
|
# Start transfer
|
517
525
|
chunk_size = update_every_kb * 1024
|
518
526
|
t0 = tstart = Time.now
|
519
527
|
notified_at = Time.now
|
520
528
|
@status = :uploading
|
521
|
-
@ftp.putbinaryfile(source_match,
|
529
|
+
@ftp.putbinaryfile(source_match, target_real, chunk_size) do |block|
|
522
530
|
# Update counters
|
523
531
|
@transfer_sent += block.bytesize
|
524
532
|
set :transfer_sent, @transfer_sent
|
@@ -544,6 +552,8 @@ module RestFtpDaemon
|
|
544
552
|
t0 = Time.now
|
545
553
|
|
546
554
|
# Notify if requested
|
555
|
+
@status = :uploaded
|
556
|
+
info "Job.ftp_transfer uploaded"
|
547
557
|
unless notify_after_sec.nil? || (notified_at + notify_after_sec > Time.now)
|
548
558
|
notif_status = {
|
549
559
|
progress: percent1,
|
@@ -557,6 +567,13 @@ module RestFtpDaemon
|
|
557
567
|
|
558
568
|
end
|
559
569
|
|
570
|
+
# Rename temp file to target_temp
|
571
|
+
if @tempfile
|
572
|
+
@status = :renaming
|
573
|
+
info "Job.ftp_transfer renaming to #{target_name}"
|
574
|
+
@ftp.rename target_real, target_name
|
575
|
+
end
|
576
|
+
|
560
577
|
# Compute final bitrate
|
561
578
|
set :transfer_bitrate, get_bitrate(@transfer_total, tstart).round(0)
|
562
579
|
|
@@ -39,14 +39,14 @@ module RestFtpDaemon
|
|
39
39
|
# Wait for a job to come into the queue
|
40
40
|
worker_status wid, :waiting
|
41
41
|
job = $queue.pop
|
42
|
-
info "worker [#{wid}] popped [#{job.id}]"
|
43
42
|
|
44
43
|
# Do the job
|
44
|
+
info "worker [#{wid}] processing [#{job.id}]"
|
45
45
|
worker_status wid, :processing, job.id
|
46
46
|
job.wid = wid
|
47
47
|
job.process
|
48
48
|
info "worker [#{wid}] processed [#{job.id}]"
|
49
|
-
job.close
|
49
|
+
# job.close
|
50
50
|
worker_status wid, :done
|
51
51
|
|
52
52
|
# Increment total processed jobs count
|
data/rest-ftp-daemon.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.date = Time.now.strftime("%Y-%m-%d")
|
11
11
|
spec.authors = ["Bruno MEDICI"]
|
12
12
|
spec.email = "rest-ftp-daemon@bmconseil.com"
|
13
|
-
spec.description = "This is a pretty simple FTP client daemon, controlled through a
|
13
|
+
spec.description = "This is a pretty simple FTP client daemon, controlled through a RESTful API"
|
14
14
|
spec.summary = "RESTful FTP client daemon"
|
15
15
|
spec.homepage = "http://github.com/bmedici/rest-ftp-daemon"
|
16
16
|
spec.licenses = ["MIT"]
|
data/rest-ftp-daemon.yml.sample
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:
|
4
|
+
version: 0.103.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bruno MEDICI
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-02-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -178,7 +178,7 @@ dependencies:
|
|
178
178
|
- - ">="
|
179
179
|
- !ruby/object:Gem::Version
|
180
180
|
version: '0'
|
181
|
-
description: This is a pretty simple FTP client daemon, controlled through a
|
181
|
+
description: This is a pretty simple FTP client daemon, controlled through a RESTful
|
182
182
|
API
|
183
183
|
email: rest-ftp-daemon@bmconseil.com
|
184
184
|
executables:
|