rest-ftp-daemon 0.300.3 → 0.302.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.
@@ -1,3 +1,5 @@
1
+ require "grape"
2
+
1
3
  module RestFtpDaemon
2
4
  module API
3
5
  class Jobs < Grape::API
@@ -1,3 +1,5 @@
1
+ require "grape"
2
+
1
3
  module RestFtpDaemon
2
4
  module API
3
5
  class Root < Grape::API
@@ -1,3 +1,4 @@
1
+ require "grape"
1
2
  require "get_process_mem"
2
3
 
3
4
  module RestFtpDaemon
@@ -6,7 +6,7 @@ DEFAULT_POOL = "default"
6
6
  DEFAULT_SFTP_TIMEOUT = 600 # 10mn
7
7
  DEFAULT_FTP_CHUNK = 1024 # 1 MB
8
8
  DEFAULT_PAGE_SIZE = 50 # 50 lines
9
- DEFAULT_RETRY_DELAY = 10 # 10s
9
+ DEFAULT_RETRY_AFTER = 10 # 10s
10
10
 
11
11
 
12
12
  # Internal job constants
@@ -21,7 +21,7 @@ LOG_ROTATION = "daily"
21
21
  LOG_FORMAT_PROGNAME = "%d\t%s"
22
22
 
23
23
  LOG_HEADER_TIME = "%Y-%m-%d %H:%M:%S"
24
- LOG_HEADER_FORMAT = "%s \t%d\t%-8s %-15s "
24
+ LOG_HEADER_FORMAT = "%s \t%d\t%-8s %-10s "
25
25
  LOG_MESSAGE_TRIM = 200
26
26
  LOG_MESSAGE_TEXT = "%s%s"
27
27
  LOG_MESSAGE_ARRAY = "%s - %s"
@@ -29,9 +29,9 @@ LOG_MESSAGE_HASH = "%s * %-20s %s"
29
29
 
30
30
  # Constants: logger app-specific prefix
31
31
  LOG_PREFIX_WID = 8
32
- LOG_PREFIX_JID = JOB_IDENT_LEN + 3 + 2
33
- LOG_PREFIX_ID = 6
34
- LOG_PREFIX_FORMAT = "%#{-LOG_PREFIX_WID.to_i}s %#{-LOG_PREFIX_JID.to_i}s %#{-LOG_PREFIX_ID.to_i}s"
32
+ LOG_PREFIX_JID = JOB_IDENT_LEN + 4
33
+ LOG_PREFIX_ID = 5
34
+ LOG_PREFIX_FORMAT = "%#{-LOG_PREFIX_WID.to_i}s %#{-LOG_PREFIX_JID.to_i}s %#{-LOG_PREFIX_ID.to_i}s "
35
35
 
36
36
 
37
37
  # Constants: logger to be cleaned up
@@ -24,6 +24,8 @@ module RestFtpDaemon
24
24
  attr_reader :infos
25
25
  attr_reader :pool
26
26
 
27
+ attr_accessor :config
28
+
27
29
  FIELDS.each do |name|
28
30
  attr_reader name
29
31
  end
@@ -43,8 +45,13 @@ module RestFtpDaemon
43
45
  @runs = 0
44
46
  @wid = nil
45
47
 
48
+ # Prepare configuration
49
+ @config = Conf[:transfer] || {}
50
+ @endpoints = Conf[:endpoints] || {}
51
+ @pools = Conf[:pools] || {}
52
+
46
53
  # Logger
47
- @logger = RestFtpDaemon::LoggerPool.instance.get :jobs
54
+ @logger = RestFtpDaemon::LoggerPool.instance.get :transfer
48
55
 
49
56
  # Protect with a mutex
50
57
  @mutex = Mutex.new
@@ -54,34 +61,24 @@ module RestFtpDaemon
54
61
  instance_variable_set "@#{name}", params[name]
55
62
  end
56
63
 
57
- # Set pool
58
- pools = (Conf[:pools] || {})
59
64
  # Check if pool name exists
60
- if (pools.keys.include? params[:pool])
65
+ if (@pools.keys.include? params[:pool])
61
66
  @pool = params[:pool].to_s
62
67
  else
63
68
  @pool = DEFAULT_POOL
64
69
  end
65
70
 
66
71
  # Set job queue, thus reset
67
- reset
68
-
69
- # Read source file size and parameters
70
- @notify_after_sec = Conf.at(:transfer, :notify_after_sec) rescue nil
72
+ # reset
71
73
  end
72
74
 
73
75
  def reset
74
- # Set super-default flags
75
- flag_default :mkdir, false
76
- flag_default :overwrite, false
77
- flag_default :tempfile, false
78
-
79
76
  # Flag current job
80
77
  @queued_at = Time.now
81
78
  @updated_at = Time.now
82
79
 
83
80
  # Send first notification
84
- log_info "Job.initialize notify[queued] notify_after_sec[#{@notify_after_sec}] interval[#{JOB_UPDATE_INTERVAL}]"
81
+ log_info "Job.initialize notify[queued]}]"
85
82
  client_notify :queued
86
83
 
87
84
  # Update job status
@@ -91,8 +88,7 @@ module RestFtpDaemon
91
88
  end
92
89
 
93
90
  def process
94
- # Update job's status
95
- log_info "Job.process"
91
+ log_info "Job.process update_interval[#{JOB_UPDATE_INTERVAL}]"
96
92
 
97
93
  # Prepare job
98
94
  begin
@@ -259,10 +255,6 @@ module RestFtpDaemon
259
255
 
260
256
  protected
261
257
 
262
- def expand_path path
263
- File.expand_path replace_tokens(path)
264
- end
265
-
266
258
  def expand_url path
267
259
  URI.parse replace_tokens(path)
268
260
  end
@@ -273,8 +265,8 @@ module RestFtpDaemon
273
265
 
274
266
  def replace_tokens path
275
267
  # Ensure endpoints are not a nil value
276
- return path unless Conf[:endpoints].is_a? Enumerable
277
- vectors = Conf[:endpoints].clone
268
+ return path unless @endpoints.is_a? Enumerable
269
+ vectors = @endpoints.clone
278
270
 
279
271
  # Stack RANDOM into tokens
280
272
  vectors["RANDOM"] = SecureRandom.hex(JOB_RANDOM_LEN)
@@ -294,16 +286,21 @@ module RestFtpDaemon
294
286
  end
295
287
 
296
288
  def prepare
289
+ # Init
290
+ @source_path = nil
291
+
292
+ # Prepare flags
293
+ flag_prepare :mkdir, false
294
+ flag_prepare :overwrite, false
295
+ flag_prepare :tempfile, true
296
+
297
297
  # Update job status
298
298
  set_status JOB_STATUS_PREPARING
299
299
  @runs += 1
300
300
 
301
- # Init
302
- @source_path = nil
303
-
304
301
  # Prepare source
305
302
  raise RestFtpDaemon::JobMissingAttribute unless @source
306
- @source_path = expand_path @source
303
+ @source_path = File.expand_path replace_tokens(@source)
307
304
  set_info :source, :path, @source_path
308
305
  set_info :source, :method, JOB_METHOD_FILE
309
306
 
@@ -324,21 +321,21 @@ module RestFtpDaemon
324
321
  # set_info :target, :method, :ftp
325
322
  set_info :target, :method, JOB_METHOD_FTP
326
323
  #@target_method = :ftp
327
- @remote = RemoteFTP.new target_uri, log_prefix
324
+ @remote = RemoteFTP.new target_uri, log_prefix, debug: @config[:debug_ftp]
328
325
 
329
326
  elsif (target_uri.is_a? URI::FTPES) || (target_uri.is_a? URI::FTPS)
330
327
  log_info "Job.prepare target_method FTPES"
331
328
  # set_info :target, :method, :ftpes
332
329
  set_info :target, :method, JOB_METHOD_FTPS
333
330
  # @target_method = :ftpes
334
- @remote = RemoteFTP.new target_uri, log_prefix, ftpes: true
331
+ @remote = RemoteFTP.new target_uri, log_prefix, debug: @config[:debug_sftp], ftpes: true
335
332
 
336
333
  elsif target_uri.is_a? URI::SFTP
337
334
  log_info "Job.prepare target_method SFTP"
338
335
  # set_info :target, :method, :sftp
339
336
  set_info :target, :method, JOB_METHOD_SFTP
340
337
  # @target_method = :sftp
341
- @remote = RemoteSFTP.new target_uri, log_prefix
338
+ @remote = RemoteSFTP.new target_uri, log_prefix, debug: @config[:debug_sftp]
342
339
 
343
340
  else
344
341
  log_info "Job.prepare unknown scheme [#{target_uri.scheme}]"
@@ -460,15 +457,17 @@ module RestFtpDaemon
460
457
  touch_job
461
458
  end
462
459
 
463
- def flag_default name, default
460
+ def flag_prepare name, default
464
461
  # build the flag instance var name
465
462
  variable = "@#{name}"
466
463
 
467
- # If it's true or false, that's ok
468
- return if [true, false].include? instance_variable_get(variable)
464
+ [config[name], default].each do |alt_value|
465
+ # If it's already true or false, that's ok
466
+ return if [true, false].include? instance_variable_get(variable)
469
467
 
470
- # Otherwise, set it to the default value
471
- instance_variable_set variable, default
468
+ # Otherwise, set it to the new alt_value
469
+ instance_variable_set variable, alt_value
470
+ end
472
471
  end
473
472
 
474
473
  def finalize
@@ -539,6 +538,7 @@ module RestFtpDaemon
539
538
  def progress transferred, name = ""
540
539
  # What's current time ?
541
540
  now = Time.now
541
+ notify_after = @config[:notify_after]
542
542
 
543
543
  # Update counters
544
544
  @transfer_sent += transferred
@@ -561,7 +561,7 @@ module RestFtpDaemon
561
561
  stack << (Helpers.format_bytes @transfer_total, "B")
562
562
  stack << (Helpers.format_bytes @current_bitrate.round(0), "bps")
563
563
  stack2 = stack.map { |txt| ("%#{LOG_PIPE_LEN.to_i}s" % txt) }.join("\t")
564
- log_debug "Job.progress #{stack2} \t#{name}"
564
+ log_debug "progress #{stack2} \t#{name}"
565
565
 
566
566
  # Remember when we last did it
567
567
  @progress_at = now
@@ -569,13 +569,13 @@ module RestFtpDaemon
569
569
 
570
570
  # Notify if requested
571
571
  notified_ago = (now.to_f - @notified_at.to_f)
572
- if (!@notify_after_sec.nil?) && (notified_ago > @notify_after_sec)
572
+ if (!notify_after.nil?) && (notified_ago > notify_after)
573
573
  # Prepare and send notification
574
574
  notif_status = {
575
575
  progress: percent0,
576
576
  transfer_sent: @transfer_sent,
577
577
  transfer_total: @transfer_total,
578
- transfer_bitrate: @current_bitrate,
578
+ transfer_bitrate: @current_bitrate.round(0),
579
579
  }
580
580
  client_notify :progress, status: notif_status
581
581
 
@@ -1,37 +1,60 @@
1
1
  require "logger"
2
+ require "singleton"
2
3
 
4
+ # Logger interface class to access logger though symbolic names
3
5
  module RestFtpDaemon
4
-
5
- # Logger interface class to access logger though symbolic names
6
6
  class LoggerPool
7
7
  include Singleton
8
8
 
9
- def initialize
10
- @loggers = {}
11
- end
12
-
13
9
  def get pipe
10
+ @loggers ||= {}
14
11
  @loggers[pipe] ||= create(pipe)
15
12
  end
16
13
 
17
14
  def create pipe
18
- # Compute file path / STDERR
19
- logfile = Conf[:logs][pipe] if Conf[:logs].is_a? Hash
20
- logfile ||= STDERR
21
-
22
- # Check if we can write to than file
23
- unless File.writable?(logfile)
24
- puts "LoggerPool [#{pipe}] logging to hyperspace (cannot write to #{logfile})"
25
- logfile = nil
26
- end
15
+ # Compute logfile or STDERR, and declare what we're doing
16
+ filename = logfile(pipe)
27
17
 
28
18
  # Create the logger and return it
29
- logger = Logger.new(logfile, LOG_ROTATION) #, 10, 1024000)
19
+ logger = Logger.new(filename, LOG_ROTATION) #, 10, 1024000)
30
20
  logger.progname = pipe.to_s.downcase
31
21
  logger.formatter = Shared::LoggerFormatter
32
22
 
33
23
  # Finally return this logger
34
24
  logger
25
+
26
+ rescue Errno::EACCES
27
+ puts "LoggerPool [#{pipe}] failed: access error"
28
+ end
29
+
30
+ protected
31
+
32
+ def logfile pipe
33
+ # Disabled if no valid config
34
+ return nil unless Conf[:logs].is_a?(Hash)
35
+
36
+ # Compute logfile and check if we can write there
37
+ logfile = File.expand_path(Conf[:logs][pipe], Conf[:logs][:path])
38
+
39
+ # Check that we'll be able to create logfiles
40
+ if File.exists?(logfile)
41
+ # File is there, is it writable ?
42
+ unless File.writable?(logfile)
43
+ puts "LoggerPool [#{pipe}] disabled: file not writable [#{logfile}]"
44
+ return nil
45
+ end
46
+ else
47
+ # No file here, can we create it ?
48
+ logdir = File.dirname(logfile)
49
+ unless File.writable?(logdir)
50
+ puts "LoggerPool [#{pipe}] disabled: directory not writable [#{logdir}]"
51
+ return nil
52
+ end
53
+ end
54
+
55
+ # OK, return a clean file path
56
+ puts "LoggerPool [#{pipe}] logging to [#{logfile}]"
57
+ return logfile
35
58
  end
36
59
 
37
60
  end
@@ -1,3 +1,6 @@
1
+ require 'api_auth'
2
+ require 'rest_client'
3
+
1
4
  module RestFtpDaemon
2
5
 
3
6
  # Handles a notification POST using a dedicated thread
@@ -61,20 +64,24 @@ module RestFtpDaemon
61
64
 
62
65
  def send flags
63
66
  # Prepare query
64
- headers = {
65
- "Content-Type" => "application/json",
66
- "Accept" => "application/json",
67
- "User-Agent" => "#{Conf.app_name}/v#{Conf.app_ver}"
68
- }
69
- data = flags.to_json
70
-
71
- # Send notification through HTTP
72
67
  uri = URI @url
73
- http = Net::HTTP.new uri.host, uri.port
74
-
75
- # Post notification, handle server response / multi-lines
76
- log_info "sending #{data}"
77
- response = http.post uri.path, data, headers
68
+ # uri = URI(rule[:relay])
69
+ #http = Net::HTTP.new uri.host, uri.port
70
+
71
+ # Prepare request
72
+ request = RestClient::Request.new url: uri.to_s,
73
+ method: :post,
74
+ payload: JSON.pretty_generate(flags),
75
+ headers: {
76
+ content_type: :json,
77
+ accept: :json,
78
+ user_agent: Conf.generate(:user_agent),
79
+ }
80
+
81
+ # Execure request
82
+ log_info "posting #{flags.to_json}"
83
+ # response = http.post uri.path, data, headers
84
+ response = request.execute
78
85
 
79
86
  # Log reponse body
80
87
  response_lines = response.body.lines
@@ -86,14 +93,14 @@ module RestFtpDaemon
86
93
  end
87
94
 
88
95
  # Handle exceptions
89
- rescue Net::OpenTimeout => ex
90
- log_error "Net::OpenTimeout: #{ex.inspect}"
96
+ rescue Net::OpenTimeout => e
97
+ log_error "Net::OpenTimeout: #{e.message}"
91
98
 
92
- rescue SocketError => ex
93
- log_error "SocketError: #{ex.inspect}"
99
+ rescue SocketError => e
100
+ log_error "SocketError: #{e.message}"
94
101
 
95
- rescue StandardError => ex
96
- log_error "UNHANDLED EXCEPTION: #{ex.inspect}"
102
+ rescue StandardError => e
103
+ log_error "UNHANDLED EXCEPTION: #{e.message}", e.backtrace
97
104
  end
98
105
 
99
106
  def log_prefix
@@ -7,9 +7,12 @@ module RestFtpDaemon
7
7
  attr_reader :log_prefix
8
8
 
9
9
  def initialize url, log_prefix, options = {}
10
+ # Options
11
+ @debug = !!options[:debug]
12
+
10
13
  # Logger
11
14
  @log_prefix = log_prefix || {}
12
- @logger = RestFtpDaemon::LoggerPool.instance.get :jobs
15
+ @logger = RestFtpDaemon::LoggerPool.instance.get :transfer
13
16
 
14
17
  # Extract URL parts
15
18
  @url = url
@@ -21,12 +24,22 @@ module RestFtpDaemon
21
24
 
22
25
  def connect
23
26
  # Debug mode ?
24
- debug_header if @debug
27
+ return unless @debug
28
+ puts
29
+ puts "-------------------- SESSION STARTING -------------------------"
30
+ puts "class\t #{myname}"
31
+ puts "host\t #{@url.host}"
32
+ puts "user\t #{@url.user}"
33
+ puts "port\t #{@url.port}"
34
+ puts "options\t #{@options.inspect}"
35
+ puts "---------------------------------------------------------------"
36
+
25
37
  end
26
38
 
27
39
  def close
28
40
  # Debug mode ?
29
- puts "-------------------- SESSION CLOSING --------------------------" if @debug
41
+ return unless @debug
42
+ puts "-------------------- SESSION CLOSING --------------------------"
30
43
  end
31
44
 
32
45
  private
@@ -35,17 +48,5 @@ module RestFtpDaemon
35
48
  self.class.to_s
36
49
  end
37
50
 
38
- def debug_header
39
- # Output header to STDOUT
40
- puts
41
- puts "-------------------- SESSION STARTING -------------------------"
42
- puts "class\t #{myname}"
43
- puts "host\t #{@url.host}"
44
- puts "user\t #{@url.user}"
45
- puts "port\t #{@url.port}"
46
- puts "options\t #{@options.inspect}"
47
- puts "---------------------------------------------------------------"
48
- end
49
-
50
51
  end
51
52
  end
@@ -10,9 +10,6 @@ module RestFtpDaemon
10
10
  # Call super
11
11
  super
12
12
 
13
- # Use debug ?
14
- @debug = (Conf.at :debug, :ftp) == true
15
-
16
13
  # Create FTP object
17
14
  if options[:ftpes]
18
15
  prepare_ftpes
@@ -20,7 +17,7 @@ module RestFtpDaemon
20
17
  prepare_ftp
21
18
  end
22
19
  @ftp.passive = true
23
- @ftp.debug_mode = !!@debug
20
+ @ftp.debug_mode = @debug
24
21
 
25
22
  # Config
26
23
  @chunk_size = DEFAULT_FTP_CHUNK.to_i * 1024
@@ -30,10 +27,8 @@ module RestFtpDaemon
30
27
  end
31
28
 
32
29
  def connect
33
- # Connect init
34
- super
35
-
36
30
  # Connect remote server
31
+ super
37
32
  @ftp.connect @url.host, @url.port
38
33
  @ftp.login @url.user, @url.password
39
34
  end