rest-ftp-daemon 0.6 → 0.9.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,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