bolt_train_runner 0.2.2 → 0.3.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 +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
|