rest-ftp-daemon 0.6 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,246 +0,0 @@
1
- require 'net/ftp'
2
-
3
-
4
- module RestFtpDaemon
5
- class Job < RestFtpDaemon::Common
6
-
7
- def initialize(id, params={})
8
- # Call super
9
- super()
10
-
11
- # Grab params
12
- @params = params
13
- @target = nil
14
- @source = nil
15
-
16
- # Init context
17
- set :id, id
18
- set :started_at, Time.now
19
- set :status, :created
20
-
21
- # Send first notification
22
- notify "rftpd.queued"
23
- end
24
-
25
- def progname
26
- job_id = get(:id)
27
- "JOB #{job_id}"
28
- end
29
-
30
- def id
31
- get :id
32
- end
33
-
34
- def priority
35
- get :priority
36
- end
37
- def get_status
38
- get :status
39
- end
40
-
41
- def process
42
- # Init
43
- info "Job.process starting"
44
- set :status, :starting
45
- set :error, 0
46
-
47
- begin
48
- # Validate job and params
49
- prepare
50
-
51
- # Process
52
- transfer
53
-
54
- rescue Net::FTPPermError => exception
55
- info "Job.process failed [Net::FTPPermError]"
56
- set :status, :failed
57
- set :error, exception.class
58
-
59
- rescue RestFtpDaemonException => exception
60
- info "Job.process failed [RestFtpDaemonException::#{exception.class}]"
61
- set :status, :failed
62
- set :error, exception.class
63
-
64
- # rescue Exception => exception
65
- # set :status, :crashed
66
- # set :error, exception.class
67
-
68
- else
69
- info "Job.process finished"
70
- # set :error, 0
71
- #set :status, :wandering
72
-
73
- # Wait for a few seconds before marking the job as finished
74
- # info "#{prefix} wander for #{RestFtpDaemon::THREAD_SLEEP_BEFORE_DIE} sec"
75
- # wander RestFtpDaemon::THREAD_SLEEP_BEFORE_DIE
76
- set :status, :finished
77
- end
78
-
79
- end
80
-
81
- def describe
82
- # Update realtime info
83
- w = wandering_time
84
- set :wandering, w.round(2) unless w.nil?
85
-
86
- # Update realtime info
87
- u = up_time
88
- set :uptime, u.round(2) unless u.nil?
89
-
90
- # Return the whole structure
91
- @params
92
- end
93
-
94
- def status text
95
- @status = text
96
- end
97
-
98
- def get attribute
99
- return nil unless @params.is_a? Enumerable
100
- @params[attribute.to_s]
101
- end
102
-
103
- protected
104
-
105
- def up_time
106
- return if @params[:started_at].nil?
107
- Time.now - @params[:started_at]
108
- end
109
-
110
- def wander time
111
- info "Job.wander #{time}"
112
- @wander_for = time
113
- @wander_started = Time.now
114
- sleep time
115
- info "Job.wandered ok"
116
- end
117
-
118
- def wandering_time
119
- return if @wander_started.nil? || @wander_for.nil?
120
- @wander_for.to_f - (Time.now - @wander_started)
121
- end
122
-
123
- # def exception_handler(actor, reason)
124
- # set :status, :crashed
125
- # set :error, reason
126
- # end
127
-
128
- def set attribute, value
129
- return unless @params.is_a? Enumerable
130
- @params[:updated_at] = Time.now
131
- @params[attribute.to_s] = value
132
- end
133
-
134
- def expand_path_from path
135
- File.expand_path replace_token_in_path(path)
136
- end
137
-
138
- def expand_url_from path
139
- URI replace_token_in_path(path) rescue nil
140
- end
141
-
142
- def replace_token_in_path path
143
- # Ensure endpoints are not a nil value
144
- return path unless Settings.endpoints.is_a? Enumerable
145
- newpath = path.clone
146
-
147
- # Replace endpoints defined in config
148
- Settings.endpoints.each do |from, to|
149
- newpath.gsub! "[#{from}]", to
150
- end
151
-
152
- # Replace with the special RAND token
153
- newpath.gsub! "[RANDOM]", SecureRandom.hex(8)
154
-
155
- return newpath
156
- end
157
-
158
- def prepare
159
- # Init
160
- set :status, :preparing
161
-
162
- # Check source
163
- raise JobSourceMissing unless @params["source"]
164
- @source = expand_path_from @params["source"]
165
- set :debug_source, @source
166
-
167
- # Check target
168
- raise JobTargetMissing unless @params["target"]
169
- @target = expand_url_from @params["target"]
170
- set :debug_target, @target.inspect
171
-
172
- # Check compliance
173
- raise JobTargetUnparseable if @target.nil?
174
- raise JobSourceNotFound unless File.exists? @source
175
-
176
- end
177
-
178
- def transfer_fake
179
- # Init
180
- set :status, :faking
181
-
182
- # Work
183
- (0..9).each do |i|
184
- set :faking, i
185
- sleep 0.5
186
- end
187
- end
188
-
189
- def transfer
190
- # Send first notification
191
- transferred = 0
192
- notify "rftpd.started"
193
-
194
- # Ensure @source and @target are there
195
- set :status, :checking_source
196
- raise JobPrerequisitesNotMet unless @source
197
- raise JobPrerequisitesNotMet unless @source
198
- target_path = File.dirname @target.path
199
- target_name = File.basename @target.path
200
-
201
- # Read source file size
202
- source_size = File.size @source
203
- set :file_size, source_size
204
-
205
- # Prepare FTP transfer
206
- set :status, :checking_target
207
- ftp = Net::FTP.new(@target.host)
208
- ftp.passive = true
209
- ftp.login @target.user, @target.password
210
- ftp.chdir(target_path)
211
-
212
- # Check for target file presence
213
- if get(:overwrite).nil?
214
- results = ftp.list(target_name)
215
- #results = ftp.list()
216
-
217
- unless results.count.zero?
218
- ftp.close
219
- notify "rftpd.ended", RestFtpDaemon::JobTargetFileExists
220
- raise RestFtpDaemon::JobTargetFileExists
221
- end
222
- end
223
-
224
- # Do transfer
225
- set :status, :uploading
226
- chunk_size = Settings.transfer.chunk_size || Settings[:default_chunk_size]
227
- ftp.putbinaryfile(@source, target_name, chunk_size) do |block|
228
- # Update counters
229
- transferred += block.bytesize
230
-
231
- # Update job info
232
- percent = (100.0 * transferred / source_size).round(1)
233
- set :progress, percent
234
- set :file_sent, transferred
235
- end
236
-
237
- # Close FTP connexion
238
- notify "rftpd.ended"
239
- set :progress, nil
240
- ftp.close
241
- end
242
-
243
- private
244
-
245
- end
246
- end
@@ -1,105 +0,0 @@
1
- require 'thread'
2
-
3
- module RestFtpDaemon
4
- class JobQueue < Queue
5
-
6
- def initialize
7
- @queued = []
8
- @popped = []
9
-
10
- @waiting = []
11
- @queued.taint # enable tainted communication
12
- @waiting.taint
13
- self.taint
14
- @mutex = Mutex.new
15
- end
16
-
17
- def queued
18
- @queued
19
- end
20
- def queued_size
21
- @queued.length
22
- end
23
-
24
- def popped
25
- @popped
26
- end
27
- def popped_size
28
- @popped.length
29
- end
30
-
31
- def all
32
- @queued + @popped
33
- end
34
- def all_size
35
- popped_size + queued_size
36
- end
37
-
38
- def push(obj)
39
- # Check that itme responds to "priorty" method
40
- raise "object should respond to priority method" unless obj.respond_to? :priority
41
-
42
- @mutex.synchronize{
43
- @queued.push obj
44
- begin
45
- t = @waiting.shift
46
- t.wakeup if t
47
- rescue ThreadError
48
- retry
49
- end
50
- }
51
- end
52
- alias << push
53
- alias enq push
54
-
55
- #
56
- # Retrieves data from the queue. If the queue is empty, the calling thread is
57
- # suspended until data is pushed onto the queue. If +non_block+ is true, the
58
- # thread isn't suspended, and an exception is raised.
59
- #
60
- def pop(non_block=false)
61
- @mutex.synchronize{
62
- while true
63
- if @queued.empty?
64
- raise ThreadError, "queue empty" if non_block
65
- @waiting.push Thread.current
66
- @mutex.sleep
67
- else
68
- return pick
69
- end
70
- end
71
- }
72
- end
73
- alias shift pop
74
- alias deq pop
75
-
76
- def empty?
77
- @queued.empty?
78
- end
79
-
80
- def clear
81
- @queued.clear
82
- end
83
-
84
- def num_waiting
85
- @waiting.size
86
- end
87
-
88
- protected
89
-
90
- def pick
91
- # Sort jobs by priority and get the biggest one
92
- picked = @queued.sort { |a,b| a.priority.to_i <=> b.priority.to_i }.last
93
-
94
- # Delete it from the queue
95
- @queued.delete_if { |item| item == picked } unless picked.nil?
96
-
97
- # Stack it to popped items
98
- @popped.push picked
99
-
100
- # Return picked
101
- picked
102
- end
103
-
104
- end
105
- end
@@ -1,7 +0,0 @@
1
- class Logger
2
- def format_message(severity, timestamp, progname, msg)
3
- stamp = Time.now.strftime("%Y-%m-%d %H:%M:%S")
4
- progname = "%-#{Settings[:default_trim_progname]}s" % progname
5
- "#{stamp} #{severity} #{progname} #{msg}\n"
6
- end
7
- end
@@ -1,82 +0,0 @@
1
- require 'net/http'
2
-
3
- module RestFtpDaemon
4
- class Notification < RestFtpDaemon::Common
5
- attr_accessor :job_id
6
- attr_accessor :signal
7
- attr_accessor :error
8
- attr_accessor :message
9
- attr_accessor :status
10
- attr_accessor :url
11
- attr_accessor :job
12
- attr_accessor :key
13
-
14
- def initialize
15
- #def initialize(job, signal, error, status)
16
- # Grab params
17
- #@job = job
18
- # @signal = signal
19
- # @error = error
20
- # @status = status
21
- @status = {}
22
- @error = 0
23
- @message = nil
24
-
25
- # Generate a random key
26
- @key = SecureRandom.hex(2)
27
-
28
- # Call super
29
- super
30
-
31
- end
32
-
33
- def progname
34
- "NOTIF #{@key}"
35
- end
36
-
37
-
38
- # def status key, val
39
- # @status[key.to_s] = val
40
- # end
41
-
42
- def notify
43
- # Check context
44
- raise NotificationMissingUrl unless @url
45
- raise NotificationMissingSignal unless @signal
46
- #sraise NotifImpossible unless @status
47
-
48
- # Params
49
- params = {
50
- id: @job_id,
51
- host: get_hostname,
52
- signal: @signal,
53
- error: @error,
54
- }
55
-
56
- # Add status only if present
57
- params["status"] = @status unless @status.empty?
58
- params["message"] = @message unless @message.to_s.blank?
59
-
60
- # Log this notification
61
- info "notify params: #{params.inspect}"
62
-
63
- # Prepare query
64
- uri = URI(@url)
65
- headers = {"Content-Type" => "application/json",
66
- "Accept" => "application/json"}
67
-
68
- # Post the notification
69
- http = Net::HTTP.new(uri.host, uri.port)
70
- response = http.post(uri.path, params.to_json, headers)
71
-
72
- info "notify reply: #{response.body.strip}"
73
- end
74
-
75
- protected
76
-
77
- def get_hostname
78
- `hostname`.chomp
79
- end
80
-
81
- end
82
- end