rest-ftp-daemon 0.85.2 → 0.90.1

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,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