smartware 0.4.5 → 0.4.6
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.
- 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
|