cantemo-portal-agent 1.0.9 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/exe/cantemo-portal-agent +8 -6
- data/lib/cantemo/portal/agent/WatchFolderUtility/foreman.rb +59 -0
- data/lib/cantemo/portal/agent/cli/commands/watch_folders-working.rb +237 -0
- data/lib/cantemo/portal/agent/cli/commands/watch_folders.rb +63 -0
- data/lib/cantemo/portal/agent/version.rb +1 -1
- data/lib/envoi/aspera/watch_service/client.rb +397 -0
- data/lib/envoi/aspera/watch_service/snapshot.rb +11 -0
- data/lib/envoi/aspera/watch_service/subscription.rb +0 -0
- data/lib/envoi/aspera/watch_service/watch_folder.rb +322 -0
- data/lib/envoi/mam/agent/cli/commands/cantemo-agent.rb +62 -0
- data/lib/envoi/mam/agent/cli/commands/cantemo-watch_folders.rb +41 -0
- data/lib/envoi/mam/agent/cli/commands/cantemo.rb +5 -0
- data/lib/envoi/mam/agent/cli/commands/iconik.rb +21 -11
- data/lib/envoi/mam/agent/cli/commands/mediasilo.rb +1 -1
- data/lib/envoi/mam/agent/cli/commands/vidispine.rb +7 -4
- data/lib/envoi/mam/agent/cli/commands/wiredrive.rb +15 -2
- data/lib/envoi/mam/agent/cli/commands.rb +4 -4
- data/lib/envoi/mam/agent/cli.rb +3 -3
- data/lib/envoi/mam/agent/transfer_client/aspera.rb +145 -7
- data/lib/envoi/mam/agent/version.rb +1 -1
- data/lib/envoi/mam/agent/watch_folder_utility/foreman.rb +76 -0
- data/lib/envoi/mam/agent.rb +6 -1
- data/lib/envoi/mam/cantemo/agent/watch_folder_handler-working.rb +111 -0
- data/lib/envoi/mam/cantemo/agent/watch_folder_handler.rb +176 -0
- data/lib/envoi/mam/cantemo/agent/watch_folder_handler_aspera.rb +112 -0
- data/lib/envoi/mam/cantemo/agent.rb +288 -0
- data/lib/envoi/mam/iconik/agent.rb +15 -3
- data/lib/envoi/mam/vidispine/agent.rb +6 -1
- data/lib/envoi/watch_folder_utility/watch_folder/handler/listen.rb +189 -0
- 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
|
-
|
62
|
-
|
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
|
-
|
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}'"
|
@@ -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
|
data/lib/envoi/mam/agent.rb
CHANGED
@@ -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
|
-
|
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
|