procon_bypass_man 0.1.2
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 +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
|