rest-ftp-daemon 0.85.2 → 0.90.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,10 @@
1
1
  require 'thread'
2
+ require 'securerandom'
2
3
 
3
4
  module RestFtpDaemon
4
5
  class JobQueue < Queue
6
+ attr_reader :queued
7
+ attr_reader :popped
5
8
 
6
9
  def initialize
7
10
  # # Logger
@@ -17,6 +20,12 @@ module RestFtpDaemon
17
20
  self.taint
18
21
  @mutex = Mutex.new
19
22
 
23
+ # Identifiers generator
24
+ @last_id = 0
25
+ #@prefix = SecureRandom.hex(IDENT_JOB_LEN)
26
+ @prefix = Helpers.identifier IDENT_JOB_LEN
27
+ info "queue initialized with prefix: #{@prefix}"
28
+
20
29
  # Mutex for counters
21
30
  @counters = {}
22
31
  @mutex_counters = Mutex.new
@@ -39,6 +48,13 @@ module RestFtpDaemon
39
48
 
40
49
  end
41
50
 
51
+ def generate_id
52
+ rand(36**8).to_s(36)
53
+ @last_id ||= 0
54
+ @last_id += 1
55
+ prefixed_id @last_id
56
+ end
57
+
42
58
  def counter_add name, value
43
59
  @mutex_counters.synchronize do
44
60
  @counters[name] ||= 0
@@ -60,27 +76,45 @@ module RestFtpDaemon
60
76
  end
61
77
  end
62
78
 
63
- def by_status status
79
+ # def by_status status
80
+ # return [] if status.nil?
81
+
82
+ # # Select jobs from the queue if their status is (status)
83
+ # all.select { |item| item.get(:status) == status.to_sym }
84
+ # end
85
+
86
+ def popped_reverse_sorted_by_status status
64
87
  return [] if status.nil?
65
88
 
66
89
  # Select jobs from the queue if their status is (status)
67
- all.select { |item| item.get(:status) == status.to_sym }
90
+ ordered_popped.reverse.select { |item| item.get(:status) == status.to_sym }
68
91
  end
69
92
 
70
- def queued
71
- @queued
72
- end
73
- def popped
74
- @popped
93
+ def popped_counts_by_status
94
+ statuses = {}
95
+ @popped.group_by { |job| job.get(:status) }.map { |status, jobs| statuses[status] = jobs.size }
96
+ statuses
75
97
  end
98
+
76
99
  def all
100
+ # queued2 = @queued.clone
101
+ # return queued2.merge(@popped)
77
102
  @queued + @popped
78
103
  end
79
104
  def all_size
80
105
  @queued.length + @popped.length
81
106
  end
82
107
 
83
- def push(obj)
108
+ def find_by_id id, prefixed = false
109
+ # Build a prefixed id if expected
110
+ id = prefixed_id(id) if prefixed
111
+ info "find_by_id (#{id}, #{prefixed}) > #{id}"
112
+
113
+ # Search in both queues
114
+ @queued.select { |item| item.id == id }.last || @popped.select { |item| item.id == id }.last
115
+ end
116
+
117
+ def push obj
84
118
  # Check that item responds to "priorty" method
85
119
  raise "JobQueue.push: object should respond to priority method" unless obj.respond_to? :priority
86
120
 
@@ -97,11 +131,7 @@ module RestFtpDaemon
97
131
  alias << push
98
132
  alias enq push
99
133
 
100
- #
101
- # Retrieves data from the queue. If the queue is empty, the calling thread is
102
- # suspended until data is pushed onto the queue. If +non_block+ is true, the
103
- # thread isn't suspended, and an exception is raised.
104
- #
134
+
105
135
  def pop(non_block=false)
106
136
  @mutex.synchronize do
107
137
  while true
@@ -110,7 +140,7 @@ module RestFtpDaemon
110
140
  @waiting.push Thread.current
111
141
  @mutex.sleep
112
142
  else
113
- return pick
143
+ return pick_one
114
144
  end
115
145
  end
116
146
  end
@@ -130,9 +160,20 @@ module RestFtpDaemon
130
160
  @waiting.size
131
161
  end
132
162
 
163
+ def ordered_queue
164
+ @queued.sort_by { |item| [item.priority.to_i, - item.id.to_i] }
165
+ end
166
+
167
+ def ordered_popped
168
+ @popped.sort_by { |item| [item.get(:updated_at)] }
169
+ end
133
170
 
134
171
  protected
135
172
 
173
+ def prefixed_id id
174
+ "#{@prefix}.#{id}"
175
+ end
176
+
136
177
  def conchita_loop
137
178
  info "conchita starting with: #{@conchita.inspect}"
138
179
  loop do
@@ -175,21 +216,20 @@ module RestFtpDaemon
175
216
  @logger.add(Logger::INFO, "#{' '*(level+1)} #{message}", progname) unless @logger.nil?
176
217
  end
177
218
 
178
- def pick # called inside a mutex/sync
219
+ def pick_one # called inside a mutex/sync
179
220
  # Sort jobs by priority and get the biggest one
180
- picked = @queued.sort { |a,b| a.priority.to_i <=> b.priority.to_i }.last
221
+ picked = ordered_queue.last
181
222
  return nil if picked.nil?
182
223
 
183
- # Delete it from the queue
224
+ # Move it away from the queue to the @popped array
184
225
  @queued.delete_if { |item| item == picked }
185
-
186
- # Stack it to popped items
187
226
  @popped.push picked
188
227
 
189
228
  # Return picked
190
229
  picked
191
230
  end
192
231
 
232
+
193
233
  private
194
234
 
195
235
  def info message, level = 0
@@ -32,12 +32,13 @@ module RestFtpDaemon
32
32
 
33
33
  # Params
34
34
  body = {
35
- id: params[:id],
35
+ id: params[:id].to_s,
36
36
  signal: params[:signal],
37
37
  error: params[:error],
38
- host: get_hostname,
38
+ host: Settings['host'].to_s,
39
39
  }
40
- body[:status] = params[:status] unless params[:status].empty? || params[:status].nil?
40
+ body[:status] = params[:status] if (params[:status].is_a? Enumerable)
41
+ # && (!params[:status].empty?)
41
42
 
42
43
  # Send message in a thread
43
44
  Thread.new do |thread|
@@ -59,9 +60,5 @@ module RestFtpDaemon
59
60
 
60
61
  protected
61
62
 
62
- def get_hostname
63
- `hostname`.chomp
64
- end
65
-
66
63
  end
67
64
  end
@@ -280,8 +280,8 @@ html {
280
280
  }
281
281
  body {
282
282
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
283
- font-size: 12px;
284
- line-height: 1.42857143;
283
+ font-size: 11px;
284
+ line-height: 1.3;
285
285
  color: #333333;
286
286
  background-color: #ffffff;
287
287
  }
@@ -0,0 +1,17 @@
1
+ .text-right {
2
+ text-align: right;
3
+ }
4
+
5
+ .transfer-method {
6
+ display: inline-block;
7
+ width: 35px;
8
+ padding: 4px 1px;
9
+ font-weight: normal;
10
+ }
11
+
12
+ .nobr {
13
+ white-space: nowrap;
14
+ }
15
+ .fixed {
16
+ font-family:monospace;
17
+ }
@@ -3,8 +3,9 @@
3
3
  %head
4
4
  %meta{:charset => "utf-8"}/
5
5
  %link{ href:"/css/bootstrap.css" , rel: "stylesheet"}
6
+ %link{ href:"/css/main.css" , rel: "stylesheet"}
6
7
 
7
- %title="#{Settings.name} dashboard"
8
+ %title="#{Settings['host']} [#{Settings.namespace}] #{APP_NAME}"
8
9
 
9
10
  :css
10
11
 
@@ -47,6 +48,10 @@
47
48
  .btn.btn-default.btn-success IP
48
49
  .btn.btn-default= @info_ipaddr
49
50
 
51
+ .btn-group.btn-group-sm
52
+ .btn.btn-default.btn-success Host
53
+ .btn.btn-default= Settings['host']
54
+
50
55
  .btn-group.btn-group-sm
51
56
  .btn.btn-default.btn-warning Load
52
57
  .btn.btn-default= @info_load.round(1)
@@ -65,9 +70,43 @@
65
70
 
66
71
 
67
72
  .row
68
- .col-md-9
69
- = render :dashboard_jobs, {jobs: @jobs, counts: @counts}
70
- .col-md-3
73
+ .col-md-10
74
+
75
+ %h2
76
+ Jobs &nbsp;
77
+
78
+ .btn-group.btn-group-md
79
+ - klass = @only.nil? ? "btn-info" : ""
80
+ %a.btn.btn-default{href: "?only=", class: klass}
81
+ ALL (#{@jobs_queued.size} + #{@jobs_popped.size})
82
+ .btn-group.btn-group-md
83
+ - @counts.each do |status, count|
84
+ - klass = (status == @only) ? "btn-info" : ""
85
+ %a.btn.btn-default{href: "?only=#{status}", class: klass}
86
+ #{status} (#{count})
87
+
88
+ %table.table.table-striped.table-hover.table-condensed
89
+ %tr
90
+ %th JID
91
+ %th prio
92
+ %th worker
93
+ %th source
94
+ %th target
95
+ %th status
96
+ %th error
97
+ %th progress
98
+ %th.text-right size
99
+ %th.text-right bitrate
100
+
101
+ - if @only.nil? && !@jobs_queued.empty?
102
+ = render :dashboard_jobs, {jobs: @jobs_queued, counts: @counts}
103
+ %tr
104
+ %th{colspan: 10}
105
+
106
+ = render :dashboard_jobs, {jobs: @jobs_popped, counts: @counts}
107
+
108
+
109
+ .col-md-2
71
110
  = render :dashboard_workers, {}
72
111
 
73
112
  = render :dashboard_tokens, {tokens: Settings.endpoints || {}}
@@ -1,75 +1,56 @@
1
- %h2
2
- Jobs
3
- = "&nbsp;"
4
-
5
- .btn-group.btn-group-md
6
- - klass = @only.nil? ? "btn-info" : ""
7
- %a.btn.btn-default{href: "?only=", class: klass}
8
- ALL (#{jobs.size})
9
-
10
- =# jobs.size
11
-
12
- .btn-group.btn-group-md
13
- - counts.each do |status, count|
14
- - klass = (status == @only) ? "btn-info" : ""
15
- %a.btn.btn-default{href: "?only=#{status}", class: klass}
16
- #{status} (#{count})
17
-
18
- %table.table.table-striped.table-hover.table-condensed
19
-
20
- %tr
21
- %th= "ID"
22
- %th= "priority"
23
- %th= "source"
24
- %th= "target"
25
- %th= "mode"
26
- %th= "size"
27
- %th= "status"
28
- %th= "error"
29
- %th= "progress"
30
- %th= "worker"
31
- %th
32
-
33
- - jobs.each do |job|
34
- - error = job.get :error
35
- - status = job.get :status
36
- - size = job.get :transfer_size
37
- - progress = job.get :progress
38
-
39
- - if error!=0 && !error.nil?
40
- - trclass = "danger"
41
- - elsif status == :uploading
42
- - trclass = "info"
43
- - elsif status == :finished
44
- - trclass = "success"
45
- - else
46
- - trclass = "warning"
47
-
48
- %tr{class: trclass}
49
-
50
- %td= job.id
51
- %td= job.get :priority
52
- %td{title: job.get(:source_path)}
53
- = job.get :source
54
- %td{title: job.get(:target_url)}
55
- = job.get :target
56
- %td
57
- .label.label-info= job.get :source_method
58
- .label.label-primary= job.get :target_method
59
- %td= Helpers.format_bytes(size, "B")
60
- %td= status
61
- %td= error
62
- %td
63
- - unless progress.nil?
64
- .progress
65
- .progress-bar{style:"width: #{progress}%;"}
66
- = Helpers.format_bytes job.get(:transfer_sent), "B"
67
- %td
68
- - unless progress.nil?
69
- = "#{progress}%"
70
- - if (bitrate = job.get :transfer_bitrate)
71
- = "|"
72
- = Helpers.format_bytes(bitrate, "bps")
73
-
74
- %td= job.wid
1
+ - jobs.each do |job|
2
+ - error = job.get :error
3
+ - status = job.get :status
4
+ - size = job.get :transfer_total
5
+ - progress = job.get :progress
6
+ - transfer_source_count = job.get(:transfer_source_count) || 0
7
+ - transfer_source_done = job.get(:transfer_source_done) || 0
8
+
9
+ - if error!=0 && !error.nil?
10
+ - trclass = "danger"
11
+ - elsif status == :uploading
12
+ - trclass = "info"
13
+ - elsif status == :finished
14
+ - trclass = "success"
15
+ - else
16
+ - trclass = "warning"
17
+
18
+ %tr{class: trclass}
19
+
20
+ %td= job.id
21
+
22
+ %td= job.get :priority
23
+
24
+ %td= job.wid
25
+
26
+ %td.fixed{title: job.get(:source_path)}
27
+ = Helpers.job_method_label job.get(:source_method)
28
+ = job.get :source
29
+
30
+ %td.fixed{title: job.get(:target_url)}
31
+ = Helpers.job_method_label job.get(:target_method)
32
+ = job.get :target
33
+
34
+ %td
35
+ = status
36
+ - if (transfer_source_count > 0) #&& (transfer_source_done < transfer_source_count)
37
+ %small= " #{transfer_source_done}/#{transfer_source_count}"
38
+
39
+ %td
40
+ = error
41
+ - unless progress.nil? || status == :finished
42
+ %small= "#{progress}%"
43
+
44
+ %td
45
+ - unless progress.nil?
46
+ .progress
47
+ .progress-bar{style:"width: #{progress}%;"}
48
+ = Helpers.format_bytes job.get(:transfer_sent), "B"
49
+
50
+ %td.nobr.text-right
51
+ = Helpers.format_bytes(size, "B")
52
+
53
+ %td.nobr.text-right
54
+ - if (bitrate = job.get :transfer_bitrate)
55
+ = Helpers.format_bytes(bitrate, "bps")
75
56
 
@@ -12,7 +12,7 @@
12
12
  %table.table.table-striped.table-hover.table-condensed
13
13
 
14
14
  %tr
15
- %th= "ID"
15
+ %th= "WID"
16
16
  %th= "status"
17
17
  %th= "job"
18
18
  %th= "time"
@@ -67,7 +67,7 @@ module RestFtpDaemon
67
67
  ex.backtrace.each do |line|
68
68
  info line, 1
69
69
  end
70
- sleep 2
70
+ sleep 1
71
71
  else
72
72
 
73
73
  # Clean job status
@@ -1,11 +1,11 @@
1
1
  defaults: &defaults
2
- daemonize: 1
3
- port: 3200
2
+ daemonize: true
3
+ port: 3000
4
4
  workers: 2
5
5
  #adminpwd: "admin"
6
- pidfile: /tmp/rftpd.pid
7
6
  user: rftpd
8
7
  group: rftpd
8
+ host: <%= `hostname`.chomp.split('.').first %>
9
9
 
10
10
  transfer:
11
11
  #update_every_kb: 500
@@ -26,3 +26,4 @@ preprod:
26
26
 
27
27
  production:
28
28
  <<: *defaults
29
+ port: 3200