smartware 0.4.5 → 0.4.6
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/smartware +4 -4
- data/bin/smartware-monitor +10 -2
- data/bin/smartware-ppp-helper +9 -4
- data/lib/smartware.rb +1 -0
- data/lib/smartware/drivers/modem/standard.rb +90 -41
- data/lib/smartware/interfaces/interface.rb +14 -0
- data/lib/smartware/interfaces/modem.rb +8 -1
- data/lib/smartware/pub_sub_client.rb +48 -3
- data/lib/smartware/pub_sub_server.rb +43 -1
- data/lib/smartware/service.rb +25 -5
- data/lib/smartware/version.rb +1 -1
- data/smartware.gemspec +1 -0
- metadata +18 -2
data/bin/smartware
CHANGED
@@ -21,11 +21,11 @@ begin
|
|
21
21
|
|
22
22
|
Smartware::Logging.logger.info "Initializing Smartware"
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
[ 'INT', 'TERM' ].each do |sig|
|
25
|
+
trap(sig) { service.stop }
|
26
|
+
end
|
27
27
|
|
28
|
-
service.
|
28
|
+
service.start
|
29
29
|
rescue => e
|
30
30
|
Smartware::Logging.logger.error e.message
|
31
31
|
Smartware::Logging.logger.error e.backtrace.join("\n")
|
data/bin/smartware-monitor
CHANGED
@@ -5,8 +5,16 @@ require 'bundler/setup'
|
|
5
5
|
require 'smartware'
|
6
6
|
|
7
7
|
EventMachine.run do
|
8
|
-
Smartware.subscribe do |
|
9
|
-
|
8
|
+
Smartware.subscribe do |message|
|
9
|
+
print "#{message.key}"
|
10
|
+
|
11
|
+
if message.reliable?
|
12
|
+
print " (reliable, #{message.id})"
|
13
|
+
end
|
14
|
+
|
15
|
+
puts ": #{message.args.map(&:inspect).join(", ")}"
|
16
|
+
|
17
|
+
message.acknowlege if ARGV[0] == "ack" && message.reliable?
|
10
18
|
end
|
11
19
|
|
12
20
|
puts "Receiving Smartware events."
|
data/bin/smartware-ppp-helper
CHANGED
@@ -29,11 +29,16 @@ ensure
|
|
29
29
|
io.close
|
30
30
|
end
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
cmdline = [
|
33
|
+
"/usr/sbin/pppd", device, "115200",
|
34
|
+
"nodetach", "logfd", "2", "file", "/etc/ppp/options"
|
35
|
+
]
|
36
|
+
|
37
|
+
cmdline.unshift "sudo" if Process.euid != 0
|
38
|
+
|
39
|
+
Process.exec *cmdline,
|
35
40
|
pgroup: true,
|
36
41
|
in: :close,
|
37
42
|
out: :close,
|
38
|
-
err: :
|
43
|
+
err: :err,
|
39
44
|
close_others: true
|
data/lib/smartware.rb
CHANGED
@@ -6,7 +6,38 @@ module Smartware
|
|
6
6
|
module Modem
|
7
7
|
|
8
8
|
class Standard
|
9
|
+
class LogConnection < EventMachine::Connection
|
10
|
+
include EventMachine::Protocols::LineProtocol
|
11
|
+
|
12
|
+
def initialize(device)
|
13
|
+
@device = device
|
14
|
+
end
|
15
|
+
|
16
|
+
def receive_line(line)
|
17
|
+
line.rstrip!
|
18
|
+
|
19
|
+
Logging.logger.debug "pppd: #{line}"
|
20
|
+
|
21
|
+
if line =~ /^Sent ([0-9]+) bytes, received ([0-9]+) bytes.$/
|
22
|
+
@sent = $1.to_i
|
23
|
+
@received = $2.to_i
|
24
|
+
elsif line =~ /^Connect time ([0-9.]+) minutes.$/
|
25
|
+
@time = ($1.to_f * 60).round
|
26
|
+
elsif line == "Connection terminated."
|
27
|
+
begin
|
28
|
+
@device.account.call @sent, @received, @time
|
29
|
+
ensure
|
30
|
+
@sent = nil
|
31
|
+
@received = nil
|
32
|
+
@time = nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
9
39
|
attr_reader :error, :model, :balance, :version
|
40
|
+
attr_accessor :account
|
10
41
|
|
11
42
|
def initialize(config)
|
12
43
|
@port = config["port"]
|
@@ -29,6 +60,25 @@ module Smartware
|
|
29
60
|
@balance = nil
|
30
61
|
@ppp_state = :stopped
|
31
62
|
@ppp_pid = nil
|
63
|
+
@shutdown = false
|
64
|
+
@account = nil
|
65
|
+
|
66
|
+
logpipe_smartware, @logpipe_ppp = IO.pipe
|
67
|
+
EventMachine.attach logpipe_smartware, LogConnection, self
|
68
|
+
end
|
69
|
+
|
70
|
+
def shutdown(callback)
|
71
|
+
@shutdown_callback = callback
|
72
|
+
|
73
|
+
Logging.logger.info "stopping modem gracefully"
|
74
|
+
@shutdown = true
|
75
|
+
@shutdown_timer = EventMachine.add_periodic_timer(0.5) do
|
76
|
+
if @state == :closed && @ppp_state == :stopped
|
77
|
+
Logging.logger.info "modem stopped"
|
78
|
+
EventMachine.cancel_timer @shutdown_timer
|
79
|
+
@shutdown_callback.call
|
80
|
+
end
|
81
|
+
end
|
32
82
|
end
|
33
83
|
|
34
84
|
def signal_level
|
@@ -43,7 +93,7 @@ module Smartware
|
|
43
93
|
|
44
94
|
wait_for_event
|
45
95
|
rescue => e
|
46
|
-
|
96
|
+
Logging.logger.error "uncatched exception in modem monitor: #{e}"
|
47
97
|
end
|
48
98
|
end
|
49
99
|
|
@@ -56,7 +106,7 @@ module Smartware
|
|
56
106
|
|
57
107
|
def ussd(mode, string = nil, dcs = nil)
|
58
108
|
if mode != "0"
|
59
|
-
|
109
|
+
Logging.logger.warn "USSD completed with mode #{mode}, expected 0"
|
60
110
|
end
|
61
111
|
|
62
112
|
if string
|
@@ -74,19 +124,21 @@ module Smartware
|
|
74
124
|
def modem_tick
|
75
125
|
case @state
|
76
126
|
when :closed
|
77
|
-
|
127
|
+
if !@shutdown
|
128
|
+
Logging.logger.info "trying to open modem"
|
78
129
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
130
|
+
begin
|
131
|
+
@mux = CMUX::MUX.new @port
|
132
|
+
@state = :open
|
133
|
+
@status_channel = @mux.allocate(@status_channel_id).open
|
134
|
+
@chatter = CMUX::ModemChatter.new @status_channel
|
135
|
+
@chatter.subscribe "CUSD", self
|
136
|
+
@error = nil
|
137
|
+
@balance_timer = 0
|
138
|
+
Logging.logger.info "modem ready"
|
139
|
+
rescue => e
|
140
|
+
close_modem "unable to open modem: #{e}"
|
141
|
+
end
|
90
142
|
end
|
91
143
|
|
92
144
|
when :open
|
@@ -110,7 +162,9 @@ module Smartware
|
|
110
162
|
end
|
111
163
|
|
112
164
|
if modem_works
|
113
|
-
if
|
165
|
+
if @shutdown && @ppp_state == :stopped
|
166
|
+
close_modem "service shutdown"
|
167
|
+
elsif !@balance_ussd.nil? && @balance_timer == 0
|
114
168
|
@balance_timer = @balance_interval
|
115
169
|
begin
|
116
170
|
@chatter.command("+CUSD=1,\"#{@balance_ussd}\",15", 1)
|
@@ -129,43 +183,45 @@ module Smartware
|
|
129
183
|
def ppp_tick
|
130
184
|
case @ppp_state
|
131
185
|
when :stopped
|
132
|
-
if @state == :open
|
133
|
-
|
186
|
+
if @state == :open && !@shutdown
|
187
|
+
Logging.logger.info "trying to start pppd"
|
134
188
|
begin
|
135
189
|
@ppp_channel = @mux.allocate @ppp_channel_id
|
136
190
|
|
137
191
|
@ppp_pid = Process.spawn "smartware-ppp-helper",
|
138
192
|
@ppp_channel.device,
|
139
|
-
@apn
|
193
|
+
@apn,
|
194
|
+
err: @logpipe_ppp
|
140
195
|
@ppp_state = :running
|
141
196
|
|
142
|
-
|
143
|
-
|
197
|
+
Logging.logger.info "started pppd, PID #{@ppp_pid}"
|
198
|
+
ProcessManager.track @ppp_pid, method(:ppp_died)
|
144
199
|
|
145
200
|
rescue => e
|
146
|
-
|
147
|
-
@ppp_channel.close
|
148
|
-
rescue
|
149
|
-
end
|
201
|
+
@ppp_channel.close rescue nil
|
150
202
|
|
151
203
|
@ppp_channel = nil
|
152
204
|
@ppp_pid = nil
|
153
205
|
@ppp_state = :stopped
|
154
206
|
|
155
|
-
|
207
|
+
Logging.logger.warn "cannot start pppd: #{e.to_s}"
|
156
208
|
end
|
157
209
|
end
|
158
210
|
|
159
211
|
when :running
|
160
212
|
if @ppp_pid.nil?
|
161
|
-
|
162
|
-
|
163
|
-
@ppp_channel.close
|
164
|
-
rescue
|
165
|
-
end
|
213
|
+
Logging.logger.warn "pppd died"
|
214
|
+
@ppp_channel.close rescue nil
|
166
215
|
|
167
216
|
@ppp_channel = nil
|
168
217
|
@ppp_state = :stopped
|
218
|
+
elsif @shutdown
|
219
|
+
Logging.logger.debug "Terminating pppd #{@ppp_pid}"
|
220
|
+
if Process.euid == 0
|
221
|
+
Process.kill 'TERM', @ppp_pid
|
222
|
+
else
|
223
|
+
system "sudo", "kill", "-TERM", @ppp_pid.to_s
|
224
|
+
end
|
169
225
|
end
|
170
226
|
end
|
171
227
|
end
|
@@ -189,19 +245,12 @@ module Smartware
|
|
189
245
|
end
|
190
246
|
|
191
247
|
def close_modem(reason)
|
192
|
-
|
248
|
+
Logging.logger.warn "#{reason}"
|
193
249
|
|
194
250
|
@error = Interface::Modem::MODEM_NOT_AVAILABLE
|
195
251
|
|
196
|
-
|
197
|
-
|
198
|
-
rescue
|
199
|
-
end
|
200
|
-
|
201
|
-
begin
|
202
|
-
@chatter.unsubscribe "CUSD", self
|
203
|
-
rescue
|
204
|
-
end
|
252
|
+
@mux.close rescue nil
|
253
|
+
@chatter.unsubscribe "CUSD", self rescue nil
|
205
254
|
|
206
255
|
@info_requested = false
|
207
256
|
@mux = nil
|
@@ -209,7 +258,7 @@ module Smartware
|
|
209
258
|
@status_channel = nil
|
210
259
|
@ppp_state = :stopped
|
211
260
|
unless @ppp_pid.nil?
|
212
|
-
|
261
|
+
ProcessManager.untrack @ppp_pid
|
213
262
|
@ppp_pid = nil # PPP will die by itself, because we closed the mux.
|
214
263
|
end
|
215
264
|
@state = :closed
|
@@ -26,6 +26,16 @@ module Smartware
|
|
26
26
|
.new(config)
|
27
27
|
end
|
28
28
|
|
29
|
+
def shutdown(callback)
|
30
|
+
if @device.respond_to? :shutdown
|
31
|
+
@device.shutdown callback
|
32
|
+
|
33
|
+
true
|
34
|
+
else
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
29
39
|
def repush_events(connection)
|
30
40
|
@status_mutex.synchronize do
|
31
41
|
@status.each do |key, value|
|
@@ -64,6 +74,10 @@ module Smartware
|
|
64
74
|
def publish_event(key, *data)
|
65
75
|
@service.publish_event "#{@iface_id}.#{key}", *data
|
66
76
|
end
|
77
|
+
|
78
|
+
def publish_reliable_event(key, *data)
|
79
|
+
@service.publish_reliable_event "#{@iface_id}.#{key}", *data
|
80
|
+
end
|
67
81
|
end
|
68
82
|
end
|
69
83
|
end
|
@@ -6,11 +6,12 @@ module Smartware
|
|
6
6
|
def initialize(config, service)
|
7
7
|
super
|
8
8
|
|
9
|
+
@device.account = method(:account)
|
10
|
+
|
9
11
|
update_status :balance, ''
|
10
12
|
update_status :signal_level, ''
|
11
13
|
|
12
14
|
@session = Thread.new &method(:poll)
|
13
|
-
Smartware::Logging.logger.info 'Modem monitor started'
|
14
15
|
end
|
15
16
|
|
16
17
|
def balance
|
@@ -39,6 +40,12 @@ module Smartware
|
|
39
40
|
Smartware::Logging.logger.error e.backtrace.join("\n")
|
40
41
|
end
|
41
42
|
end
|
43
|
+
|
44
|
+
def account(sent, received, time)
|
45
|
+
Smartware::Logging.logger.debug "recording session: #{sent} upstream #{received} downstream, #{time} seconds"
|
46
|
+
|
47
|
+
publish_reliable_event 'accounting', sent, received, time
|
48
|
+
end
|
42
49
|
end
|
43
50
|
end
|
44
51
|
end
|
@@ -2,6 +2,39 @@ require "em/protocols/line_protocol"
|
|
2
2
|
|
3
3
|
module Smartware
|
4
4
|
class PubSubClient
|
5
|
+
class Message
|
6
|
+
attr_reader :key, :args
|
7
|
+
|
8
|
+
def initialize(reliable_id, key, args, callback)
|
9
|
+
@reliable_id = reliable_id
|
10
|
+
@key = key
|
11
|
+
@args = args
|
12
|
+
@callback = callback
|
13
|
+
end
|
14
|
+
|
15
|
+
def reliable?
|
16
|
+
!@reliable_id.nil?
|
17
|
+
end
|
18
|
+
|
19
|
+
def id
|
20
|
+
@reliable_id
|
21
|
+
end
|
22
|
+
|
23
|
+
def acknowlege
|
24
|
+
raise "message is not reliable" if @reliable_id.nil?
|
25
|
+
|
26
|
+
@callback.call @reliable_id
|
27
|
+
end
|
28
|
+
|
29
|
+
def [](index)
|
30
|
+
@args[index]
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_a
|
34
|
+
@args
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
5
38
|
class PubSubHandler < EventMachine::Connection
|
6
39
|
include EventMachine::Protocols::LineProtocol
|
7
40
|
|
@@ -16,7 +49,11 @@ module Smartware
|
|
16
49
|
def receive_line(line)
|
17
50
|
data = JSON.load line
|
18
51
|
|
19
|
-
@client.
|
52
|
+
@client.receive data
|
53
|
+
end
|
54
|
+
|
55
|
+
def send_record(data)
|
56
|
+
send_data(JSON.dump(data) + "\r\n")
|
20
57
|
end
|
21
58
|
end
|
22
59
|
|
@@ -55,8 +92,16 @@ module Smartware
|
|
55
92
|
@reconnect_timer = EventMachine.add_timer 1, &method(:attempt)
|
56
93
|
end
|
57
94
|
|
58
|
-
def
|
59
|
-
|
95
|
+
def receive(data)
|
96
|
+
message = Message.new data["reliable_id"],
|
97
|
+
data["key"],
|
98
|
+
data["args"],
|
99
|
+
->(id) do
|
100
|
+
|
101
|
+
@connection.send_record command: "acknowlege", id: id
|
102
|
+
end
|
103
|
+
|
104
|
+
@receiver.call message
|
60
105
|
end
|
61
106
|
|
62
107
|
private
|
@@ -1,6 +1,10 @@
|
|
1
|
+
require "em/protocols/line_protocol"
|
2
|
+
|
1
3
|
module Smartware
|
2
4
|
class PubSubServer
|
3
5
|
class PubSubConnection < EventMachine::Connection
|
6
|
+
include EventMachine::Protocols::LineProtocol
|
7
|
+
|
4
8
|
def initialize(server)
|
5
9
|
@server = server
|
6
10
|
end
|
@@ -13,13 +17,30 @@ module Smartware
|
|
13
17
|
@server.remove_connection self
|
14
18
|
end
|
15
19
|
|
16
|
-
def
|
20
|
+
def receive_line(line)
|
21
|
+
begin
|
22
|
+
data = JSON.load line
|
17
23
|
|
24
|
+
case data["command"]
|
25
|
+
when "acknowlege"
|
26
|
+
@server.acknowlege_reliable data["id"]
|
27
|
+
|
28
|
+
else
|
29
|
+
raise "unsupported command #{data["command"]}"
|
30
|
+
end
|
31
|
+
rescue => e
|
32
|
+
Logging.logger.warn e.to_s
|
33
|
+
e.backtrace.each { |line| Logging.logger.warn line }
|
34
|
+
end
|
18
35
|
end
|
19
36
|
|
20
37
|
def publish_event(key, *args)
|
21
38
|
send_data(JSON.dump({ key: key, args: args }) + "\r\n")
|
22
39
|
end
|
40
|
+
|
41
|
+
def publish_reliable_event(id, key, *args)
|
42
|
+
send_data(JSON.dump({ reliable_id: id, key: key, args: args }) + "\r\n")
|
43
|
+
end
|
23
44
|
end
|
24
45
|
|
25
46
|
attr_accessor :repush
|
@@ -27,6 +48,7 @@ module Smartware
|
|
27
48
|
def initialize(host, port)
|
28
49
|
@repush = nil
|
29
50
|
@connections = Set.new
|
51
|
+
@redis = Redis.new
|
30
52
|
|
31
53
|
EventMachine.start_server host, port, PubSubConnection, self
|
32
54
|
end
|
@@ -34,6 +56,12 @@ module Smartware
|
|
34
56
|
def add_connection(connection)
|
35
57
|
@connections.add connection
|
36
58
|
@repush.call connection
|
59
|
+
|
60
|
+
@redis.hgetall("smartware:reliable_events").each do |key, data|
|
61
|
+
data = JSON.load(data)
|
62
|
+
|
63
|
+
connection.publish_reliable_event key, data["key"], data["args"]
|
64
|
+
end
|
37
65
|
end
|
38
66
|
|
39
67
|
def remove_connection(connection)
|
@@ -45,5 +73,19 @@ module Smartware
|
|
45
73
|
connection.publish_event key, *args
|
46
74
|
end
|
47
75
|
end
|
76
|
+
|
77
|
+
def publish_reliable_event(key, *args)
|
78
|
+
id = (Time.now.to_f * 1000000).round.to_s
|
79
|
+
|
80
|
+
@redis.hset "smartware:reliable_events", id, JSON.dump({ key: key, args: args })
|
81
|
+
|
82
|
+
@connections.each do |connection|
|
83
|
+
connection.publish_reliable_event id, key, args
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def acknowlege_reliable(id)
|
88
|
+
@redis.hdel "smartware:reliable_events", id
|
89
|
+
end
|
48
90
|
end
|
49
91
|
end
|
data/lib/smartware/service.rb
CHANGED
@@ -6,6 +6,7 @@ module Smartware
|
|
6
6
|
@config = YAML.load File.read(config_file)
|
7
7
|
@interfaces = []
|
8
8
|
@devices = []
|
9
|
+
@shutdown_holders = 0
|
9
10
|
end
|
10
11
|
|
11
12
|
def start
|
@@ -16,6 +17,11 @@ module Smartware
|
|
16
17
|
@pubsub.publish_event key, *args
|
17
18
|
end
|
18
19
|
|
20
|
+
@reliable_event_channel = EventMachine::Channel.new
|
21
|
+
@reliable_event_channel.subscribe do |(key, args)|
|
22
|
+
@pubsub.publish_reliable_event key, *args
|
23
|
+
end
|
24
|
+
|
19
25
|
@pubsub = PubSubServer.new "localhost", (@config["pubsub_port"] || 6100)
|
20
26
|
@pubsub.repush = ->(connection) do
|
21
27
|
@devices.each do |device|
|
@@ -51,16 +57,30 @@ module Smartware
|
|
51
57
|
@event_channel.push [key, args]
|
52
58
|
end
|
53
59
|
|
60
|
+
def publish_reliable_event(key, *args)
|
61
|
+
@reliable_event_channel.push [key, args]
|
62
|
+
end
|
63
|
+
|
54
64
|
def stop
|
55
65
|
@interfaces.each &:stop_service
|
56
66
|
|
57
|
-
|
58
|
-
end
|
67
|
+
callback = method :decr_shutdown_holders
|
59
68
|
|
60
|
-
|
61
|
-
|
62
|
-
|
69
|
+
@devices.each do |interface|
|
70
|
+
if interface.shutdown callback
|
71
|
+
@shutdown_holders += 1
|
72
|
+
end
|
63
73
|
end
|
74
|
+
|
75
|
+
EventMachine.stop if @shutdown_holders == 0
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def decr_shutdown_holders
|
81
|
+
@shutdown_holders -= 1
|
82
|
+
|
83
|
+
EventMachine.stop if @shutdown_holders == 0
|
64
84
|
end
|
65
85
|
end
|
66
86
|
end
|
data/lib/smartware/version.rb
CHANGED
data/smartware.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smartware
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2013-02-
|
14
|
+
date: 2013-02-16 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: smartkiosk-common
|
@@ -173,6 +173,22 @@ dependencies:
|
|
173
173
|
- - ! '>='
|
174
174
|
- !ruby/object:Gem::Version
|
175
175
|
version: '0'
|
176
|
+
- !ruby/object:Gem::Dependency
|
177
|
+
name: redis
|
178
|
+
requirement: !ruby/object:Gem::Requirement
|
179
|
+
none: false
|
180
|
+
requirements:
|
181
|
+
- - ! '>='
|
182
|
+
- !ruby/object:Gem::Version
|
183
|
+
version: '0'
|
184
|
+
type: :runtime
|
185
|
+
prerelease: false
|
186
|
+
version_requirements: !ruby/object:Gem::Requirement
|
187
|
+
none: false
|
188
|
+
requirements:
|
189
|
+
- - ! '>='
|
190
|
+
- !ruby/object:Gem::Version
|
191
|
+
version: '0'
|
176
192
|
description: Smartware is the Smartkiosk hardware control daemon
|
177
193
|
email:
|
178
194
|
- e.sudarchikov@roundlake.ru
|