procon_bypass_man 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +18 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +42 -0
- data/LICENSE.txt +21 -0
- data/README.md +157 -0
- data/Rakefile +4 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/docs/how_to_connect_procon.md +23 -0
- data/docs/setup_raspi.md +38 -0
- data/examples/practical/app.rb +16 -0
- data/examples/practical/setting.yml +24 -0
- data/examples/simple.rb +13 -0
- data/lib/procon_bypass_man.rb +66 -0
- data/lib/procon_bypass_man/bypass.rb +53 -0
- data/lib/procon_bypass_man/configuration.rb +83 -0
- data/lib/procon_bypass_man/configuration/layer.rb +52 -0
- data/lib/procon_bypass_man/configuration/loader.rb +44 -0
- data/lib/procon_bypass_man/configuration/validator.rb +26 -0
- data/lib/procon_bypass_man/device_registry.rb +41 -0
- data/lib/procon_bypass_man/io_monitor.rb +89 -0
- data/lib/procon_bypass_man/processor.rb +17 -0
- data/lib/procon_bypass_man/procon.rb +129 -0
- data/lib/procon_bypass_man/procon/button_collection.rb +40 -0
- data/lib/procon_bypass_man/procon/data.rb +5 -0
- data/lib/procon_bypass_man/procon/layer_changeable.rb +28 -0
- data/lib/procon_bypass_man/procon/macro_registry.rb +48 -0
- data/lib/procon_bypass_man/procon/mode_registry.rb +46 -0
- data/lib/procon_bypass_man/procon/pressed_button_helper.rb +25 -0
- data/lib/procon_bypass_man/procon/user_operation.rb +72 -0
- data/lib/procon_bypass_man/runner.rb +171 -0
- data/lib/procon_bypass_man/version.rb +5 -0
- data/procon_bypass_man.gemspec +35 -0
- metadata +82 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
class ProconBypassMan::Processor
|
2
|
+
# @return [String] binary
|
3
|
+
def initialize(binary)
|
4
|
+
@binary = binary
|
5
|
+
end
|
6
|
+
|
7
|
+
# @return [String] 加工後の入力データ
|
8
|
+
def process
|
9
|
+
unless @binary[0] == "\x30".b
|
10
|
+
return @binary
|
11
|
+
end
|
12
|
+
|
13
|
+
procon = ProconBypassMan::Procon.new(@binary)
|
14
|
+
procon.apply!
|
15
|
+
procon.to_binary
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
class ProconBypassMan::Procon
|
2
|
+
require "procon_bypass_man/procon/mode_registry"
|
3
|
+
require "procon_bypass_man/procon/macro_registry"
|
4
|
+
require "procon_bypass_man/procon/layer_changeable"
|
5
|
+
require "procon_bypass_man/procon/button_collection"
|
6
|
+
require "procon_bypass_man/procon/pressed_button_helper"
|
7
|
+
require "procon_bypass_man/procon/user_operation"
|
8
|
+
|
9
|
+
attr_accessor :user_operation
|
10
|
+
|
11
|
+
def self.reset_cvar!
|
12
|
+
@@status = {
|
13
|
+
buttons: {},
|
14
|
+
current_layer_key: :up,
|
15
|
+
ongoing_macro: MacroRegistry.load(:null),
|
16
|
+
ongoing_mode: ModeRegistry.load(:manual),
|
17
|
+
}
|
18
|
+
end
|
19
|
+
def self.reset!; reset_cvar!; end
|
20
|
+
reset!
|
21
|
+
|
22
|
+
def initialize(binary)
|
23
|
+
self.user_operation = ProconBypassMan::Procon::UserOperation.new(binary.dup)
|
24
|
+
end
|
25
|
+
|
26
|
+
def status; @@status[:buttons]; end
|
27
|
+
def ongoing_macro; @@status[:ongoing_macro]; end
|
28
|
+
def ongoing_mode; @@status[:ongoing_mode]; end
|
29
|
+
def current_layer_key; @@status[:current_layer_key]; end
|
30
|
+
|
31
|
+
def current_layer
|
32
|
+
ProconBypassMan::Configuration.instance.layers[current_layer_key]
|
33
|
+
end
|
34
|
+
|
35
|
+
def apply!
|
36
|
+
if user_operation.change_layer?
|
37
|
+
@@status[:current_layer_key] = user_operation.next_layer_key if user_operation.pressed_next_layer?
|
38
|
+
user_operation.set_no_action!
|
39
|
+
return
|
40
|
+
end
|
41
|
+
|
42
|
+
if ongoing_macro.finished?
|
43
|
+
current_layer.macros.each do |macro_name, options|
|
44
|
+
if options[:if_pressed].all? { |b| user_operation.pressed_button?(b) }
|
45
|
+
@@status[:ongoing_macro] = MacroRegistry.load(macro_name)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
case current_layer.mode
|
51
|
+
when :manual
|
52
|
+
@@status[:ongoing_mode] = ModeRegistry.load(:manual)
|
53
|
+
current_layer.flip_buttons.each do |button, options|
|
54
|
+
unless options[:if_pressed]
|
55
|
+
status[button] = !status[button]
|
56
|
+
next
|
57
|
+
end
|
58
|
+
|
59
|
+
if options[:if_pressed] && options[:if_pressed].all? { |b| user_operation.pressed_button?(b) }
|
60
|
+
status[button] = !status[button]
|
61
|
+
else
|
62
|
+
status[button] = false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
else
|
66
|
+
unless ongoing_mode.name == current_layer.mode
|
67
|
+
@@status[:ongoing_mode] = ProconBypassMan::Procon::ModeRegistry.load(current_layer.mode)
|
68
|
+
end
|
69
|
+
if(binary = ongoing_mode.next_binary)
|
70
|
+
self.user_operation.merge(target_binary: binary)
|
71
|
+
end
|
72
|
+
return
|
73
|
+
end
|
74
|
+
|
75
|
+
status
|
76
|
+
end
|
77
|
+
|
78
|
+
# @return [String<binary>]
|
79
|
+
def to_binary
|
80
|
+
if ongoing_mode.name != :manual
|
81
|
+
return user_operation.binary
|
82
|
+
end
|
83
|
+
|
84
|
+
if ongoing_macro.ongoing?
|
85
|
+
step = ongoing_macro.next_step or return(user_operation.binary)
|
86
|
+
user_operation.press_button_only(step)
|
87
|
+
return user_operation.binary
|
88
|
+
end
|
89
|
+
|
90
|
+
current_layer.flip_buttons.each do |button, options|
|
91
|
+
# 何もしないで常に連打
|
92
|
+
if !options[:if_pressed] && status[button]
|
93
|
+
user_operation.press_button(button) unless user_operation.pressed_button?(button)
|
94
|
+
next
|
95
|
+
end
|
96
|
+
|
97
|
+
# 押している時だけ連打
|
98
|
+
if options[:if_pressed] && options[:if_pressed].all? { |b| user_operation.pressed_button?(b) }
|
99
|
+
if !status[button]
|
100
|
+
user_operation.unpress_button(button)
|
101
|
+
end
|
102
|
+
if options[:force_neutral] && user_operation.pressed_button?(options[:force_neutral])
|
103
|
+
button = options[:force_neutral]
|
104
|
+
user_operation.unpress_button(button)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
current_layer.remaps.each do |from_button, to_button|
|
110
|
+
if user_operation.pressed_button?(from_button)
|
111
|
+
user_operation.unpress_button(from_button)
|
112
|
+
# TODO 2重でpressしないようにしたい
|
113
|
+
user_operation.press_button(to_button) unless user_operation.pressed_button?(to_button)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
user_operation.binary
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def method_missing(name)
|
123
|
+
if name.to_s =~ /\Apressed_[a-z]+\?\z/
|
124
|
+
user_operation.public_send(name)
|
125
|
+
else
|
126
|
+
super
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class ProconBypassMan::Procon::ButtonCollection
|
2
|
+
class Button
|
3
|
+
attr_accessor :byte_position, :bit_position
|
4
|
+
def initialize(key)
|
5
|
+
b = BUTTONS_MAP[key] or raise("undefined button")
|
6
|
+
self.byte_position = b[:byte_position]
|
7
|
+
self.bit_position = b[:bit_position]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
#3) ZR R SR(right) SL(right) A B X Y
|
12
|
+
#4) Grip (none) Cap Home ThumbL ThumbR + -
|
13
|
+
#5) ZL L SL(left) SR(left) Left Right Up Down
|
14
|
+
#6) analog[0]
|
15
|
+
#7) analog[1]
|
16
|
+
#8) analog[2]
|
17
|
+
#9) analog[3]
|
18
|
+
#a) analog[4]
|
19
|
+
#b) analog[5]
|
20
|
+
BYTES_MAP = {
|
21
|
+
0 => nil,
|
22
|
+
1 => nil,
|
23
|
+
2 => nil,
|
24
|
+
3 => [:zr, :r, :sr, :sl, :a, :b, :x, :y],
|
25
|
+
4 => [:grip, :_undefined_key, :cap, :home, :thumbl, :thumbr, :plus, :minus],
|
26
|
+
5 => [:zl, :l, :sl, :sr, :left, :right, :up, :down],
|
27
|
+
}
|
28
|
+
|
29
|
+
BUTTONS_MAP = BYTES_MAP.reduce({}) { |acc, value|
|
30
|
+
next acc if value[1].nil?
|
31
|
+
value[1].reverse.each.with_index do |button, index|
|
32
|
+
acc[button] = { byte_position: value[0], bit_position: index }
|
33
|
+
end
|
34
|
+
acc
|
35
|
+
}
|
36
|
+
|
37
|
+
def self.load(button_key)
|
38
|
+
Button.new(button_key)
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module ProconBypassMan::Procon::LayerChangeable
|
2
|
+
def next_layer_key
|
3
|
+
case
|
4
|
+
when pressed_up?
|
5
|
+
:up
|
6
|
+
when pressed_right?
|
7
|
+
:right
|
8
|
+
when pressed_left?
|
9
|
+
:left
|
10
|
+
when pressed_down?
|
11
|
+
:down
|
12
|
+
else
|
13
|
+
ProconBypassMan.logger.warn("next_layer_key is unknown")
|
14
|
+
:up
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def change_layer?
|
19
|
+
if ProconBypassMan::Configuration.instance.prefix_keys.empty?
|
20
|
+
raise "prefix_keysが未設定です"
|
21
|
+
end
|
22
|
+
ProconBypassMan::Configuration.instance.prefix_keys.map { |b| pressed_button?(b) }.all?
|
23
|
+
end
|
24
|
+
|
25
|
+
def pressed_next_layer?
|
26
|
+
change_layer? && (pressed_up? || pressed_right? || pressed_left? || pressed_down?)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class ProconBypassMan::Procon::MacroRegistry
|
2
|
+
class Macro
|
3
|
+
attr_accessor :name, :steps
|
4
|
+
|
5
|
+
def initialize(name: , steps: )
|
6
|
+
self.name = name
|
7
|
+
self.steps = steps
|
8
|
+
end
|
9
|
+
|
10
|
+
def next_step
|
11
|
+
steps.shift
|
12
|
+
end
|
13
|
+
|
14
|
+
def finished?
|
15
|
+
steps.empty?
|
16
|
+
end
|
17
|
+
|
18
|
+
def ongoing?
|
19
|
+
!finished?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
PRESETS = {
|
24
|
+
null: [],
|
25
|
+
}
|
26
|
+
|
27
|
+
def self.install_plugin(klass)
|
28
|
+
if plugins[klass.name]
|
29
|
+
raise "すでに登録済みです"
|
30
|
+
end
|
31
|
+
plugins[klass.name] = klass.steps
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.load(name)
|
35
|
+
steps = PRESETS[name] || plugins[name] || raise("unknown macro")
|
36
|
+
Macro.new(name: name, steps: steps.dup)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.reset!
|
40
|
+
ProconBypassMan::Configuration.instance.macro_plugins = {}
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.plugins
|
44
|
+
ProconBypassMan::Configuration.instance.macro_plugins
|
45
|
+
end
|
46
|
+
|
47
|
+
reset!
|
48
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class ProconBypassMan::Procon::ModeRegistry
|
2
|
+
class Mode
|
3
|
+
attr_accessor :name, :binaries, :source_binaries
|
4
|
+
|
5
|
+
def initialize(name: , binaries: )
|
6
|
+
self.name = name
|
7
|
+
self.binaries = binaries
|
8
|
+
self.source_binaries = binaries.dup
|
9
|
+
end
|
10
|
+
|
11
|
+
def next_binary
|
12
|
+
binary = binaries.shift
|
13
|
+
unless binary
|
14
|
+
self.binaries = source_binaries.dup
|
15
|
+
return binaries.shift
|
16
|
+
end
|
17
|
+
return binary
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
PRESETS = {
|
22
|
+
manual: [],
|
23
|
+
}
|
24
|
+
|
25
|
+
def self.install_plugin(klass)
|
26
|
+
if plugins[klass.name]
|
27
|
+
raise "すでに登録済みです"
|
28
|
+
end
|
29
|
+
plugins[klass.name] = klass.binaries
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.load(name)
|
33
|
+
b = PRESETS[name] || plugins[name] || raise("unknown mode")
|
34
|
+
Mode.new(name: name, binaries: b.dup)
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.reset!
|
38
|
+
ProconBypassMan::Configuration.instance.mode_plugins = {}
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.plugins
|
42
|
+
ProconBypassMan::Configuration.instance.mode_plugins
|
43
|
+
end
|
44
|
+
|
45
|
+
reset!
|
46
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module ProconBypassMan::Procon::PushedButtonHelper
|
2
|
+
module Static
|
3
|
+
def pressed_button?(button)
|
4
|
+
binary[
|
5
|
+
::ProconBypassMan::Procon::ButtonCollection.load(button).byte_position
|
6
|
+
].unpack("H*").first.to_i(16).to_s(2).reverse[
|
7
|
+
::ProconBypassMan::Procon::ButtonCollection.load(button).bit_position
|
8
|
+
] == '1'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module Dynamic
|
13
|
+
@@compiled = false
|
14
|
+
def compile_if_not_compile_yet!
|
15
|
+
unless @@compiled
|
16
|
+
::ProconBypassMan::Procon::ButtonCollection::BUTTONS_MAP.each do |button, value|
|
17
|
+
define_method "pressed_#{button}?" do
|
18
|
+
pressed_button?(button)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
@@compiled = true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
class ProconBypassMan::Procon
|
2
|
+
class UserOperation
|
3
|
+
include LayerChangeable
|
4
|
+
include PushedButtonHelper::Static
|
5
|
+
extend PushedButtonHelper::Dynamic
|
6
|
+
|
7
|
+
attr_reader :binary
|
8
|
+
|
9
|
+
def initialize(binary)
|
10
|
+
self.class.compile_if_not_compile_yet!
|
11
|
+
unless binary.encoding.name == ASCII_ENCODING
|
12
|
+
raise "おかしいです"
|
13
|
+
end
|
14
|
+
@binary = binary
|
15
|
+
end
|
16
|
+
|
17
|
+
ZERO_BIT = ["0"].pack("H*").freeze
|
18
|
+
ASCII_ENCODING = "ASCII-8BIT"
|
19
|
+
|
20
|
+
# @depilicate
|
21
|
+
def binary=(binary)
|
22
|
+
unless binary.encoding.name == ASCII_ENCODING
|
23
|
+
raise "おかしいです"
|
24
|
+
end
|
25
|
+
@binary = binary
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_no_action!
|
29
|
+
binary[3] = ZERO_BIT
|
30
|
+
binary[4] = ZERO_BIT
|
31
|
+
binary[5] = ZERO_BIT
|
32
|
+
end
|
33
|
+
|
34
|
+
def unpress_button(button)
|
35
|
+
byte_position = ButtonCollection.load(button).byte_position
|
36
|
+
value = binary[byte_position].unpack("H*").first.to_i(16) - 2**ButtonCollection.load(button).bit_position
|
37
|
+
binary[byte_position] = ["%02X" % value.to_s].pack("H*")
|
38
|
+
end
|
39
|
+
|
40
|
+
def press_button(button)
|
41
|
+
byte_position = ButtonCollection.load(button).byte_position
|
42
|
+
value = binary[byte_position].unpack("H*").first.to_i(16) + 2**ButtonCollection.load(button).bit_position
|
43
|
+
binary[byte_position] = ["%02X" % value.to_s].pack("H*")
|
44
|
+
end
|
45
|
+
|
46
|
+
def press_button_only(button)
|
47
|
+
[ProconBypassMan::Procon::Data::NO_ACTION.dup].pack("H*").tap do |no_action_binary|
|
48
|
+
ButtonCollection.load(button).byte_position
|
49
|
+
byte_position = ButtonCollection.load(button).byte_position
|
50
|
+
value = 2**ButtonCollection.load(button).bit_position
|
51
|
+
no_action_binary[byte_position] = ["%02X" % value.to_s].pack("H*")
|
52
|
+
binary[3] = no_action_binary[3]
|
53
|
+
binary[4] = no_action_binary[4]
|
54
|
+
binary[5] = no_action_binary[5]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def merge(target_binary: )
|
59
|
+
tb = [target_binary].pack("H*")
|
60
|
+
binary[3] = tb[3]
|
61
|
+
binary[4] = tb[4]
|
62
|
+
binary[5] = tb[5]
|
63
|
+
binary[6] = tb[6]
|
64
|
+
binary[7] = tb[7]
|
65
|
+
binary[8] = tb[8]
|
66
|
+
binary[9] = tb[9]
|
67
|
+
binary[10] = tb[10]
|
68
|
+
binary[11] = tb[11]
|
69
|
+
self.binary
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require_relative "io_monitor"
|
2
|
+
|
3
|
+
class ProconBypassMan::Runner
|
4
|
+
class InterruptForRestart < StandardError; end
|
5
|
+
class InterruptForCouldNotConnect < StandardError; end
|
6
|
+
|
7
|
+
def initialize(gadget: , procon: )
|
8
|
+
@gadget = gadget
|
9
|
+
@procon = procon
|
10
|
+
|
11
|
+
$will_interval_0_0_0_5 = 0
|
12
|
+
$will_interval_1_6 = 0
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
first_negotiation
|
17
|
+
$is_stable = false
|
18
|
+
|
19
|
+
self_read, self_write = IO.pipe
|
20
|
+
%w(TERM INT USR1 USR2).each do |sig|
|
21
|
+
begin
|
22
|
+
trap sig do
|
23
|
+
self_write.puts(sig)
|
24
|
+
end
|
25
|
+
rescue ArgumentError
|
26
|
+
ProconBypassMan.logger.info("Signal #{sig} not supported")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
FileUtils.mkdir_p "tmp"
|
31
|
+
File.write "tmp/pid", $$
|
32
|
+
|
33
|
+
loop do
|
34
|
+
$will_terminate_token = false
|
35
|
+
main_loop_pid = fork { main_loop }
|
36
|
+
|
37
|
+
begin
|
38
|
+
while readable_io = IO.select([self_read])
|
39
|
+
signal = readable_io.first[0].gets.strip
|
40
|
+
handle_signal(signal)
|
41
|
+
end
|
42
|
+
rescue InterruptForCouldNotConnect
|
43
|
+
$will_terminate_token = true
|
44
|
+
Process.kill("TERM", main_loop_pid)
|
45
|
+
Process.wait
|
46
|
+
raise ProconBypassMan::CouldNotConnectDeviceError
|
47
|
+
rescue InterruptForRestart
|
48
|
+
$will_terminate_token = true
|
49
|
+
Process.kill("TERM", main_loop_pid)
|
50
|
+
Process.wait
|
51
|
+
ProconBypassMan.logger.info("Reloading config file")
|
52
|
+
begin
|
53
|
+
ProconBypassMan::Configuration::Loader.reload_setting
|
54
|
+
puts "設定ファイルの再読み込みができました"
|
55
|
+
rescue ProconBypassMan::CouldNotLoadConfigError
|
56
|
+
ProconBypassMan.logger.error "設定ファイルが不正です。再読み込みができませんでした"
|
57
|
+
end
|
58
|
+
ProconBypassMan.logger.info("バイパス処理を再開します")
|
59
|
+
rescue Interrupt
|
60
|
+
$will_terminate_token = true
|
61
|
+
Process.kill("TERM", main_loop_pid)
|
62
|
+
Process.wait
|
63
|
+
@gadget&.close
|
64
|
+
@procon&.close
|
65
|
+
exit 1
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def main_loop
|
73
|
+
# TODO 接続確立完了をswitchを読み取るようにして、この暫定で接続完了sleepを消す
|
74
|
+
Thread.new do
|
75
|
+
sleep(10)
|
76
|
+
$will_interval_0_0_0_5 = 0.005
|
77
|
+
$will_interval_1_6 = 1.6
|
78
|
+
$is_stable = true
|
79
|
+
end
|
80
|
+
|
81
|
+
ProconBypassMan::IOMonitor.start!
|
82
|
+
# gadget => procon
|
83
|
+
# 遅くていい
|
84
|
+
monitor1 = ProconBypassMan::IOMonitor.new(label: "switch -> procon")
|
85
|
+
monitor2 = ProconBypassMan::IOMonitor.new(label: "procon -> switch")
|
86
|
+
ProconBypassMan.logger.info "Thread1を起動します"
|
87
|
+
t1 = Thread.new do
|
88
|
+
bypass = ProconBypassMan::Bypass.new(gadget: @gadget, procon: @procon, monitor: monitor1)
|
89
|
+
begin
|
90
|
+
loop do
|
91
|
+
break if $will_terminate_token
|
92
|
+
bypass.send_gadget_to_procon!
|
93
|
+
rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError => e
|
94
|
+
ProconBypassMan.logger.error "Proconが切断されました.終了処理を開始します"
|
95
|
+
Process.kill "TERM", Process.ppid
|
96
|
+
end
|
97
|
+
ProconBypassMan.logger.info "Thread1を終了します"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# procon => gadget
|
102
|
+
# シビア
|
103
|
+
ProconBypassMan.logger.info "Thread2を起動します"
|
104
|
+
t2 = Thread.new do
|
105
|
+
bypass = ProconBypassMan::Bypass.new(gadget: @gadget, procon: @procon, monitor: monitor2)
|
106
|
+
begin
|
107
|
+
loop do
|
108
|
+
break if $will_terminate_token
|
109
|
+
bypass.send_procon_to_gadget!
|
110
|
+
rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError => e
|
111
|
+
ProconBypassMan.logger.error "Proconが切断されました.終了処理を開始します"
|
112
|
+
Process.kill "TERM", Process.ppid
|
113
|
+
end
|
114
|
+
ProconBypassMan.logger.info "Thread2を終了します"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
self_read, self_write = IO.pipe
|
119
|
+
%w(TERM INT).each do |sig|
|
120
|
+
begin
|
121
|
+
trap sig do
|
122
|
+
self_write.puts(sig)
|
123
|
+
end
|
124
|
+
rescue ArgumentError
|
125
|
+
puts "プロセスでSignal #{sig} not supported"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
ProconBypassMan.logger.info "子プロセスでgraceful shutdownの準備ができました"
|
130
|
+
begin
|
131
|
+
while readable_io = IO.select([self_read])
|
132
|
+
signal = readable_io.first[0].gets.strip
|
133
|
+
handle_signal(signal)
|
134
|
+
end
|
135
|
+
rescue Interrupt
|
136
|
+
$will_terminate_token = true
|
137
|
+
[t1, t2].each(&:join)
|
138
|
+
@gadget&.close
|
139
|
+
@procon&.close
|
140
|
+
exit 1
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def first_negotiation
|
145
|
+
loop do
|
146
|
+
begin
|
147
|
+
input = @gadget.read_nonblock(128)
|
148
|
+
ProconBypassMan.logger.debug { ">>> #{input.unpack("H*")}" }
|
149
|
+
@procon.write_nonblock(input)
|
150
|
+
if input[0] == "\x80".b && input[1] == "\x01".b
|
151
|
+
ProconBypassMan.logger.info("first negotiation is over")
|
152
|
+
break
|
153
|
+
end
|
154
|
+
break if $will_terminate_token
|
155
|
+
rescue IO::EAGAINWaitReadable
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def handle_signal(sig)
|
161
|
+
ProconBypassMan.logger.info "#{$$}で#{sig}を受け取りました"
|
162
|
+
case sig
|
163
|
+
when 'USR1'
|
164
|
+
raise InterruptForCouldNotConnect
|
165
|
+
when 'USR2'
|
166
|
+
raise InterruptForRestart
|
167
|
+
when 'INT', 'TERM'
|
168
|
+
raise Interrupt
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|