rest-ftp-daemon 0.101 → 0.103.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b3c42331f0e483617809300fcc7b6623e94e617b
4
- data.tar.gz: 0184e556177357a18e19a686d3fc3ae852dcbffd
3
+ metadata.gz: c059a568b0a22503a734c966807a19c8ff426333
4
+ data.tar.gz: a3d2443af653af100e642e86ba7144a2b9985495
5
5
  SHA512:
6
- metadata.gz: ead761e0002d4cfda4409fd43dd1c5828040b204fadb2286898c31ccd428edc41be0dd3c83a334d4c0c35770c5bd77856c3665279b539ca3614460990e5b78c6
7
- data.tar.gz: 0518b79a4037e122c99d6ce50e660724f1db21693c0e5abfeeab319f6759dfce66461aaf7bc999500e967f833c67660fbadfa6a00f241be65c6b154099021ab7
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 RESTfull API.
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 do |field|
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
- optional :overwrite, type: Boolean, desc: "wether to overwrites files at target server",
67
- default: false
68
- optional :mkdir, type: Boolean, desc: "wether to create missing directories on target server",
69
- default: false
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.101"
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
 
@@ -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 |field|
26
- attr_reader field
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, :job_missing_attribute
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, :job_unresolved_tokens
85
+ return oops "rftpd.started", exception, :unresolved_tokens
84
86
 
85
87
  rescue RestFtpDaemon::JobTargetUnparseable => exception
86
- return oops "rftpd.started", exception, :job_target_unparseable
88
+ return oops "rftpd.started", exception, :target_unparseable
87
89
 
88
90
  rescue RestFtpDaemon::JobTargetUnsupported => exception
89
- return oops "rftpd.started", exception, :job_target_unsupported
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, :job_assertion_failed
97
+ return oops "rftpd.started", exception, :assertion_failed
93
98
 
94
99
  rescue RestFtpDaemon::RestFtpDaemonException => exception
95
- return oops "rftpd.started", exception, :job_prepare_failed
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, :job_prepare_unhandled, true
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, :job_host_is_down
122
+ return oops "rftpd.ended", exception, :conn_host_is_down
118
123
 
119
124
  rescue Errno::ENOTCONN => exception
120
- return oops "rftpd.ended", exception, :job_connexion_failed
125
+ return oops "rftpd.ended", exception, :conn_failed
121
126
 
122
127
  rescue Errno::ECONNREFUSED => exception
123
- return oops "rftpd.ended", exception, :job_connexion_refused
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, :job_timeout
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, :job_openssl_error
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, :job_too_many_open_files
140
+ return oops "rftpd.ended", exception, :too_many_open_files
139
141
 
140
142
  rescue RestFtpDaemon::JobSourceNotFound => exception
141
- return oops "rftpd.ended", exception, :job_source_not_found
143
+ return oops "rftpd.ended", exception, :source_not_found
142
144
 
143
145
  rescue RestFtpDaemon::JobTargetFileExists => exception
144
- return oops "rftpd.ended", exception, :job_target_file_exists
146
+ return oops "rftpd.ended", exception, :target_file_exists
145
147
 
146
148
  rescue RestFtpDaemon::JobTargetShouldBeDirectory => exception
147
- return oops "rftpd.ended", exception, :job_target_should_be_directory
149
+ return oops "rftpd.ended", exception, :target_not_directory
148
150
 
149
151
  rescue RestFtpDaemon::JobAssertionFailed => exception
150
- return oops "rftpd.started", exception, :job_assertion_failed
152
+ return oops "rftpd.started", exception, :assertion_failed
151
153
 
152
154
  rescue RestFtpDaemon::RestFtpDaemonException => exception
153
- return oops "rftpd.ended", exception, :job_transfer_failed
155
+ return oops "rftpd.ended", exception, :transfer_failed
154
156
 
155
157
  rescue Exception => exception
156
- return oops "rftpd.ended", exception, :job_transfer_unhandled, true
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, login and chdir
304
- ftp_connect_and_login
292
+ # Connect to remote server and login
293
+ ftp_connect
294
+ ftp_login
305
295
 
306
- # Connect remote server, login and chdir
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 ftp_connect_and_login
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.ftp_connect login [#{@target_url.user}]"
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, target_name, chunk_size) do |block|
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
@@ -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 RESTfull API"
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"]
@@ -11,6 +11,11 @@ defaults: &defaults
11
11
  update_every_kb: 1024
12
12
  notify_after_sec: 10
13
13
 
14
+ mkdir: true
15
+ tempfile: true
16
+ overwrite: false
17
+
18
+
14
19
  conchita:
15
20
  timer: 10
16
21
  #clean_failed: 3600
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.101'
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: 2014-12-24 00:00:00.000000000 Z
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 RESTfull
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: