bolt_train_runner 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/bolt_train_runner.rb +27 -27
- data/lib/bolt_train_runner/commands/connect.rb +12 -10
- data/lib/bolt_train_runner/commands/debug.rb +8 -8
- data/lib/bolt_train_runner/commands/disconnect.rb +4 -4
- data/lib/bolt_train_runner/commands/exit.rb +4 -3
- data/lib/bolt_train_runner/commands/move.rb +16 -15
- data/lib/bolt_train_runner/commands/power.rb +8 -8
- data/lib/bolt_train_runner/commands/sessions.rb +15 -13
- data/lib/bolt_train_runner/commands/stop.rb +4 -4
- data/lib/bolt_train_runner/commands/throttle.rb +10 -10
- data/lib/bolt_train_runner/comms.rb +11 -10
- data/lib/bolt_train_runner/conf.rb +3 -1
- data/lib/bolt_train_runner/log.rb +99 -0
- data/lib/bolt_train_runner/session_runner.rb +9 -7
- data/lib/bolt_train_runner/version.rb +1 -1
- data/lib/websocket-client-simple.rb +17 -0
- data/lib/websocket-client-simple/client.rb +107 -0
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0e80ec83f70924cb436ed6b458742180e1427d50e749485f2e4dac40bd61b4e5
|
4
|
+
data.tar.gz: 8df15fb1607cfd47767ebe616e6bbc4742da7b5a20793962a4d7a49424fc94b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c0294c14f12dbec5b0e7889535c135ead63b426c2a72db2add19e495169d90c5a85e9c375d4c918dd34b4bbb96aaad03ed4514f8c859d8197275c3e34c01dc06
|
7
|
+
data.tar.gz: d1229742d9593cc036830cbf2bd089d3f1cbb99945bdc0e0e4853a5ea92cadd60d074d1060f0ac3708f62f00e1319bd16512e59c5effa8602cec8611d60808fc
|
data/lib/bolt_train_runner.rb
CHANGED
@@ -4,6 +4,7 @@ require 'rubygems'
|
|
4
4
|
require 'colorize'
|
5
5
|
require 'bolt_train_runner/comms'
|
6
6
|
require 'bolt_train_runner/session_runner'
|
7
|
+
require 'bolt_train_runner/log'
|
7
8
|
|
8
9
|
# Load all commands
|
9
10
|
Dir[File.join(File.absolute_path(__dir__) + '/bolt_train_runner/commands') + "/**/*.rb"].each do |file|
|
@@ -12,13 +13,11 @@ end
|
|
12
13
|
|
13
14
|
# TODO:
|
14
15
|
# Add a lot more error handling
|
15
|
-
# Add thread for consuming session files and issuing commands
|
16
16
|
# Figure out best way to verify commands worked given that responses from JMRI are async
|
17
17
|
# Figure out why it gets multiple messages back each time
|
18
18
|
# Make debug output show what method/command the output is from
|
19
19
|
# Make debug output not screw with the console prompt
|
20
|
-
#
|
21
|
-
# Add a way to log to a file in addition to the console
|
20
|
+
# Add more user control over logging (where it goes, log level, etc.)
|
22
21
|
|
23
22
|
|
24
23
|
class BoltTrainRunner
|
@@ -26,59 +25,60 @@ class BoltTrainRunner
|
|
26
25
|
def run
|
27
26
|
comms = nil
|
28
27
|
session_runner = nil
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
log = Log.new
|
29
|
+
log.help('Welcome to the Bolty McBoltTrain Runner! Choo choo!')
|
30
|
+
log.help('To list all commands, enter "help"')
|
31
|
+
log.help('For help with a specific command, enter "<command> help"')
|
32
|
+
log.help('First order of business: run "connect" to connect to the JMRI server')
|
33
|
+
|
33
34
|
loop do
|
34
35
|
print '> '
|
35
36
|
input = gets.chomp
|
36
37
|
args = input.split(' ')
|
37
38
|
command = args.shift
|
39
|
+
log.info_file("Console command: #{input}")
|
38
40
|
|
39
41
|
case command
|
40
42
|
when /^help$/i
|
41
|
-
help
|
42
|
-
when Commands.respond_to?(command)
|
43
|
-
puts 'Commands can run this'
|
43
|
+
help(log)
|
44
44
|
when /^connect$/i
|
45
|
-
newcomms = Commands.connect(args)
|
45
|
+
newcomms = Commands.connect(args, log)
|
46
46
|
comms = newcomms if newcomms
|
47
47
|
when /^disconnect$/i
|
48
48
|
session_runner.stop if session_runner
|
49
49
|
session_runner = nil
|
50
|
-
Commands.disconnect(comms)
|
50
|
+
Commands.disconnect(comms, log)
|
51
51
|
comms = nil
|
52
52
|
when /^sessions$/i
|
53
|
-
session_runner = Commands.sessions(args, comms, session_runner)
|
53
|
+
session_runner = Commands.sessions(args, comms, session_runner, log)
|
54
54
|
when /^debug$/i
|
55
|
-
Commands.debug(args)
|
55
|
+
Commands.debug(args, log)
|
56
56
|
when /^exit$/i
|
57
|
-
Commands.exit_program(comms, session_runner)
|
57
|
+
Commands.exit_program(comms, session_runner, log)
|
58
58
|
else
|
59
59
|
if Commands.respond_to?(command)
|
60
60
|
# The commands for directly manipulating the train should all
|
61
61
|
# accept "args" and "comms" parameters. Because the CLI will pass
|
62
62
|
# in args as an array and the session runner will pass in a hash,
|
63
63
|
# these commands must be able to handle both.
|
64
|
-
Commands.send(command.to_sym, args, comms)
|
64
|
+
Commands.send(command.to_sym, args, comms, log)
|
65
65
|
else
|
66
|
-
|
66
|
+
log.warn("Unknown command: #{command}")
|
67
67
|
end
|
68
68
|
end
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
-
def help
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
72
|
+
def help(log)
|
73
|
+
log.help('Available commands:')
|
74
|
+
log.help('help - This help text')
|
75
|
+
log.help('connect - Connect to the Bolt Train JMRI JSON server')
|
76
|
+
log.help('disconnect - Disconnect from the JMRI server')
|
77
|
+
log.help('power - Turn power on or off to the train')
|
78
|
+
log.help('throttle - Set throttle to a value between 0 and 10')
|
79
|
+
log.help('move - Move the train in the given direction at the given speed for a certain length of time')
|
80
|
+
log.help('stop - Stop the train')
|
81
|
+
log.help('exit - Exit program')
|
82
82
|
end
|
83
83
|
|
84
84
|
end
|
@@ -1,23 +1,25 @@
|
|
1
1
|
require 'bolt_train_runner/conf'
|
2
2
|
require 'bolt_train_runner/comms'
|
3
|
-
require '
|
3
|
+
require 'bolt_train_runner/log'
|
4
4
|
|
5
5
|
module Commands
|
6
|
-
def self.connect(args)
|
6
|
+
def self.connect(args, log)
|
7
7
|
conf = Conf.load_conf
|
8
8
|
if !args.empty? && args[0] =~ /help/i
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
log.help('Command: connect')
|
10
|
+
log.help('Syntax: connect [server:port]')
|
11
|
+
log.help('If called with no argument, it will attempt to use the last specified server:port')
|
12
|
+
log.help('If this is the first time connect was called with no arguments, it will prompt you for the server and port')
|
13
13
|
return
|
14
14
|
end
|
15
15
|
if args.empty?
|
16
16
|
server = conf['server']
|
17
17
|
unless server
|
18
|
-
|
18
|
+
prompt = 'Please enter server:port [10.0.7.82:12080] > '
|
19
|
+
print prompt
|
19
20
|
server = gets.chomp
|
20
21
|
server = '10.0.7.82:12080' if server.empty?
|
22
|
+
log.info_file("#{prompt} #{server}")
|
21
23
|
end
|
22
24
|
else
|
23
25
|
server = args[0]
|
@@ -25,9 +27,9 @@ module Commands
|
|
25
27
|
conf['server'] = server
|
26
28
|
Conf.save_conf(conf)
|
27
29
|
|
28
|
-
|
29
|
-
comms = Comms.new(server)
|
30
|
-
|
30
|
+
log.info("Connecting to ws://#{server}/json/")
|
31
|
+
comms = Comms.new(server, log)
|
32
|
+
log.info("Connected")
|
31
33
|
return comms
|
32
34
|
end
|
33
35
|
end
|
@@ -1,24 +1,24 @@
|
|
1
|
-
require 'colorize'
|
2
1
|
require 'bolt_train_runner/conf'
|
2
|
+
require 'bolt_train_runner/log'
|
3
3
|
|
4
4
|
module Commands
|
5
|
-
def self.debug(args)
|
5
|
+
def self.debug(args, log)
|
6
6
|
if args.empty? || args[0] =~ /help/i
|
7
|
-
|
8
|
-
|
7
|
+
log.help('Command: debug')
|
8
|
+
log.help('Syntax: debug <on|off>')
|
9
9
|
#Should fix this at some point
|
10
|
-
|
11
|
-
puts 'Choice will be persistent across program invocations.'.cyan
|
10
|
+
log.help('Turns debug logging on or off. Choice will be persistent across program invocations.')
|
12
11
|
return
|
13
12
|
end
|
14
13
|
state = args[0]
|
15
14
|
if !['on','off'].include?(state)
|
16
|
-
|
15
|
+
log.error('Debug must be called with either "on" or "off"')
|
17
16
|
return
|
18
17
|
end
|
19
18
|
conf = Conf.load_conf
|
20
19
|
conf['debug'] = state == 'on'
|
21
20
|
Conf.save_conf(conf)
|
22
|
-
|
21
|
+
state == 'on' ? log.set_console_level('DEBUG') : log.set_console_level('INFO')
|
22
|
+
log.info("Debug mode #{state}")
|
23
23
|
end
|
24
24
|
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
require 'bolt_train_runner/comms'
|
2
|
-
require '
|
2
|
+
require 'bolt_train_runner/log'
|
3
3
|
|
4
4
|
module Commands
|
5
|
-
def self.disconnect(comms)
|
5
|
+
def self.disconnect(comms, log)
|
6
6
|
if comms.nil?
|
7
|
-
|
7
|
+
log.error('Not currently connected')
|
8
8
|
return
|
9
9
|
end
|
10
10
|
comms.disconnect
|
11
|
-
|
11
|
+
log.info('Disconnected')
|
12
12
|
end
|
13
13
|
end
|
@@ -1,11 +1,12 @@
|
|
1
|
-
require 'colorize'
|
2
1
|
require 'bolt_train_runner/comms'
|
2
|
+
require 'bolt_train_runner/log'
|
3
3
|
|
4
4
|
module Commands
|
5
|
-
def self.exit_program(comms, session_runner)
|
5
|
+
def self.exit_program(comms, session_runner, log)
|
6
6
|
session_runner.stop if session_runner
|
7
7
|
comms.disconnect if comms
|
8
|
-
|
8
|
+
log.info('Seeya later!')
|
9
|
+
log.close
|
9
10
|
exit 0
|
10
11
|
end
|
11
12
|
end
|
@@ -1,19 +1,19 @@
|
|
1
1
|
require 'bolt_train_runner/comms'
|
2
2
|
require 'bolt_train_runner/commands/throttle'
|
3
3
|
require 'bolt_train_runner/commands/stop'
|
4
|
-
require '
|
4
|
+
require 'bolt_train_runner/log'
|
5
5
|
|
6
6
|
module Commands
|
7
|
-
def self.move(args, comms)
|
7
|
+
def self.move(args, comms, log)
|
8
8
|
unless comms
|
9
|
-
|
9
|
+
log.error('Please connect first')
|
10
10
|
return
|
11
11
|
end
|
12
12
|
if args.empty? || args[0] =~ /help/i
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
log.help('Command: move')
|
14
|
+
log.help('Syntax: move <forward|reverse> <speed 0-10> <time 1-60>')
|
15
|
+
log.help('Move the train the given direction at the given speed for the given number of seconds')
|
16
|
+
log.help('Note that the power must be on first')
|
17
17
|
return
|
18
18
|
end
|
19
19
|
|
@@ -27,28 +27,29 @@ module Commands
|
|
27
27
|
end
|
28
28
|
|
29
29
|
unless direction && speed && time
|
30
|
-
|
30
|
+
log.error('Please provide direction, speed, and time')
|
31
31
|
return
|
32
32
|
end
|
33
33
|
speed = speed.to_i
|
34
34
|
time = time.to_i
|
35
|
+
direction = direction == 'f' ? 'forward' : direction == 'r' ? 'reverse' : direction
|
35
36
|
unless ['forward','reverse'].include?(direction)
|
36
|
-
|
37
|
+
log.error('Please provide "forward" or "reverse" for direction')
|
37
38
|
return
|
38
39
|
end
|
39
40
|
if speed < 0 or speed > 10
|
40
|
-
|
41
|
+
log.error('Please select a speed between 0 and 10')
|
41
42
|
return
|
42
43
|
end
|
43
44
|
if time < 1 or time > 60
|
44
|
-
|
45
|
+
log.error('Please select a time between 1 and 60 seconds')
|
45
46
|
return
|
46
47
|
end
|
47
48
|
|
48
|
-
|
49
|
-
Commands.throttle([speed,direction],comms)
|
49
|
+
log.info("Moving train #{direction} direction at speed #{speed} for #{time} seconds...")
|
50
|
+
Commands.throttle([speed, direction], comms, log)
|
50
51
|
sleep(time)
|
51
|
-
Commands.stop(nil, comms)
|
52
|
-
|
52
|
+
Commands.stop(nil, comms, log)
|
53
|
+
log.info('Move complete')
|
53
54
|
end
|
54
55
|
end
|
@@ -1,16 +1,16 @@
|
|
1
1
|
require 'bolt_train_runner/comms'
|
2
|
-
require '
|
2
|
+
require 'bolt_train_runner/log'
|
3
3
|
|
4
4
|
module Commands
|
5
|
-
def self.power(args, comms)
|
5
|
+
def self.power(args, comms, log)
|
6
6
|
unless comms
|
7
|
-
|
7
|
+
log.error('Please connect first')
|
8
8
|
return
|
9
9
|
end
|
10
10
|
if args.empty? || args[0] =~ /help/i
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
log.help('Command: power')
|
12
|
+
log.help('Syntax: power <on|off>')
|
13
|
+
log.help('Turns power to the train on or off. Must first be connected.')
|
14
14
|
return
|
15
15
|
end
|
16
16
|
|
@@ -21,7 +21,7 @@ module Commands
|
|
21
21
|
end
|
22
22
|
|
23
23
|
unless ['on','off'].include?(state)
|
24
|
-
|
24
|
+
log.error('Please provide either "on" or "off"')
|
25
25
|
return
|
26
26
|
end
|
27
27
|
|
@@ -36,6 +36,6 @@ module Commands
|
|
36
36
|
}
|
37
37
|
}
|
38
38
|
comms.send_message(message)
|
39
|
-
|
39
|
+
log.info("Power #{state}")
|
40
40
|
end
|
41
41
|
end
|
@@ -1,37 +1,37 @@
|
|
1
|
-
require 'colorize'
|
2
1
|
require 'bolt_train_runner/conf'
|
3
2
|
require 'bolt_train_runner/session_runner'
|
3
|
+
require 'bolt_train_runner/log'
|
4
4
|
|
5
5
|
module Commands
|
6
|
-
def self.sessions(args, comms, session_runner)
|
6
|
+
def self.sessions(args, comms, session_runner, log)
|
7
7
|
if args.empty? || args[0] =~ /help/i
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
log.help('Command: sessions')
|
9
|
+
log.help('Syntax: sessions <start|stop>')
|
10
|
+
log.help('Start or stop the thread that monitors the sessions folder for sessions files. When running, this thread')
|
11
|
+
log.help('will automatically execute the commands contained in sessions files generated by the bolt-train-api server')
|
12
|
+
log.help('as they appear in the folder.')
|
13
13
|
return
|
14
14
|
end
|
15
15
|
|
16
16
|
state = args[0]
|
17
17
|
starting = state == 'start'
|
18
18
|
if !['start','stop'].include?(state)
|
19
|
-
|
19
|
+
log.error('Please provide either "start" or "stop"')
|
20
20
|
return
|
21
21
|
end
|
22
22
|
|
23
23
|
unless comms
|
24
|
-
|
24
|
+
log.error('Please connect first')
|
25
25
|
return
|
26
26
|
end
|
27
27
|
|
28
28
|
if starting and session_runner
|
29
|
-
|
29
|
+
log.warn('Session runner thread already started')
|
30
30
|
return session_runner
|
31
31
|
end
|
32
32
|
|
33
33
|
if !starting and !session_runner
|
34
|
-
|
34
|
+
log.warn('No session runner thread currently running')
|
35
35
|
return nil
|
36
36
|
end
|
37
37
|
|
@@ -45,15 +45,17 @@ module Commands
|
|
45
45
|
session_dir = conf['session_dir']
|
46
46
|
unless session_dir
|
47
47
|
# This should be changed to pick up BOLT_TRAIN_QUEUE_DIR automatically
|
48
|
-
|
48
|
+
prompt = 'Please enter directory for session files [/tmp/bolt-train-queue] > '
|
49
|
+
print prompt
|
49
50
|
session_dir = gets.chomp
|
50
51
|
session_dir = '/tmp/bolt-train-queue' if session_dir.empty?
|
51
52
|
conf['session_dir'] = session_dir
|
52
53
|
Conf.save_conf(conf)
|
54
|
+
log.info_file("#{prompt} #{session_dir}")
|
53
55
|
end
|
54
56
|
end
|
55
57
|
|
56
|
-
runner = SessionRunner.new(comms, session_dir)
|
58
|
+
runner = SessionRunner.new(comms, session_dir, log)
|
57
59
|
runner.start
|
58
60
|
return runner
|
59
61
|
else
|
@@ -1,12 +1,12 @@
|
|
1
|
-
require 'colorize'
|
2
1
|
require 'bolt_train_runner/commands/throttle'
|
2
|
+
require 'bolt_train_runner/log'
|
3
3
|
|
4
4
|
module Commands
|
5
|
-
def self.stop(_args, comms)
|
5
|
+
def self.stop(_args, comms, log)
|
6
6
|
unless comms
|
7
|
-
|
7
|
+
log.error('Please connect first')
|
8
8
|
return
|
9
9
|
end
|
10
|
-
Commands.throttle([0],comms)
|
10
|
+
Commands.throttle([0], comms, log)
|
11
11
|
end
|
12
12
|
end
|
@@ -1,17 +1,17 @@
|
|
1
1
|
require 'bolt_train_runner/comms'
|
2
|
-
require '
|
2
|
+
require 'bolt_train_runner/log'
|
3
3
|
|
4
4
|
module Commands
|
5
|
-
def self.throttle(args, comms)
|
5
|
+
def self.throttle(args, comms, log)
|
6
6
|
unless comms
|
7
|
-
|
7
|
+
log.error('Please connect first')
|
8
8
|
return
|
9
9
|
end
|
10
10
|
if args.empty? || args[0] =~ /help/i
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
log.help('Command: throttle')
|
12
|
+
log.help('Syntax: throttle <0-10> [forward|reverse]')
|
13
|
+
log.help('Sets the throttle to the given level, between 0 and 10. May optionally provide a direction.')
|
14
|
+
log.help('Note that power must be on first for this to take effect.')
|
15
15
|
return
|
16
16
|
end
|
17
17
|
|
@@ -24,12 +24,12 @@ module Commands
|
|
24
24
|
|
25
25
|
speed = speed.to_i
|
26
26
|
if speed < 0 or speed > 10
|
27
|
-
|
27
|
+
log.error('Please select a speed between 0 and 10')
|
28
28
|
return
|
29
29
|
end
|
30
30
|
|
31
31
|
unless direction.nil? || ['forward','reverse'].include?(direction)
|
32
|
-
|
32
|
+
log.error('Direction must be either "forward" or "reverse"')
|
33
33
|
return
|
34
34
|
end
|
35
35
|
|
@@ -45,6 +45,6 @@ module Commands
|
|
45
45
|
message['data']['forward'] = direction == 'forward' if direction
|
46
46
|
comms.send_message(message)
|
47
47
|
direction_string = direction.nil? ? '' : " with direction #{direction}"
|
48
|
-
|
48
|
+
log.info("Throttle set to #{speed}#{direction_string}")
|
49
49
|
end
|
50
50
|
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'websocket-client-simple'
|
2
2
|
require 'json'
|
3
|
-
require 'colorize'
|
4
3
|
require 'bolt_train_runner/conf'
|
4
|
+
require 'bolt_train_runner/log'
|
5
|
+
require 'pry-byebug'
|
5
6
|
|
6
7
|
# Sending and receiving responses is a little bit funky
|
7
8
|
# Since we have to receive messages asynchronously, and because
|
@@ -17,16 +18,17 @@ class Comms
|
|
17
18
|
@heartbeat_thread = nil
|
18
19
|
@consumer_thread = nil
|
19
20
|
@kill_threads = false
|
21
|
+
@log = nil
|
20
22
|
|
21
|
-
def initialize(server)
|
22
|
-
|
23
|
-
@ws = WebSocket::Client::Simple.connect("ws://#{server}/json/")
|
24
|
-
@ws.on :message do |msg|
|
23
|
+
def initialize(server, log)
|
24
|
+
@log = log
|
25
|
+
@ws = WebSocket::Client::Simple.connect("ws://#{server}/json/", @log)
|
26
|
+
@ws.on :message do |msg, logger|
|
25
27
|
data = JSON.parse(msg.data)
|
26
|
-
|
28
|
+
logger.debug("Received #{data}\n> ")
|
27
29
|
end
|
28
|
-
@ws.on :error do |e|
|
29
|
-
|
30
|
+
@ws.on :error do |e, logger|
|
31
|
+
logger.error("Error from Websocket: #{e}")
|
30
32
|
end
|
31
33
|
|
32
34
|
@heartbeat_thread = Thread.new { run_heartbeat }
|
@@ -54,9 +56,8 @@ class Comms
|
|
54
56
|
# Expects a hash with the correctly formed message, which
|
55
57
|
# will get transformed to a JSON string by this function
|
56
58
|
def send_message(message)
|
57
|
-
debug = Conf.debug
|
58
59
|
message = JSON.generate(message)
|
59
|
-
|
60
|
+
@log.debug("Sending #{message}")
|
60
61
|
@ws.send(message)
|
61
62
|
end
|
62
63
|
|
@@ -3,7 +3,9 @@ require 'yaml'
|
|
3
3
|
class Conf
|
4
4
|
attr_reader :CONFFILE
|
5
5
|
|
6
|
-
CONFFILE = File.expand_path('~/.bolttrain
|
6
|
+
CONFFILE = File.expand_path('~/.bolttrain/config')
|
7
|
+
CONFDIR = File.split(CONFFILE)[0]
|
8
|
+
Dir.mkdir(CONFDIR) unless File.exist?(CONFDIR)
|
7
9
|
File.write(CONFFILE, "---\n{}") unless File.exist?(CONFFILE)
|
8
10
|
|
9
11
|
def self.load_conf
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'colorize'
|
3
|
+
class Log
|
4
|
+
|
5
|
+
@loggers = []
|
6
|
+
|
7
|
+
def initialize(file='~/.bolttrain/runner.log', console_level='INFO', file_level='DEBUG')
|
8
|
+
file = File.expand_path(file)
|
9
|
+
dir = File.split(file)[0]
|
10
|
+
Dir.mkdir(dir) unless File.exist?(dir)
|
11
|
+
@console = Logger.new(STDOUT,
|
12
|
+
level: console_level,
|
13
|
+
formatter: proc { |sev, datetime, progname, msg| "#{msg}\n" })
|
14
|
+
@file = Logger.new(file, 'daily', level: file_level)
|
15
|
+
end
|
16
|
+
|
17
|
+
def set_console_level(level)
|
18
|
+
@console.level = level
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_file_level(level)
|
22
|
+
@file.level = level
|
23
|
+
end
|
24
|
+
|
25
|
+
def debug(msg, console=true, file=true)
|
26
|
+
@console.debug(msg) if console
|
27
|
+
@file.debug(msg) if file
|
28
|
+
end
|
29
|
+
|
30
|
+
def debug_console(msg)
|
31
|
+
debug(msg, true, false)
|
32
|
+
end
|
33
|
+
|
34
|
+
def debug_file(msg)
|
35
|
+
debug(msg, false, true)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Just for printing help text to the console. Doesn't need to be logged.
|
39
|
+
def help(msg)
|
40
|
+
@console.info(msg.cyan)
|
41
|
+
end
|
42
|
+
|
43
|
+
def info(msg, console=true, file=true)
|
44
|
+
@console.info(msg.green) if console
|
45
|
+
@file.info(msg) if file
|
46
|
+
end
|
47
|
+
|
48
|
+
def info_console(msg)
|
49
|
+
info(msg, true, false)
|
50
|
+
end
|
51
|
+
|
52
|
+
def info_file(msg)
|
53
|
+
info(msg, false, true)
|
54
|
+
end
|
55
|
+
|
56
|
+
def warn(msg, console=true, file=true)
|
57
|
+
@console.warn(msg.yellow) if console
|
58
|
+
@file.warn(msg) if file
|
59
|
+
end
|
60
|
+
|
61
|
+
def warn_console(msg)
|
62
|
+
warn(msg, true, false)
|
63
|
+
end
|
64
|
+
|
65
|
+
def warn_file(msg)
|
66
|
+
warn(msg, false, true)
|
67
|
+
end
|
68
|
+
|
69
|
+
def error(msg, console=true, file=true)
|
70
|
+
@console.error(msg.red) if console
|
71
|
+
@file.error(msg) if file
|
72
|
+
end
|
73
|
+
|
74
|
+
def error_console(msg)
|
75
|
+
error(msg, true, false)
|
76
|
+
end
|
77
|
+
|
78
|
+
def error_file(msg)
|
79
|
+
error(msg, false, true)
|
80
|
+
end
|
81
|
+
|
82
|
+
def fatal(msg, console=true, file=true)
|
83
|
+
@console.fatal(msg.red) if console
|
84
|
+
@file.fatal(msg) if file
|
85
|
+
end
|
86
|
+
|
87
|
+
def fatal_console(msg)
|
88
|
+
fatal(msg, true, false)
|
89
|
+
end
|
90
|
+
|
91
|
+
def fatal_file(msg)
|
92
|
+
fatal(msg, false, true)
|
93
|
+
end
|
94
|
+
|
95
|
+
def close
|
96
|
+
@console.close
|
97
|
+
@file.close
|
98
|
+
end
|
99
|
+
end
|
@@ -13,14 +13,16 @@ class SessionRunner
|
|
13
13
|
|
14
14
|
@session_thread = nil
|
15
15
|
@kill_thread = false
|
16
|
+
@log = nil
|
16
17
|
|
17
|
-
def initialize(comms, session_dir)
|
18
|
+
def initialize(comms, session_dir, log)
|
18
19
|
raise 'comms must not be nil' if comms.nil?
|
19
20
|
raise 'session_dir must not be nil' if session_dir.nil?
|
20
21
|
raise 'session_dir does not exist' unless File.exist?(session_dir)
|
21
22
|
|
22
23
|
@session_dir = session_dir
|
23
24
|
@comms = comms
|
25
|
+
@log = log
|
24
26
|
end
|
25
27
|
|
26
28
|
def start
|
@@ -29,7 +31,7 @@ class SessionRunner
|
|
29
31
|
|
30
32
|
def stop
|
31
33
|
@kill_thread = true
|
32
|
-
|
34
|
+
@log.info('Stopping Session Runner')
|
33
35
|
@session_thread.join if @session_thread
|
34
36
|
end
|
35
37
|
|
@@ -44,17 +46,17 @@ class SessionRunner
|
|
44
46
|
end
|
45
47
|
session = data['session']
|
46
48
|
email = session['email']
|
47
|
-
|
49
|
+
@log.info("[Session Runner] Starting session for #{email}")
|
48
50
|
commands = session['commands']
|
49
51
|
commands.each do |args|
|
50
52
|
c = args['command']
|
51
53
|
args.delete('command')
|
52
|
-
|
53
|
-
|
54
|
-
Commands.send(c, args, @comms)
|
54
|
+
@log.info("[Session Runner] Sending command #{c}")
|
55
|
+
@log.info("[Session Runner] Arguments = #{args}")
|
56
|
+
Commands.send(c, args, @comms, @log)
|
55
57
|
end
|
56
58
|
File.delete(f)
|
57
|
-
|
59
|
+
@log.info("[Session Runner] Session for #{email} complete")
|
58
60
|
end
|
59
61
|
end
|
60
62
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Forked from https://github.com/shokai/websocket-client-simple
|
2
|
+
# Credit to Sho Hashimoto
|
3
|
+
|
4
|
+
require 'event_emitter'
|
5
|
+
require 'websocket'
|
6
|
+
require 'socket'
|
7
|
+
require 'openssl'
|
8
|
+
require 'uri'
|
9
|
+
|
10
|
+
require 'websocket-client-simple/client'
|
11
|
+
|
12
|
+
module WebSocket
|
13
|
+
module Client
|
14
|
+
module Simple
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# Forked from https://github.com/shokai/websocket-client-simple
|
2
|
+
# Credit to Sho Hashimoto
|
3
|
+
|
4
|
+
module WebSocket
|
5
|
+
module Client
|
6
|
+
module Simple
|
7
|
+
|
8
|
+
def self.connect(url, options={}, logger)
|
9
|
+
client = ::WebSocket::Client::Simple::Client.new
|
10
|
+
yield client if block_given?
|
11
|
+
client.connect url, options, logger
|
12
|
+
return client
|
13
|
+
end
|
14
|
+
|
15
|
+
class Client
|
16
|
+
include EventEmitter
|
17
|
+
attr_reader :url, :handshake
|
18
|
+
attr_accessor :logger
|
19
|
+
|
20
|
+
def connect(url, options={}, logger)
|
21
|
+
return if @socket
|
22
|
+
@logger = logger
|
23
|
+
@url = url
|
24
|
+
uri = URI.parse url
|
25
|
+
@socket = TCPSocket.new(uri.host,
|
26
|
+
uri.port || (uri.scheme == 'wss' ? 443 : 80))
|
27
|
+
if ['https', 'wss'].include? uri.scheme
|
28
|
+
ctx = OpenSSL::SSL::SSLContext.new
|
29
|
+
ctx.ssl_version = options[:ssl_version] || 'SSLv23'
|
30
|
+
ctx.verify_mode = options[:verify_mode] || OpenSSL::SSL::VERIFY_NONE #use VERIFY_PEER for verification
|
31
|
+
cert_store = OpenSSL::X509::Store.new
|
32
|
+
cert_store.set_default_paths
|
33
|
+
ctx.cert_store = cert_store
|
34
|
+
@socket = ::OpenSSL::SSL::SSLSocket.new(@socket, ctx)
|
35
|
+
@socket.connect
|
36
|
+
end
|
37
|
+
@handshake = ::WebSocket::Handshake::Client.new :url => url, :headers => options[:headers]
|
38
|
+
@handshaked = false
|
39
|
+
@pipe_broken = false
|
40
|
+
frame = ::WebSocket::Frame::Incoming::Client.new
|
41
|
+
@closed = false
|
42
|
+
once :__close do |err|
|
43
|
+
close
|
44
|
+
emit :close, err
|
45
|
+
end
|
46
|
+
|
47
|
+
@thread = Thread.new do
|
48
|
+
while !@closed do
|
49
|
+
begin
|
50
|
+
unless recv_data = @socket.getc
|
51
|
+
sleep 1
|
52
|
+
next
|
53
|
+
end
|
54
|
+
unless @handshaked
|
55
|
+
@handshake << recv_data
|
56
|
+
if @handshake.finished?
|
57
|
+
@handshaked = true
|
58
|
+
emit :open, @logger
|
59
|
+
end
|
60
|
+
else
|
61
|
+
frame << recv_data
|
62
|
+
while msg = frame.next
|
63
|
+
emit :message, msg, @logger
|
64
|
+
end
|
65
|
+
end
|
66
|
+
rescue => e
|
67
|
+
emit :error, e, @logger
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
@socket.write @handshake.to_s
|
73
|
+
end
|
74
|
+
|
75
|
+
def send(data, opt={:type => :text})
|
76
|
+
return if !@handshaked or @closed
|
77
|
+
type = opt[:type]
|
78
|
+
frame = ::WebSocket::Frame::Outgoing::Client.new(:data => data, :type => type, :version => @handshake.version)
|
79
|
+
begin
|
80
|
+
@socket.write frame.to_s
|
81
|
+
rescue Errno::EPIPE => e
|
82
|
+
@pipe_broken = true
|
83
|
+
emit :__close, e
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def close
|
88
|
+
return if @closed
|
89
|
+
if !@pipe_broken
|
90
|
+
send nil, :type => :close
|
91
|
+
end
|
92
|
+
@closed = true
|
93
|
+
@socket.close if @socket
|
94
|
+
@socket = nil
|
95
|
+
emit :__close
|
96
|
+
Thread.kill @thread if @thread
|
97
|
+
end
|
98
|
+
|
99
|
+
def open?
|
100
|
+
@handshake.finished? and !@closed
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bolt_train_runner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Burgan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-11-
|
11
|
+
date: 2019-11-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -39,7 +39,21 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name: websocket
|
42
|
+
name: websocket
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: event_emitter
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
59
|
- - ">="
|
@@ -91,8 +105,11 @@ files:
|
|
91
105
|
- lib/bolt_train_runner/commands/throttle.rb
|
92
106
|
- lib/bolt_train_runner/comms.rb
|
93
107
|
- lib/bolt_train_runner/conf.rb
|
108
|
+
- lib/bolt_train_runner/log.rb
|
94
109
|
- lib/bolt_train_runner/session_runner.rb
|
95
110
|
- lib/bolt_train_runner/version.rb
|
111
|
+
- lib/websocket-client-simple.rb
|
112
|
+
- lib/websocket-client-simple/client.rb
|
96
113
|
homepage: https://github.com/puppetlabs/bolt-train-runner
|
97
114
|
licenses:
|
98
115
|
- MIT
|