cantemo-portal-agent 1.0.9 → 1.1.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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/exe/cantemo-portal-agent +8 -6
  3. data/lib/cantemo/portal/agent/WatchFolderUtility/foreman.rb +59 -0
  4. data/lib/cantemo/portal/agent/cli/commands/watch_folders-working.rb +237 -0
  5. data/lib/cantemo/portal/agent/cli/commands/watch_folders.rb +63 -0
  6. data/lib/cantemo/portal/agent/version.rb +1 -1
  7. data/lib/envoi/aspera/watch_service/client.rb +397 -0
  8. data/lib/envoi/aspera/watch_service/snapshot.rb +11 -0
  9. data/lib/envoi/aspera/watch_service/subscription.rb +0 -0
  10. data/lib/envoi/aspera/watch_service/watch_folder.rb +322 -0
  11. data/lib/envoi/mam/agent/cli/commands/cantemo-agent.rb +62 -0
  12. data/lib/envoi/mam/agent/cli/commands/cantemo-watch_folders.rb +41 -0
  13. data/lib/envoi/mam/agent/cli/commands/cantemo.rb +5 -0
  14. data/lib/envoi/mam/agent/cli/commands/iconik.rb +21 -11
  15. data/lib/envoi/mam/agent/cli/commands/mediasilo.rb +1 -1
  16. data/lib/envoi/mam/agent/cli/commands/vidispine.rb +7 -4
  17. data/lib/envoi/mam/agent/cli/commands/wiredrive.rb +15 -2
  18. data/lib/envoi/mam/agent/cli/commands.rb +4 -4
  19. data/lib/envoi/mam/agent/cli.rb +3 -3
  20. data/lib/envoi/mam/agent/transfer_client/aspera.rb +145 -7
  21. data/lib/envoi/mam/agent/version.rb +1 -1
  22. data/lib/envoi/mam/agent/watch_folder_utility/foreman.rb +76 -0
  23. data/lib/envoi/mam/agent.rb +6 -1
  24. data/lib/envoi/mam/cantemo/agent/watch_folder_handler-working.rb +111 -0
  25. data/lib/envoi/mam/cantemo/agent/watch_folder_handler.rb +176 -0
  26. data/lib/envoi/mam/cantemo/agent/watch_folder_handler_aspera.rb +112 -0
  27. data/lib/envoi/mam/cantemo/agent.rb +288 -0
  28. data/lib/envoi/mam/iconik/agent.rb +15 -3
  29. data/lib/envoi/mam/vidispine/agent.rb +6 -1
  30. data/lib/envoi/watch_folder_utility/watch_folder/handler/listen.rb +189 -0
  31. metadata +48 -4
@@ -1,4 +1,59 @@
1
1
  require 'envoi/mam/agent/transfer_client'
2
+ require 'asperalm/fasp/local'
3
+
4
+
5
+
6
+ module Asperalm
7
+ module Fasp
8
+ module InstallationExtensions
9
+
10
+ PRODUCTS = {
11
+ unix: {
12
+ :aspera_cli_local => {
13
+ :expected=>'Aspera CLI',
14
+ :exe_ext=>'',
15
+ :app_root=>File.join(Dir.home,'.aspera','cli'),
16
+ :run_root=>File.join(Dir.home,'.aspera','cli'),
17
+ :sub_bin=>'bin',
18
+ :sub_keys=>'etc',
19
+ :dsa=>'asperaweb_id_dsa.openssh'
20
+ }
21
+ }
22
+ }
23
+
24
+ def find_missing_products(os_type, common_places)
25
+ missing_products = []
26
+ case os_type
27
+ when :unix
28
+ extended_products = PRODUCTS[os_type] || { }
29
+ extended_products.each do |product_name, product|
30
+ product_found = common_places.find do |cp|
31
+ cp[:expected] == product[:expected] && cp[:app_root] == product[:app_root]
32
+ end
33
+ missing_products.push product unless product_found
34
+ end
35
+ end
36
+ missing_products
37
+ end
38
+
39
+ def add_missing_products(os_type, common_places)
40
+ missing_products = find_missing_products(os_type, common_places)
41
+ common_places.concat missing_products unless missing_products.empty?
42
+ end
43
+
44
+ def product_locations
45
+ common_places = super
46
+ add_missing_products(OpenApplication.current_os_type, common_places)
47
+ common_places
48
+ end
49
+
50
+ end
51
+
52
+ class Installation
53
+ include InstallationExtensions
54
+ end
55
+ end
56
+ end
2
57
 
3
58
  module Envoi
4
59
  module Mam
@@ -32,10 +87,68 @@ module Envoi
32
87
  File.executable?(@ascp_path)
33
88
  end
34
89
 
90
+ def build_asperala_transfer_args(config, mode, source_path, target_path)
91
+
92
+ aspera_host_address = config['host_address'] || config['host']
93
+ aspera_username = config['username']
94
+ aspera_password = config['password']
95
+ aspera_ssh_port = config['ssh_port']
96
+
97
+ aspera_url = config['url'] || config['uri']
98
+ if aspera_url
99
+ aspera_uri = URI(aspera_url)
100
+ aspera_host_address ||= aspera_uri.host if aspera_uri
101
+ un, pw = (aspera_uri.userinfo || '').split(':')
102
+ aspera_username ||= un if un
103
+ aspera_password ||= pw if pw
104
+ aspera_ssh_port = aspera_uri.port
105
+ end
106
+
107
+ aspera_token = config['aspera_transfer_token'] || config['aspera_token'] || config['token'] || config['transfer_token']
108
+
109
+ # @ascp_path = config['ascp_path'] || default_ascp_path
110
+ # @ascp_path = File.expand_path(@ascp_path)
111
+ # aspera_ascp_path = @ascp_path
112
+
113
+ env_vars = { }
114
+ env_vars['ASPERA_SCP_PASS'] = aspera_password if aspera_password
115
+
116
+ ascp_args = config['ascp_args'] || default_ascp_args || agent.default_ascp_args
117
+
118
+ tags = config['tags'] || { }
119
+ aspera_tags = tags['aspera'] || { }
120
+ aspera_tags['xfer_id'] ||= SecureRandom.uuid
121
+
122
+ cmdline_args = [
123
+ '--mode', mode,
124
+ '--host', aspera_host_address,
125
+ '--user', aspera_username,
126
+ '--tags64', Base64.strict_encode64(JSON.generate(tags)),
127
+ ]
128
+ cmdline_args.concat [ '-P', aspera_ssh_port ] if aspera_ssh_port
129
+ cmdline_args.concat ascp_args.is_a?(Array) ? ascp_args : ascp_args.split(' ') if ascp_args && !ascp_args.empty?
130
+ cmdline_args.concat [ '-W', aspera_token ] if aspera_token && !aspera_token.empty?
131
+ cmdline_args.concat [ source_path.gsub('"', '\"'), target_path.gsub('"', '\"') ]
132
+
133
+ { env: env_vars, args: cmdline_args, ascp_version: :ascp }
134
+ end
135
+
35
136
  def build_ascp_command(config, mode, source_path, target_path)
36
137
  aspera_host_address = config['host_address'] || config['host']
37
138
  aspera_username = config['username']
38
139
  aspera_password = config['password']
140
+ aspera_ssh_port = config['ssh_port']
141
+
142
+ aspera_url = config['url'] || config['uri']
143
+ if aspera_url
144
+ aspera_uri = URI(aspera_url)
145
+ aspera_host_address ||= aspera_uri.host if aspera_uri
146
+ un, pw = (aspera_uri.userinfo || '').split(':')
147
+ aspera_username ||= un if un
148
+ aspera_password ||= pw if pw
149
+ aspera_ssh_port ||= aspera_uri.port
150
+ end
151
+
39
152
  aspera_token = config['aspera_transfer_token'] || config['aspera_token'] || config['token'] || config['transfer_token']
40
153
 
41
154
  @ascp_path = config['ascp_path'] || default_ascp_path
@@ -43,11 +156,19 @@ module Envoi
43
156
 
44
157
  aspera_ascp_path = @ascp_path
45
158
 
159
+ tags = config['tags'] || { }
160
+ aspera_tags = tags['aspera'] || { }
161
+ aspera_tags['xfer_id'] ||= SecureRandom.uuid
162
+
163
+
46
164
  ascp_args = config['ascp_args'] || default_ascp_args || agent.default_ascp_args
165
+
47
166
  # command = %(export ASPERA_SCP_PASS="#{aspera_password}"; "#{aspera_ascp_path}" #{ascp_args} --host="#{aspera_host_address}" --user=#{aspera_username} --mode=#{mode} "#{source_path}" "#{target_path}" )
48
167
  command = ''
49
168
  command << %(export ASPERA_SCP_PASS="#{aspera_password}"; ) if aspera_password
50
169
  command << %("#{aspera_ascp_path}" --mode=#{mode} --host="#{aspera_host_address}" --user="#{aspera_username}")
170
+ command << %( -P #{aspera_ssh_port}) if aspera_ssh_port
171
+ command << %(--tags64 #{Base64.strict_encode64(JSON.generate(tags))}) if tags && !tags.empty?
51
172
  command << %( #{ascp_args}) if ascp_args && !ascp_args.empty?
52
173
  command << %( -W "#{aspera_token}") if aspera_token && !aspera_token.empty?
53
174
  command << %( "#{source_path.gsub('"', '\"')}" "#{target_path.gsub('"', '\"')}")
@@ -56,20 +177,37 @@ module Envoi
56
177
  def download(config, path, destination_path = DEFAULT_DESTINATION_PATH)
57
178
  aspera_base_path = config['base_path'] || ''
58
179
  source_path = File.join(aspera_base_path, path)
59
- command = build_ascp_command(config, 'recv', source_path, destination_path)
60
180
 
61
- unless ascp_path_exists?
62
- warn "ASCP not found. '#{ascp_path}'"
63
- return false
64
- end
65
- agent.shell_execute(command)
181
+ mode = 'recv'
182
+ transfer(config, mode, source_path, destination_path)
66
183
  end
67
184
 
68
185
  def upload(config, path, destination_path = DEFAULT_DESTINATION_PATH)
69
186
  aspera_base_path = config['base_path'] || ''
70
187
  source_path = path
71
188
  destination_path = aspera_base_path.empty? ? destination_path : File.join(aspera_base_path, destination_path)
72
- command = build_ascp_command(config, 'send', source_path, destination_path)
189
+
190
+ mode = 'send'
191
+ transfer(config, mode, source_path, destination_path)
192
+ end
193
+
194
+ def transfer(config, mode, source_path, destination_path)
195
+ if false
196
+ transfer_using_asperala(config, mode, source_path, destination_path)
197
+ else
198
+ transfer_using_shell_execute(config, mode, source_path, destination_path)
199
+ end
200
+ end
201
+
202
+ def transfer_using_asperala(config, mode, source_path, destination_path)
203
+ args_out = build_asperala_transfer_args(config, mode, source_path, destination_path)
204
+ fasp = Asperalm::Fasp::Local.instance
205
+ Asperalm::Log.instance.level = :debug
206
+ fasp.start_transfer_with_args_env(args_out, {})
207
+ end
208
+
209
+ def transfer_using_shell_execute(config, mode, source_path, destination_path)
210
+ command = build_ascp_command(config, mode, source_path, destination_path)
73
211
 
74
212
  unless ascp_path_exists?
75
213
  warn "ASCP not found. '#{ascp_path}'"
@@ -1,7 +1,7 @@
1
1
  module Envoi
2
2
  module Mam
3
3
  class Agent
4
- VERSION = '1.0.2'.freeze
4
+ VERSION = '1.1.0'.freeze
5
5
  end
6
6
  end
7
7
  end
@@ -0,0 +1,76 @@
1
+ module Envoi
2
+ module Mam
3
+ class Agent
4
+ class WatchFolderUtility
5
+ class Foreman
6
+
7
+ AWF = Envoi::Aspera::WatchService::WatchFolder
8
+ LWF = Envoi::WatchFolderUtility::WatchFolder::Listen
9
+
10
+ attr_accessor :logger, :agent, :config, :watch_folders
11
+
12
+ def initialize(args = { })
13
+ initialize_logger(args)
14
+
15
+ @agent = Envoi::Mam::Cantemo::Agent.load_from_config_file(args)
16
+ @config = agent.config
17
+ cantemo_config = config[:cantemo] || config['cantemo']
18
+ watch_folder_defs = cantemo_config[:watch_folders] || cantemo_config['watch_folders']
19
+
20
+ @ignored_file_paths_by_watch_folder = Hash.new { |h, k| h[k] = [] }
21
+
22
+
23
+
24
+ @watch_folders = AWF.process_watch_folder_defs(watch_folder_defs)
25
+ end
26
+
27
+ def self.initialize_watch_folder(watch_folder_def)
28
+ case (watch_folder_def['handler'] || '').downcase.gsub(/[-_ ]/, '')
29
+ when 'asperawatch'
30
+ wf_class = Envoi::Aspera::WatchService::WatchFolder
31
+ end
32
+ wf_class.new(watch_folder_def)
33
+ end
34
+
35
+ def self.process_watch_folder_def(watch_folder_def)
36
+ initialize_watch_folder(watch_folder_def)
37
+ end
38
+
39
+ def self.process_watch_folder_defs(watch_folder_defs)
40
+ if watch_folder_defs.is_a?(Array)
41
+ watch_folder_defs.map { |watch_folder_def| process_watch_folder_def(watch_folder_def) }
42
+ elsif watch_folder_defs.is_a?(Hash)
43
+ watch_folder_defs.map do |name, watch_folder_def|
44
+ watch_folder_def['path'] ||= name; process_watch_folder_def(watch_folder_def)
45
+ end
46
+ else
47
+ raise "Unhandled format: #{watch_folder_defs.class.name}"
48
+ end
49
+ end
50
+
51
+ def self.poll_watch_folder(watch_folder, &block)
52
+ watch_folder.poll(&block)
53
+ end
54
+
55
+ def self.poll_watch_folders(watch_folders, &block)
56
+ watch_folders.each { |watch_folder| poll_watch_folder(watch_folder, &block) }
57
+ end
58
+
59
+ def self.run_once(watch_folders, &block)
60
+ poll_watch_folders(watch_folders, &block)
61
+ end
62
+
63
+ # Foreman
64
+ end
65
+
66
+ # WatchFolderUtility
67
+ end
68
+
69
+ # Agent
70
+ end
71
+
72
+ # Mam
73
+ end
74
+
75
+ # Envoi
76
+ end
@@ -55,6 +55,7 @@ module Envoi
55
55
  end
56
56
  logger.debug { "Executing Command: '#{command}'" }
57
57
 
58
+ success = false
58
59
  Open3.popen3(command) do |stdin, stdout, stderr, thread|
59
60
  # stdin.sync = true
60
61
  # stdout.sync = true
@@ -65,11 +66,15 @@ module Envoi
65
66
  output << stdout.read #rescue nil
66
67
  output << stderr.read # rescue nil
67
68
  unless output.empty?
68
- print output
69
+ logger.debug { output }
69
70
  output.clear
70
71
  end
71
72
  end
73
+
74
+ success = thread.value == 0 ? true : false
72
75
  end
76
+
77
+ success
73
78
  end
74
79
 
75
80
  def self.load_from_config_file(args)
@@ -0,0 +1,111 @@
1
+ require 'envoi/mam/cantemo/agent'
2
+ require 'envoi/aspera/watch_service/watch_folder'
3
+
4
+ module Envoi::Mam::Cantemo
5
+
6
+ class Agent
7
+
8
+ class WatchFolderHandler
9
+
10
+ AWF = Envoi::Aspera::WatchService::WatchFolder
11
+
12
+ attr_accessor :logger, :agent, :config, :watch_folders
13
+
14
+ def initialize(args = { })
15
+ initialize_logger(args)
16
+
17
+ @agent = Envoi::Mam::Cantemo::Agent.load_from_config_file(args)
18
+ @config = agent.config
19
+ cantemo_config = config[:cantemo] || config['cantemo']
20
+ watch_folder_defs = cantemo_config[:watch_folders] || cantemo_config['watch_folders']
21
+
22
+ @ignored_file_paths_by_watch_folder = Hash.new { |h, k| h[k] = [] }
23
+
24
+ @watch_folders = AWF.process_watch_folder_defs(watch_folder_defs)
25
+ end
26
+
27
+ def initialize_logger(args = { })
28
+ @logger = args[:logger] ||= Logger.new(args[:log_to] || STDOUT)
29
+ log_level = args[:log_level]
30
+ if log_level
31
+ @logger.level = log_level
32
+ args[:logger] = @logger
33
+ end
34
+ @logger
35
+ end
36
+
37
+ def add_to_ignore(wf, file)
38
+ @ignored_file_paths_by_watch_folder[wf] << file.path
39
+ end
40
+
41
+ def process_file(watch_folder, file, storage_id = nil, quarantine_directory_path = nil)
42
+ full_file_path = File.join(watch_folder.path, file.path)
43
+ if storage_id && agent.upload(file_path: full_file_path, storage_id: storage_id)
44
+ FileUtils.rm full_file_path
45
+ else
46
+ if Dir.exist?(quarantine_directory_path)
47
+ FileUtils.mv full_file_path, quarantine_directory_path
48
+ else
49
+ add_to_ignore(watch_folder, file)
50
+ end
51
+ end
52
+ end
53
+
54
+ def process_watch_folder(wf)
55
+ storage_id = wf.definition['upload_to_storage_id'] || wf.definition['storage_id']
56
+ quarantine_directory_path = wf.definition['quarantine_path']
57
+ exclude = wf.definition['exclude']
58
+ min_stable_poll_count = wf.definition['stable_poll_count'] || 3
59
+
60
+ maps = wf.state.details[:maps]
61
+ stable_paths = maps[:stable]
62
+ ignored_files = @ignored_file_paths_by_watch_folder[wf]
63
+ stable_paths.each do |fp, file|
64
+ if exclude
65
+ next if ignored_files.include?(file.path)
66
+ if [*exclude].find { |ep| File.fnmatch(ep, file.path) }
67
+ logger.debug { "Adding File to Ignore Cache: '#{file.path}'"}
68
+ ignored_files << file.path
69
+ next
70
+ end
71
+ end
72
+
73
+ # full_file_path = File.join(wf.path, file.path)
74
+
75
+ # pp file
76
+ # puts file_path
77
+ stable_poll_count = file[:stable_poll_count]
78
+
79
+ if stable_poll_count && stable_poll_count > min_stable_poll_count
80
+ process_file(wf, file, storage_id, quarantine_directory_path)
81
+ end
82
+ end
83
+
84
+ # process_watch_folder
85
+ end
86
+
87
+ def run
88
+ # AWF.run_once(watch_folders) { |wf| pp wf }
89
+ AWF.run(watch_folders) { |wf| process_watch_folder(wf) }
90
+ end
91
+
92
+ def run_once
93
+ AWF.run_once(watch_folders) { |wf| process_watch_folder(wf) }
94
+ end
95
+
96
+ def self.run(args)
97
+ w = self.new(args)
98
+ w.run
99
+ end
100
+
101
+ def self.run_as_daemon(args)
102
+ # ARGV.unshift 'run' unless %w(start stop restart run zap killall status).include? ARGV.first
103
+ require 'daemons'
104
+ Daemons.run_proc('cantemo-portal-watch-folders') { self.run(args) }
105
+ end
106
+
107
+ end
108
+
109
+ end
110
+
111
+ end
@@ -0,0 +1,176 @@
1
+ require 'envoi/mam/cantemo/agent'
2
+ require 'envoi/aspera/watch_service/watch_folder'
3
+ require 'envoi/watch_folder_utility/watch_folder/handler/listen'
4
+
5
+ module Envoi::Mam::Cantemo
6
+
7
+ class Agent
8
+
9
+ class WatchFolderHandler
10
+
11
+ AWF = Envoi::Aspera::WatchService::WatchFolder
12
+ LWF = Envoi::WatchFolderUtility::WatchFolder::Handler::Listen
13
+
14
+ attr_accessor :logger, :agent, :config, :watch_folder_defs, :watch_folders
15
+
16
+ def initialize(args = { })
17
+ initialize_logger(args)
18
+
19
+ @agent = Envoi::Mam::Cantemo::Agent.load_from_config_file(args)
20
+ @config = agent.config
21
+ cantemo_config = config[:cantemo] || config['cantemo']
22
+ @watch_folder_defs = cantemo_config[:watch_folders] || cantemo_config['watch_folders']
23
+
24
+ @ignored_file_paths_by_watch_folder = Hash.new { |h, k| h[k] = [] }
25
+ process_watch_folder_defs
26
+ end
27
+
28
+ def process_watch_folder_def(watch_folder_def)
29
+ name = watch_folder_def['name']
30
+
31
+ path = watch_folder_def['path']
32
+ path ||= name
33
+ (watch_folder_def['paths'] ||= []).concat [*path]
34
+ watch_folder_def['paths'].uniq!
35
+ paths = watch_folder_def['paths']
36
+ watch_folder_def['path'] ||= paths.first if path.length == 1
37
+
38
+ exclude = watch_folder_def['exclude']
39
+ exclude ||= '**/.*'
40
+ (watch_folder_def['excludes'] ||= []).concat [*exclude]
41
+ watch_folder_def['excludes'].uniq!
42
+
43
+ args_out = { }
44
+ logging = watch_folder_def['logging'] || watch_folder_def
45
+ log_to = logging['log_to']
46
+ log_level = logging['log_level']
47
+ args_out[:log_to] ||= log_to if log_to && !log_to.empty?
48
+ args_out[:log_level] ||= log_level if log_level && !log_level.empty?
49
+ args_out[:logger] ||= logger.dup unless log_to
50
+ args_out[:definition] = watch_folder_def
51
+
52
+ LWF.new(args_out)
53
+ end
54
+
55
+ def process_watch_folder_defs
56
+ if watch_folder_defs.is_a?(Array)
57
+ @watch_folders = watch_folder_defs.map { |watch_folder_def| process_watch_folder_def(watch_folder_def) }
58
+ elsif watch_folder_defs.is_a?(Hash)
59
+ @watch_folders = watch_folder_defs.map do |name, watch_folder_def|
60
+ watch_folder_def['name'] ||= name
61
+
62
+ process_watch_folder_def(watch_folder_def)
63
+ end
64
+ else
65
+ raise "Unhandled format: #{watch_folder_defs.class.name}"
66
+ end
67
+ end
68
+
69
+ def initialize_logger(args = { })
70
+ @logger = args[:logger] ||= Logger.new(args[:log_to] || STDOUT)
71
+ log_level = args[:log_level]
72
+ if log_level
73
+ @logger.level = log_level
74
+ args[:logger] = @logger
75
+ end
76
+ @logger
77
+ end
78
+
79
+ def add_to_ignore(watch_folder, file)
80
+ logger.debug { "Adding File to Ignore Cache: '#{file.path}'"}
81
+ @ignored_file_paths_by_watch_folder[watch_folder] << file.path
82
+ end
83
+
84
+ def process_file(watch_folder, file, storage_id = nil, quarantine_directory_path = nil)
85
+ # full_file_path = File.join(watch_folder.path, file.path)
86
+ full_file_path = file.path
87
+ if storage_id && agent.upload(file_path: full_file_path, storage_id: storage_id)
88
+ FileUtils.rm full_file_path
89
+ else
90
+ if Dir.exist?(quarantine_directory_path)
91
+ FileUtils.mv full_file_path, quarantine_directory_path
92
+ else
93
+ add_to_ignore(watch_folder, file)
94
+ end
95
+ end
96
+ end
97
+
98
+ def process_watch_folder_stable_files(wf, stable_files)
99
+ storage_id = wf.definition['upload_to_storage_id'] || wf.definition['storage_id']
100
+ quarantine_directory_path = wf.definition['quarantine_path']
101
+ exclude = wf.definition['excludes']
102
+
103
+ ignored_file_paths = @ignored_file_paths_by_watch_folder[wf]
104
+ stable_files.each do |file|
105
+ next if ignored_file_paths.include?(file.path)
106
+
107
+ if exclude && [*exclude].find do |ep|
108
+ excluded = (r = Regexp.try_convert(ep) ? r.match(ep) : File.fnmatch(ep, file.path))
109
+ logger.debug { "#{ep} #{excluded ? 'matched' : "didn't match"} #{file.path}" }
110
+ excluded
111
+ end
112
+ add_to_ignore(wf, file)
113
+ next
114
+ end
115
+
116
+ process_file(wf, file, storage_id, quarantine_directory_path)
117
+ end
118
+
119
+ end
120
+
121
+ def poll
122
+ stable_files_by_watch_folder = {} # Hash.new { |h, k| h[k] = [] }
123
+ watch_folders.each do |watch_folder|
124
+ if !watch_folder.last_poll_time || (Time.now - watch_folder.last_poll_time) >= watch_folder.poll_interval
125
+ stable_files = watch_folder.poll
126
+ stable_files_by_watch_folder[watch_folder] = stable_files
127
+ end
128
+ end
129
+ stable_files_by_watch_folder.each do |watch_folder, stable_files|
130
+ process_watch_folder_stable_files(watch_folder, stable_files)
131
+ end
132
+ end
133
+
134
+ def run
135
+ # AWF.run_once(watch_folders) { |wf| pp wf }
136
+ # AWF.run(watch_folders) { |wf| process_watch_folder(wf) }
137
+
138
+ logger.info { 'Running...' }
139
+ watch_folders.map { |wf| wf.run }
140
+ loop do
141
+ begin
142
+ poll
143
+ sleep 1
144
+ rescue SystemExit, Interrupt
145
+ break
146
+ end
147
+ end
148
+ logger.info { 'Exiting...' }
149
+ rescue => e
150
+ logger.error { "An error occurred.\n#{e.message}\n#{e.backtrace.join("\n")}\n#{e.message}" }
151
+ raise e
152
+ end
153
+
154
+ def run_once
155
+ # AWF.run_once(watch_folders) { |wf| process_watch_folder(wf) }
156
+ end
157
+
158
+ def self.run(args)
159
+ w = self.new(args)
160
+ w.run
161
+ rescue => e
162
+ abort("An error occurred.\n#{e.message}\n#{e.message}")
163
+ end
164
+
165
+ def self.run_as_daemon(args)
166
+ # ARGV.unshift 'run' unless %w(start stop restart run zap killall status).include? ARGV.first
167
+ require 'daemons'
168
+ # Daemons.run_proc('cantemo-portal-watch-folders', { force: true }) { self.run(args) }
169
+ Daemons.run_proc('cantemo-portal-watch-folders') { self.run(args) }
170
+ end
171
+
172
+ end
173
+
174
+ end
175
+
176
+ end