panopticon 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/panopticond +52 -0
- data/extra/install.sh +14 -0
- data/extra/panopticond +62 -0
- data/extra/public/css/bootstrap-theme.css +384 -0
- data/extra/public/css/bootstrap-theme.min.css +1 -0
- data/extra/public/css/bootstrap.css +6805 -0
- data/extra/public/css/bootstrap.min.css +9 -0
- data/extra/public/css/panopticon.css +15 -0
- data/extra/public/fonts/glyphicons-halflings-regular.eot +0 -0
- data/extra/public/fonts/glyphicons-halflings-regular.svg +228 -0
- data/extra/public/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/extra/public/fonts/glyphicons-halflings-regular.woff +0 -0
- data/extra/public/index.html +135 -0
- data/extra/public/js/bootstrap.js +1999 -0
- data/extra/public/js/bootstrap.min.js +6 -0
- data/extra/public/js/canvasjs.min.js +555 -0
- data/extra/public/js/jquery-3.1.0.min.js +4 -0
- data/extra/public/js/script.js +512 -0
- data/lib/panopticon.rb +10 -0
- data/lib/panopticon/api.rb +59 -0
- data/lib/panopticon/command/panopticond.rb +47 -0
- data/lib/panopticon/log.rb +36 -0
- data/lib/panopticon/version.rb +3 -0
- data/lib/panopticon/wlan_capture.rb +135 -0
- data/lib/panopticon/wlan_control.rb +275 -0
- data/lib/panopticon/wlan_utilization.rb +128 -0
- data/panopticon.gemspec +30 -0
- metadata +151 -0
data/lib/panopticon.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require "panopticon/version"
|
2
|
+
require "panopticon/api"
|
3
|
+
require "panopticon/log"
|
4
|
+
require "panopticon/wlan_capture"
|
5
|
+
require "panopticon/wlan_control"
|
6
|
+
require "panopticon/wlan_utilization"
|
7
|
+
require "panopticon/command/panopticond"
|
8
|
+
|
9
|
+
module Panopticon
|
10
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Panopticon
|
2
|
+
require "sinatra/base"
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
require "panopticon/wlan_control"
|
6
|
+
|
7
|
+
class APIServer < Sinatra::Base
|
8
|
+
DEFAULT_PORT=8080
|
9
|
+
|
10
|
+
set :port, DEFAULT_PORT
|
11
|
+
set :public_folder, File.dirname(__FILE__) + "/../../extra/public"
|
12
|
+
enable :logging
|
13
|
+
|
14
|
+
def self.run! arg={}
|
15
|
+
@arg = arg
|
16
|
+
|
17
|
+
@port = arg[:port] || DEFAULT_PORT
|
18
|
+
set :port, @port
|
19
|
+
|
20
|
+
@@wlan_control = Panopticon::WlanControl.new(arg)
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
get "/" do
|
25
|
+
redirect to ("/index.html")
|
26
|
+
end
|
27
|
+
|
28
|
+
get "/api/v1/status" do
|
29
|
+
JSON.dump(@@wlan_control.get_status)
|
30
|
+
end
|
31
|
+
|
32
|
+
post "/api/v1/start" do
|
33
|
+
begin
|
34
|
+
data = request.body.read
|
35
|
+
json = JSON.parse(data)
|
36
|
+
|
37
|
+
@@wlan_control.start_capture(json)
|
38
|
+
status 200
|
39
|
+
"success"
|
40
|
+
rescue => e
|
41
|
+
$log.err("/start failed => #{e}")
|
42
|
+
status 500
|
43
|
+
"failed (#{e})"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
post "/api/v1/stop" do
|
48
|
+
begin
|
49
|
+
@@wlan_control.stop_capture
|
50
|
+
status 200
|
51
|
+
"success"
|
52
|
+
rescue => e
|
53
|
+
$log.err("/start failed => #{e}")
|
54
|
+
status 500
|
55
|
+
"failed (#{e})"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Panopticon
|
2
|
+
require "panopticon/log"
|
3
|
+
|
4
|
+
class Daemon
|
5
|
+
DEFAULT_CONFIG_PATH="/etc/panopticon.conf"
|
6
|
+
|
7
|
+
DEFAULT_API_PORT=8080
|
8
|
+
|
9
|
+
DEFAULT_IFNAME="wlan0"
|
10
|
+
DEFAULT_CAPTURE_PATH="/cap"
|
11
|
+
DEFAULT_LOG_FILE="/var/log/panopticond.log"
|
12
|
+
|
13
|
+
def self.default_options
|
14
|
+
{
|
15
|
+
# config file (exclusive)
|
16
|
+
:config_file => DEFAULT_CONFIG_PATH,
|
17
|
+
|
18
|
+
# daemon parameters
|
19
|
+
:port => DEFAULT_API_PORT,
|
20
|
+
|
21
|
+
# capture parameters
|
22
|
+
:ifname => DEFAULT_IFNAME,
|
23
|
+
:capture_path => DEFAULT_CAPTURE_PATH,
|
24
|
+
|
25
|
+
# log
|
26
|
+
:log_file => DEFAULT_LOG_FILE,
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize arg={}
|
31
|
+
@arg = arg
|
32
|
+
|
33
|
+
@config_file = arg[:config_file]
|
34
|
+
|
35
|
+
@arg = read_config(@config_file)
|
36
|
+
end
|
37
|
+
|
38
|
+
def run
|
39
|
+
Panopticon::APIServer.run!(@arg)
|
40
|
+
end
|
41
|
+
|
42
|
+
def read_config path
|
43
|
+
# notimp
|
44
|
+
@arg
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Log
|
2
|
+
require "logger"
|
3
|
+
def initialize opts={}
|
4
|
+
@debug_mode = opts[:debug_mode] || false
|
5
|
+
@output = opts[:output] || STDOUT
|
6
|
+
|
7
|
+
case @output
|
8
|
+
when "STDOUT"
|
9
|
+
@output = STDOUT
|
10
|
+
when "STDERR"
|
11
|
+
@output = STDERR
|
12
|
+
end
|
13
|
+
@logger = Logger.new(@output)
|
14
|
+
|
15
|
+
@logger.datetime_format = "%Y%m%d%H%m%S"
|
16
|
+
@logger.formatter = proc { |severity, datetime, progname, msg|
|
17
|
+
"[#{datetime}] #{progname}\t#{severity}: #{msg}\n"
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def warn str
|
22
|
+
@logger.warn(str)
|
23
|
+
end
|
24
|
+
|
25
|
+
def err str
|
26
|
+
@logger.error(str)
|
27
|
+
end
|
28
|
+
|
29
|
+
def info str
|
30
|
+
@logger.info(str)
|
31
|
+
end
|
32
|
+
|
33
|
+
def debug str
|
34
|
+
@logger.debug(str)
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
module Panopticon
|
2
|
+
require "open3"
|
3
|
+
require "panopticon/wlan_utilization"
|
4
|
+
|
5
|
+
class WlanCapture
|
6
|
+
attr_reader :duration, :current_channel, :filesize, :channel_walk, :utilization, :utilization_channel
|
7
|
+
CHAN = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
8
|
+
34, 36, 38, 40, 42, 44, 46, 48,
|
9
|
+
52, 56, 60, 64,
|
10
|
+
100, 104, 108, 112, 116,
|
11
|
+
120, 124, 128, 132, 136, 140,
|
12
|
+
149, 153, 157, 161, 165]
|
13
|
+
LIMIT_IDX=CHAN.length
|
14
|
+
|
15
|
+
DEFAULT_IFNAME="wlan0"
|
16
|
+
DEFAULT_INTERVAL=1
|
17
|
+
|
18
|
+
def initialize ifname=DEFAULT_IFNAME, channels=CHAN, interval = DEFAULT_INTERVAL
|
19
|
+
@th_shark = nil
|
20
|
+
@th_capture = nil
|
21
|
+
@black_list = []
|
22
|
+
|
23
|
+
@ifname = ifname || DEFAULT_IFNAME
|
24
|
+
@channels = channels || CHAN
|
25
|
+
@interval = interval || DEFAULT_INTERVAL
|
26
|
+
|
27
|
+
init_status()
|
28
|
+
|
29
|
+
@wlan_utilization = Panopticon::WlanUtilization.new(@ifname)
|
30
|
+
end
|
31
|
+
|
32
|
+
def run_capture fpath
|
33
|
+
init_device()
|
34
|
+
init_status()
|
35
|
+
start_time = Time.now.to_i
|
36
|
+
|
37
|
+
stdin, stdout, stderr, @th_tshark = *Open3.popen3(
|
38
|
+
"tshark -i #{@ifname} -F pcapng -w #{fpath}")
|
39
|
+
|
40
|
+
while @th_tshark.alive?
|
41
|
+
sleep 1
|
42
|
+
|
43
|
+
# update status
|
44
|
+
@duration = Time.now.to_i - start_time
|
45
|
+
@filesize = File.size?(fpath) || 0
|
46
|
+
|
47
|
+
# do something here to run before channel transition
|
48
|
+
ary = @wlan_utilization.current_data()
|
49
|
+
@utilization_channel = ary[0]
|
50
|
+
@utilization = ary[3]
|
51
|
+
|
52
|
+
prev_channel = @current_channel
|
53
|
+
@current_chanenl = move_channel(@current_channel, @channels)
|
54
|
+
@channel_walk += 1
|
55
|
+
$log.debug("channel moved to #{@current_channel} from #{prev_channel} (dur=#{@duration}, size=#{@filesize}, walk=#{@channel_walk}, utilization=#{@utilization} uch=#{@utilization_channel})")
|
56
|
+
end
|
57
|
+
rescue => e
|
58
|
+
$log.warn("run_capture detected unknown error (#{e})")
|
59
|
+
end
|
60
|
+
|
61
|
+
def stop_capture
|
62
|
+
if @th_tshark == nil
|
63
|
+
$log.err("tried to kill tshark, but it's not executed? (or already dead?)")
|
64
|
+
return
|
65
|
+
end
|
66
|
+
|
67
|
+
Process.kill("INT", @th_tshark.pid)
|
68
|
+
end
|
69
|
+
|
70
|
+
def modify_channels channels
|
71
|
+
@channels = channels
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
def init_status
|
76
|
+
@duration = 0
|
77
|
+
@current_channel = @channels[0] || 1
|
78
|
+
@filesize = 0
|
79
|
+
@channel_walk = 0
|
80
|
+
end
|
81
|
+
|
82
|
+
def init_device
|
83
|
+
unless @ifname.match(/^wlan\d+$/)
|
84
|
+
$log.debug("non-wlan device skips device initialization")
|
85
|
+
return
|
86
|
+
end
|
87
|
+
|
88
|
+
unless system("ip link set #{@ifname} down")
|
89
|
+
raise "failed to turn down #{@ifname}"
|
90
|
+
end
|
91
|
+
unless system("iw #{@ifname} set monitor fcsfail otherbss control")
|
92
|
+
raise "failed to set #{@ifname} to monitor mode"
|
93
|
+
end
|
94
|
+
unless system("ip link set #{@ifname} up")
|
95
|
+
raise "failed to turn up #{@ifname}"
|
96
|
+
end
|
97
|
+
unless system("iw wlan0 set channel #{@current_channel}")
|
98
|
+
raise "failed to set channel #{@current_channel} on #{@ifname}"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def move_channel current, channels
|
103
|
+
unless @ifname.match(/^wlan\d+$/)
|
104
|
+
$log.debug("non-wlan device skips channel transition")
|
105
|
+
return
|
106
|
+
end
|
107
|
+
|
108
|
+
next_channel = pick_channel(current, channels)
|
109
|
+
|
110
|
+
while !system("iw #{@ifname} set channel #{next_channel}")
|
111
|
+
# what if we got unplugged ifname? => should we die?
|
112
|
+
$log.debug("channel transition failed, added to black list (channel=#{next_channel})")
|
113
|
+
@black_list << next_channel
|
114
|
+
sleep 1
|
115
|
+
next_channel = pick_channel(next_channel, channels)
|
116
|
+
end
|
117
|
+
|
118
|
+
@current_channel = next_channel
|
119
|
+
end
|
120
|
+
|
121
|
+
def pick_channel current, channels
|
122
|
+
idx = channels.index(current)
|
123
|
+
idx += 1
|
124
|
+
next_channel = channels[idx % channels.length] || 1
|
125
|
+
|
126
|
+
# we have black list
|
127
|
+
while @black_list.include?(next_channel)
|
128
|
+
idx += 1
|
129
|
+
next_channel = channels[idx % channels.length] || 1
|
130
|
+
end
|
131
|
+
|
132
|
+
return next_channel
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,275 @@
|
|
1
|
+
module Panopticon
|
2
|
+
require "json"
|
3
|
+
require "thread"
|
4
|
+
|
5
|
+
require "panopticon/log"
|
6
|
+
require "panopticon/wlan_capture"
|
7
|
+
|
8
|
+
class WlanControl
|
9
|
+
DEFAULT_IFNAME = "wlan0"
|
10
|
+
DEFAULT_CAPTURE_PATH = "/cap"
|
11
|
+
|
12
|
+
STATE_INIT = :INIT
|
13
|
+
STATE_RUNNING = :RUNNING
|
14
|
+
STATE_STOP = :STOP
|
15
|
+
|
16
|
+
def self.default_options
|
17
|
+
return {
|
18
|
+
:ifname => DEFAULT_IFNAME,
|
19
|
+
:capture_path => DEFAULT_CAPTURE_PATH,
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize args={}
|
24
|
+
@th_capture = nil
|
25
|
+
@wlan_capture = nil
|
26
|
+
@state = STATE_INIT
|
27
|
+
|
28
|
+
@ifname = args[:ifname] || DEFAULT_IFNAME
|
29
|
+
$log.debug("hogeeee #{@ifname} #{args[:ifname]}")
|
30
|
+
@capture_path = args[:capture_path] || DEFAULT_CAPTURE_PATH
|
31
|
+
|
32
|
+
@hostname = `hostname`
|
33
|
+
end
|
34
|
+
|
35
|
+
def disk_info
|
36
|
+
line = `df`.split("\n")[1].split # assumes first line to be "/"
|
37
|
+
size = line[1].to_i * 512
|
38
|
+
used = line[2].to_i * 512
|
39
|
+
|
40
|
+
return {:size => size, :used => used }
|
41
|
+
end
|
42
|
+
|
43
|
+
def memory_info
|
44
|
+
if File.exists?("/proc/meminfo")
|
45
|
+
# linux or bsd
|
46
|
+
return memory_info_from_proc
|
47
|
+
else
|
48
|
+
# mac os x ?
|
49
|
+
return memory_info_from_mac
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def memory_info_from_proc
|
54
|
+
total = 0
|
55
|
+
free = 0
|
56
|
+
used = 0
|
57
|
+
File.open("/proc/meminfo") do |file|
|
58
|
+
total = file.gets.split[1].to_i
|
59
|
+
free = file.gets.split[1].to_i
|
60
|
+
used = total - free
|
61
|
+
end
|
62
|
+
|
63
|
+
return {:size => total, :used => used}
|
64
|
+
end
|
65
|
+
|
66
|
+
def memory_info_from_mac
|
67
|
+
_, total = `sysctl hw.memsize`.split.map{|n| n.to_i}
|
68
|
+
|
69
|
+
used = 0
|
70
|
+
app_mem = 0
|
71
|
+
comp_mem = 0
|
72
|
+
file_backed_mem = 0
|
73
|
+
`vm_stat`.split("\n").each do |line|
|
74
|
+
match = line.match(/^Anonymous pages: *(\d+)\.$/)
|
75
|
+
if match
|
76
|
+
app_mem = match[1].to_i * 4096
|
77
|
+
end
|
78
|
+
|
79
|
+
match = line.match(/^Pages occupied by compressor: *(\d+)\.$/)
|
80
|
+
if match
|
81
|
+
comp_mem = match[1].to_i * 4096
|
82
|
+
end
|
83
|
+
|
84
|
+
match = line.match(/^File-backed pages: *(\d+)\.$/)
|
85
|
+
if match
|
86
|
+
file_backed_mem = match[1].to_i * 4096
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
used = (app_mem + comp_mem + file_backed_mem)
|
91
|
+
|
92
|
+
return {:size => total, :used => used}
|
93
|
+
end
|
94
|
+
|
95
|
+
def cpu_info
|
96
|
+
if File.exists?("/proc/stat")
|
97
|
+
return cpu_info_from_proc
|
98
|
+
else
|
99
|
+
return cpu_info_from_mac
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def cpu_info_from_proc
|
104
|
+
used = 0
|
105
|
+
|
106
|
+
current_cpu_info = []
|
107
|
+
File.open("/proc/stat") do |file|
|
108
|
+
current_cpu_info = file.gets.split[1..4].map{|elm| elm.to_i}
|
109
|
+
end
|
110
|
+
|
111
|
+
if @prev_cpu_info == nil
|
112
|
+
@prev_cpu_info = current_cpu_info
|
113
|
+
return 0
|
114
|
+
end
|
115
|
+
|
116
|
+
usage_sub = current_cpu_info[0..2].inject(0){|sum, elm| sum += elm} -
|
117
|
+
@prev_cpu_info[0..2].inject(0){|sum, elm| sum += elm}
|
118
|
+
total_sub = current_cpu_info.inject(0){|sum, elm| sum += elm} -
|
119
|
+
@prev_cpu_info.inject(0){|sum, elm| sum += elm}
|
120
|
+
|
121
|
+
@prev_cpu_info = current_cpu_info
|
122
|
+
|
123
|
+
used = ((usage_sub.to_f * 100) / total_sub)
|
124
|
+
|
125
|
+
return used
|
126
|
+
end
|
127
|
+
|
128
|
+
def cpu_info_from_mac
|
129
|
+
line = `top | head -4 | grep CPU`
|
130
|
+
match = line.match(/^CPU usage: *(\d+\.\d+)% user, *(\d+\.\d+)% sys, *(\d+\.\d+)% idle $/)
|
131
|
+
return 0.0 unless match
|
132
|
+
|
133
|
+
user = match[1].to_f
|
134
|
+
sys = match[2].to_f
|
135
|
+
idle = match[3].to_f
|
136
|
+
used = 100 - idle
|
137
|
+
|
138
|
+
return used
|
139
|
+
end
|
140
|
+
|
141
|
+
def capture_file_info
|
142
|
+
filesize = 0
|
143
|
+
duration = 0
|
144
|
+
|
145
|
+
if @wlan_capture
|
146
|
+
filesize = @wlan_capture.filesize
|
147
|
+
duration = @wlan_capture.duration
|
148
|
+
end
|
149
|
+
|
150
|
+
return {
|
151
|
+
:filename => @filename,
|
152
|
+
:filesize => filesize,
|
153
|
+
:duration => duration,
|
154
|
+
}
|
155
|
+
end
|
156
|
+
|
157
|
+
def wlan_info
|
158
|
+
info = {
|
159
|
+
:current_channel => 0,
|
160
|
+
:channel_walk => 0,
|
161
|
+
:utilization => 0,
|
162
|
+
:utilization_channel => 0,
|
163
|
+
}
|
164
|
+
|
165
|
+
unless @state == STATE_RUNNING
|
166
|
+
return info
|
167
|
+
end
|
168
|
+
|
169
|
+
if @wlan_capture.nil?
|
170
|
+
$log.err("state mismatch (state = #{@state} <=> capture is running");
|
171
|
+
return
|
172
|
+
end
|
173
|
+
|
174
|
+
info[:current_channel] = @wlan_capture.current_channel
|
175
|
+
info[:channel_walk] = @wlan_capture.channel_walk
|
176
|
+
info[:utilization] = @wlan_capture.utilization
|
177
|
+
info[:utilization_channel] = @wlan_capture.utilization_channel
|
178
|
+
|
179
|
+
return info
|
180
|
+
end
|
181
|
+
|
182
|
+
def generate_filename
|
183
|
+
return "#{Time.now.strftime("%Y%m%d%H%m%S")}_#{@ifname}_#{$$}.pcapng"
|
184
|
+
end
|
185
|
+
|
186
|
+
# request handler for API
|
187
|
+
def start_capture arg
|
188
|
+
$log.info("starting new capture")
|
189
|
+
|
190
|
+
if @state == STATE_RUNNING
|
191
|
+
$log.warn("WlanCapture instance is already running")
|
192
|
+
return
|
193
|
+
end
|
194
|
+
|
195
|
+
if @th_capture
|
196
|
+
$log.warn("capture thread is already running, terminate it first")
|
197
|
+
return
|
198
|
+
end
|
199
|
+
|
200
|
+
if @wlan_capture
|
201
|
+
$log.warn("capture instance is running, teminate it first")
|
202
|
+
return
|
203
|
+
end
|
204
|
+
|
205
|
+
$log.info("starting new capture instance")
|
206
|
+
@wlan_capture = Panopticon::WlanCapture.new(@ifname)
|
207
|
+
|
208
|
+
# start capturing
|
209
|
+
filename = generate_filename()
|
210
|
+
@th_capture = Thread.new do
|
211
|
+
@wlan_capture.run_capture("#{@capture_path}/#{filename}")
|
212
|
+
end
|
213
|
+
$log.info("started new capture at #{filename}")
|
214
|
+
|
215
|
+
# move state
|
216
|
+
@state = STATE_RUNNING
|
217
|
+
@filename = filename
|
218
|
+
end
|
219
|
+
|
220
|
+
def stop_capture
|
221
|
+
if @state == STATE_INIT or @state == STATE_STOP
|
222
|
+
$log.err("stopping not runnning capture instance")
|
223
|
+
return
|
224
|
+
end
|
225
|
+
|
226
|
+
if @wlan_capture
|
227
|
+
@wlan_capture.stop_capture
|
228
|
+
end
|
229
|
+
|
230
|
+
if @th_capture and @th_capture.alive?
|
231
|
+
$log.info("stopping capture thread")
|
232
|
+
@th_capture.join
|
233
|
+
end
|
234
|
+
|
235
|
+
@wlan_capture = nil
|
236
|
+
@th_capture = nil
|
237
|
+
|
238
|
+
@state = STATE_STOP
|
239
|
+
end
|
240
|
+
|
241
|
+
def change_channels arg
|
242
|
+
end
|
243
|
+
|
244
|
+
def get_config
|
245
|
+
end
|
246
|
+
|
247
|
+
def get_status
|
248
|
+
@cached_disk_info = disk_info()
|
249
|
+
@cached_memory_info = memory_info()
|
250
|
+
@cached_cpu_info = cpu_info()
|
251
|
+
@cached_file_info = capture_file_info()
|
252
|
+
@cached_wlan_info = wlan_info()
|
253
|
+
|
254
|
+
return {
|
255
|
+
:date => Time.now.to_i,
|
256
|
+
:hostname => @hostname,
|
257
|
+
:disk_size => @cached_disk_info[:size],
|
258
|
+
:disk_used => @cached_disk_info[:used],
|
259
|
+
:memory_size => @cached_memory_info[:size],
|
260
|
+
:memory_used => @cached_memory_info[:used],
|
261
|
+
:cpu_usage => @cached_cpu_info,
|
262
|
+
|
263
|
+
:state => @state,
|
264
|
+
:filename => @filename,
|
265
|
+
:filesize => @cached_file_info[:filesize],
|
266
|
+
:duration => @cached_file_info[:duration],
|
267
|
+
|
268
|
+
:current_channel => @cached_wlan_info[:current_channel],
|
269
|
+
:channel_walk => @cached_wlan_info[:channel_walk],
|
270
|
+
:utilization => @cached_wlan_info[:utilization],
|
271
|
+
:utilization_channel => @cached_wlan_info[:utilization_channel],
|
272
|
+
}
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|