procon_bypass_man 0.1.9 → 0.1.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +5 -0
- data/.rubocop.yml +2 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +13 -12
- data/README.md +14 -16
- data/bin/console +4 -0
- data/bin/{report_receive_server.rb → dev_api_server.rb} +8 -1
- data/lib/procon_bypass_man/background/has_server_pool.rb +54 -0
- data/lib/procon_bypass_man/background/http_client.rb +67 -0
- data/lib/procon_bypass_man/background/job_performer.rb +16 -0
- data/lib/procon_bypass_man/background/job_runnable.rb +16 -0
- data/lib/procon_bypass_man/background/job_runner.rb +45 -0
- data/lib/procon_bypass_man/background/jobs/base_job.rb +12 -0
- data/lib/procon_bypass_man/background/jobs/report_boot_job.rb +10 -0
- data/lib/procon_bypass_man/background/jobs/report_error_job.rb +10 -0
- data/lib/procon_bypass_man/background/jobs/report_heartbeat_job.rb +10 -0
- data/lib/procon_bypass_man/background/jobs/report_load_config_job.rb +10 -0
- data/lib/procon_bypass_man/background/jobs/report_pressed_buttons_job.rb +18 -0
- data/lib/procon_bypass_man/background/jobs/report_reload_config_job.rb +10 -0
- data/lib/procon_bypass_man/background.rb +12 -0
- data/lib/procon_bypass_man/boot_message.rb +13 -9
- data/lib/procon_bypass_man/{configuration → buttons_setting_configuration}/layer.rb +51 -30
- data/lib/procon_bypass_man/{configuration → buttons_setting_configuration}/loader.rb +12 -11
- data/lib/procon_bypass_man/{configuration → buttons_setting_configuration}/validator.rb +1 -1
- data/lib/procon_bypass_man/buttons_setting_configuration.rb +101 -0
- data/lib/procon_bypass_man/bypass/usb_hid_logger.rb +42 -0
- data/lib/procon_bypass_man/bypass.rb +57 -38
- data/lib/procon_bypass_man/commands/bypass_command.rb +86 -0
- data/lib/procon_bypass_man/commands/connect_device_command.rb +11 -0
- data/lib/procon_bypass_man/commands/print_boot_message_command.rb +9 -0
- data/lib/procon_bypass_man/commands/send_error_command.rb +19 -0
- data/lib/procon_bypass_man/commands/send_reload_config_event_command.rb +11 -0
- data/lib/procon_bypass_man/commands/write_device_id_command.rb +12 -0
- data/lib/procon_bypass_man/commands/write_session_id_command.rb +13 -0
- data/lib/procon_bypass_man/commands.rb +7 -0
- data/lib/procon_bypass_man/configuration.rb +92 -78
- data/lib/procon_bypass_man/device_connector.rb +31 -25
- data/lib/procon_bypass_man/io_monitor.rb +9 -4
- data/lib/procon_bypass_man/procon/analog_stick.rb +31 -0
- data/lib/procon_bypass_man/procon/analog_stick_cap.rb +9 -32
- data/lib/procon_bypass_man/procon/button_collection.rb +1 -0
- data/lib/procon_bypass_man/procon/{data.rb → consts.rb} +1 -1
- data/lib/procon_bypass_man/procon/layer_changer.rb +40 -0
- data/lib/procon_bypass_man/procon/macro_registry.rb +2 -2
- data/lib/procon_bypass_man/procon/mode_registry.rb +2 -2
- data/lib/procon_bypass_man/procon/user_operation.rb +15 -17
- data/lib/procon_bypass_man/procon.rb +15 -15
- data/lib/procon_bypass_man/procon_reader.rb +31 -0
- data/lib/procon_bypass_man/runner.rb +15 -113
- data/lib/procon_bypass_man/splatoon2/macro/fast_return.rb +15 -0
- data/lib/procon_bypass_man/splatoon2/macro/jump_to_left_key.rb +15 -0
- data/lib/procon_bypass_man/splatoon2/macro/jump_to_right_key.rb +15 -0
- data/lib/procon_bypass_man/splatoon2/macro/jump_to_up_key.rb +15 -0
- data/lib/procon_bypass_man/splatoon2/mode/guruguru.rb +57 -0
- data/lib/procon_bypass_man/splatoon2/version.rb +7 -0
- data/lib/procon_bypass_man/splatoon2.rb +11 -0
- data/lib/procon_bypass_man/support/callbacks.rb +70 -0
- data/lib/procon_bypass_man/support/compress_array.rb +56 -0
- data/lib/procon_bypass_man/{on_memory_cache.rb → support/on_memory_cache.rb} +0 -0
- data/lib/procon_bypass_man/{timer.rb → support/safe_timeout.rb} +1 -1
- data/lib/procon_bypass_man/support/signal_handler.rb +11 -0
- data/lib/procon_bypass_man/support/uptime.rb +25 -0
- data/lib/procon_bypass_man/version.rb +1 -1
- data/lib/procon_bypass_man.rb +41 -82
- data/procon_bypass_man.gemspec +2 -2
- data/project_template/README.md +19 -12
- data/project_template/app.rb +7 -8
- data/project_template/systemd_units/pbm_web.service +11 -0
- data/project_template/web.rb +16 -0
- data/sig/{README.rb → README.md} +0 -0
- data/sig/main.rbs +54 -16
- metadata +53 -22
- data/examples/practical/app.rb +0 -21
- data/examples/practical/setting.yml +0 -24
- data/lib/procon_bypass_man/analog_stick_position.rb +0 -14
- data/lib/procon_bypass_man/error_reporter.rb +0 -44
- data/lib/procon_bypass_man/procon/debug_dumper.rb +0 -17
- data/lib/procon_bypass_man/procon/layer_changeable.rb +0 -28
- data/lib/procon_bypass_man/procon/pressed_button_helper.rb +0 -15
- data/lib/procon_bypass_man/reporter.rb +0 -42
- data/lib/procon_bypass_man/uptime.rb +0 -13
@@ -1,7 +1,7 @@
|
|
1
1
|
module ProconBypassMan
|
2
|
-
class
|
2
|
+
class ButtonsSettingConfiguration
|
3
3
|
class Layer
|
4
|
-
attr_accessor :mode, :flips, :macros, :remaps, :left_analog_stick_caps
|
4
|
+
attr_accessor :mode, :flips, :macros, :remaps, :left_analog_stick_caps, :disables
|
5
5
|
|
6
6
|
def initialize(mode: :manual)
|
7
7
|
self.mode = mode
|
@@ -9,6 +9,7 @@ module ProconBypassMan
|
|
9
9
|
self.macros = {}
|
10
10
|
self.remaps = {}
|
11
11
|
self.left_analog_stick_caps = {}
|
12
|
+
self.disables = []
|
12
13
|
instance_eval(&block) if block_given?
|
13
14
|
end
|
14
15
|
|
@@ -19,21 +20,26 @@ module ProconBypassMan
|
|
19
20
|
if_pressed = [button]
|
20
21
|
when Symbol, String
|
21
22
|
if_pressed = [if_pressed]
|
22
|
-
when Array
|
23
|
-
#
|
23
|
+
when Array
|
24
|
+
# if_pressed = if_pressed
|
25
|
+
when FalseClass, NilClass
|
26
|
+
# no-op
|
24
27
|
else
|
25
28
|
raise "not support class"
|
26
29
|
end
|
30
|
+
|
27
31
|
hash = { if_pressed: if_pressed }
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
32
|
+
case force_neutral
|
33
|
+
when TrueClass
|
34
|
+
raise "ボタンを渡してください"
|
35
|
+
when Symbol, String
|
36
|
+
hash[:force_neutral] = [force_neutral]
|
37
|
+
when Array
|
38
|
+
hash[:force_neutral] = force_neutral
|
39
|
+
when FalseClass, NilClass
|
40
|
+
# no-op
|
41
|
+
else
|
42
|
+
raise "not support value"
|
37
43
|
end
|
38
44
|
|
39
45
|
if flip_interval
|
@@ -62,7 +68,7 @@ module ProconBypassMan
|
|
62
68
|
|
63
69
|
def remap(button, to: )
|
64
70
|
case to
|
65
|
-
when TrueClass, FalseClass
|
71
|
+
when TrueClass, FalseClass, NilClass
|
66
72
|
raise "ボタンを渡してください"
|
67
73
|
when Symbol, String
|
68
74
|
self.remaps[button] = { to: [to] }
|
@@ -76,32 +82,47 @@ module ProconBypassMan
|
|
76
82
|
hash = { cap: cap }
|
77
83
|
|
78
84
|
case if_pressed
|
79
|
-
when TrueClass
|
80
|
-
raise "
|
85
|
+
when TrueClass, FalseClass
|
86
|
+
raise "ボタンを渡してください"
|
81
87
|
when Symbol, String
|
82
88
|
if_pressed = [if_pressed]
|
83
|
-
when Array,
|
84
|
-
#
|
85
|
-
when NilClass
|
86
|
-
if_pressed = nil
|
89
|
+
when Array, NilClass
|
90
|
+
# no-op
|
87
91
|
else
|
88
|
-
raise "not support
|
92
|
+
raise "not support value"
|
89
93
|
end
|
90
94
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
95
|
+
case force_neutral
|
96
|
+
when TrueClass
|
97
|
+
raise "ボタンを渡してください"
|
98
|
+
when Symbol, String
|
99
|
+
hash[:force_neutral] = [force_neutral]
|
100
|
+
when Array
|
101
|
+
hash[:force_neutral] = force_neutral
|
102
|
+
when FalseClass, NilClass
|
103
|
+
# no-op
|
104
|
+
else
|
105
|
+
raise "not support value"
|
100
106
|
end
|
101
107
|
|
102
108
|
left_analog_stick_caps[if_pressed] = hash
|
103
109
|
end
|
104
110
|
|
111
|
+
def disable(button)
|
112
|
+
case button
|
113
|
+
when TrueClass, FalseClass, NilClass
|
114
|
+
raise "not support class"
|
115
|
+
when Symbol
|
116
|
+
disables << button
|
117
|
+
when String
|
118
|
+
disables << button.to_sym
|
119
|
+
when Array
|
120
|
+
button.each { |b| disables << b }
|
121
|
+
else
|
122
|
+
raise "not support value"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
105
126
|
# @return [Array]
|
106
127
|
def flip_buttons
|
107
128
|
flips
|
@@ -1,13 +1,13 @@
|
|
1
1
|
module ProconBypassMan
|
2
|
-
class
|
2
|
+
class ButtonsSettingConfiguration
|
3
3
|
module Loader
|
4
4
|
require 'digest/md5'
|
5
5
|
|
6
6
|
def self.load(setting_path: )
|
7
|
-
ProconBypassMan::
|
7
|
+
ProconBypassMan::ButtonsSettingConfiguration.switch_new_context(:validation) do |new_instance|
|
8
8
|
yaml = YAML.load_file(setting_path) or raise "読み込みに失敗しました"
|
9
|
-
|
10
|
-
validator = Validator.new(
|
9
|
+
new_instance.instance_eval(yaml["setting"])
|
10
|
+
validator = Validator.new(new_instance)
|
11
11
|
if validator.valid?
|
12
12
|
next
|
13
13
|
else
|
@@ -19,26 +19,27 @@ module ProconBypassMan
|
|
19
19
|
raise ProconBypassMan::CouldNotLoadConfigError, "yamlのシンタックスエラーです"
|
20
20
|
end
|
21
21
|
|
22
|
-
|
23
|
-
ProconBypassMan::
|
24
|
-
ProconBypassMan::Configuration.instance.reset!
|
22
|
+
ProconBypassMan::ButtonsSettingConfiguration.instance.setting_path = setting_path
|
23
|
+
ProconBypassMan::ButtonsSettingConfiguration.instance.reset!
|
25
24
|
ProconBypassMan.reset!
|
26
25
|
|
26
|
+
yaml = YAML.load_file(setting_path)
|
27
|
+
ProconBypassMan.config.raw_setting = yaml.dup
|
27
28
|
case yaml["version"]
|
28
29
|
when 1.0, nil
|
29
|
-
ProconBypassMan::
|
30
|
+
ProconBypassMan::ButtonsSettingConfiguration.instance.instance_eval(yaml["setting"])
|
30
31
|
else
|
31
32
|
ProconBypassMan.logger.warn "不明なバージョンです。failoverします"
|
32
|
-
ProconBypassMan::
|
33
|
+
ProconBypassMan::ButtonsSettingConfiguration.instance.instance_eval(yaml["setting"])
|
33
34
|
end
|
34
35
|
|
35
36
|
File.write(ProconBypassMan.digest_path, Digest::MD5.hexdigest(yaml["setting"]))
|
36
37
|
|
37
|
-
ProconBypassMan::
|
38
|
+
ProconBypassMan::ButtonsSettingConfiguration.instance
|
38
39
|
end
|
39
40
|
|
40
41
|
def self.reload_setting
|
41
|
-
self.load(setting_path: ProconBypassMan::
|
42
|
+
self.load(setting_path: ProconBypassMan::ButtonsSettingConfiguration.instance.setting_path)
|
42
43
|
end
|
43
44
|
end
|
44
45
|
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require "procon_bypass_man/buttons_setting_configuration/validator"
|
2
|
+
require "procon_bypass_man/buttons_setting_configuration/loader"
|
3
|
+
require "procon_bypass_man/buttons_setting_configuration/layer"
|
4
|
+
|
5
|
+
module ProconBypassMan
|
6
|
+
class AnalogStickPosition < Struct.new(:x, :y); end
|
7
|
+
|
8
|
+
class ButtonsSettingConfiguration
|
9
|
+
attr_accessor :layers,
|
10
|
+
:setting_path,
|
11
|
+
:mode_plugins,
|
12
|
+
:macro_plugins,
|
13
|
+
:context,
|
14
|
+
:current_context_key,
|
15
|
+
:neutral_position
|
16
|
+
|
17
|
+
def self.instance
|
18
|
+
@@current_context_key ||= :main
|
19
|
+
@@context ||= {}
|
20
|
+
@@context[@@current_context_key] ||= new
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.switch_new_context(key)
|
24
|
+
@@context[key] = new
|
25
|
+
previous_key = @@current_context_key
|
26
|
+
if block_given?
|
27
|
+
@@current_context_key = key
|
28
|
+
value = yield(@@context[key])
|
29
|
+
@@current_context_key = previous_key
|
30
|
+
return value
|
31
|
+
else
|
32
|
+
@@current_context_key = key
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize
|
37
|
+
reset!
|
38
|
+
end
|
39
|
+
|
40
|
+
module ManualMode
|
41
|
+
def self.name
|
42
|
+
'manual'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
def layer(direction, mode: ManualMode, &block)
|
46
|
+
mode_name = case mode
|
47
|
+
when String
|
48
|
+
mode.to_sym
|
49
|
+
when Symbol
|
50
|
+
mode
|
51
|
+
else
|
52
|
+
mode.name.to_sym
|
53
|
+
end
|
54
|
+
unless ([ManualMode.name.to_sym] + ProconBypassMan::Procon::ModeRegistry.plugins.keys).include?(mode_name)
|
55
|
+
raise("#{mode_name} mode is unknown")
|
56
|
+
end
|
57
|
+
|
58
|
+
layer = Layer.new(mode: mode_name)
|
59
|
+
layer.instance_eval(&block) if block_given?
|
60
|
+
self.layers[direction] = layer
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
def install_mode_plugin(klass)
|
65
|
+
ProconBypassMan::Procon::ModeRegistry.install_plugin(klass)
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
def install_macro_plugin(klass)
|
70
|
+
ProconBypassMan::Procon::MacroRegistry.install_plugin(klass)
|
71
|
+
self
|
72
|
+
end
|
73
|
+
|
74
|
+
def prefix_keys_for_changing_layer(buttons)
|
75
|
+
@prefix_keys_for_changing_layer = buttons
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
def set_neutral_position(x, y)
|
80
|
+
self.neutral_position = AnalogStickPosition.new(x, y).freeze
|
81
|
+
self
|
82
|
+
end
|
83
|
+
|
84
|
+
def prefix_keys
|
85
|
+
@prefix_keys_for_changing_layer
|
86
|
+
end
|
87
|
+
|
88
|
+
def reset!
|
89
|
+
@prefix_keys_for_changing_layer = []
|
90
|
+
self.mode_plugins = {}
|
91
|
+
self.macro_plugins = {}
|
92
|
+
self.layers = {
|
93
|
+
up: Layer.new,
|
94
|
+
down: Layer.new,
|
95
|
+
left: Layer.new,
|
96
|
+
right: Layer.new,
|
97
|
+
}
|
98
|
+
@neutral_position = AnalogStickPosition.new(2124, 1808).freeze
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class ProconBypassMan::Bypass
|
2
|
+
module UsbHidLogger
|
3
|
+
extend ProconBypassMan::Callbacks::ClassMethods
|
4
|
+
include ProconBypassMan::Callbacks
|
5
|
+
|
6
|
+
define_callbacks :send_gadget_to_procon
|
7
|
+
define_callbacks :send_procon_to_gadget
|
8
|
+
|
9
|
+
set_callback :send_gadget_to_procon, :after, :log_send_gadget_to_procon
|
10
|
+
set_callback :send_procon_to_gadget, :after, :log_procon_to_gadget
|
11
|
+
|
12
|
+
def log_send_gadget_to_procon
|
13
|
+
if ProconBypassMan.config.verbose_bypass_log
|
14
|
+
ProconBypassMan.logger.debug { ">>> #{bypass_value.to_text}" }
|
15
|
+
else
|
16
|
+
ProconBypassMan.cache.fetch key: 'bypass_log', expires_in: 1 do
|
17
|
+
ProconBypassMan.logger.debug { ">>> #{bypass_value.to_text}" }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def log_procon_to_gadget
|
23
|
+
if ProconBypassMan.config.verbose_bypass_log
|
24
|
+
ProconBypassMan.logger.debug { "<<< #{bypass_value.to_text}" }
|
25
|
+
else
|
26
|
+
ProconBypassMan.cache.fetch key: 'bypass_log', expires_in: 1 do
|
27
|
+
ProconBypassMan.logger.debug { "<<< #{bypass_value.to_text}" }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
ProconBypassMan.cache.fetch key: 'pressed_buttons_reporter', expires_in: 5 do
|
32
|
+
ProconBypassMan::ReportPressedButtonsJob.perform_async(
|
33
|
+
ProconBypassMan::ProconReader.new(binary: bypass_value.binary).to_hash
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
ProconBypassMan.cache.fetch key: 'heartbeat_reporter', expires_in: 60 do
|
38
|
+
ProconBypassMan::ReportHeartbeatJob.perform_async(ProconBypassMan::BootMessage.new.to_hash)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -1,5 +1,15 @@
|
|
1
|
+
require "procon_bypass_man/bypass/usb_hid_logger"
|
2
|
+
|
1
3
|
class ProconBypassMan::Bypass
|
2
|
-
|
4
|
+
include ProconBypassMan::Bypass::UsbHidLogger
|
5
|
+
|
6
|
+
class BypassValue < Struct.new(:binary, :sent)
|
7
|
+
def to_text
|
8
|
+
"#{binary.unpack("H*").first} #{'x' unless sent}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_accessor :gadget, :procon, :monitor, :bypass_value
|
3
13
|
|
4
14
|
def initialize(gadget: , procon: , monitor: )
|
5
15
|
self.gadget = gadget
|
@@ -11,22 +21,27 @@ class ProconBypassMan::Bypass
|
|
11
21
|
def send_gadget_to_procon!
|
12
22
|
monitor.record(:start_function)
|
13
23
|
input = nil
|
14
|
-
|
15
|
-
return if $will_terminate_token
|
16
|
-
# TODO blocking readにしたい
|
17
|
-
input = self.gadget.read_nonblock(64)
|
18
|
-
ProconBypassMan.logger.debug { ">>> #{input.unpack("H*")}" }
|
19
|
-
rescue IO::EAGAINWaitReadable
|
20
|
-
monitor.record(:eagain_wait_readable_on_read)
|
21
|
-
sleep(0.001)
|
22
|
-
retry
|
23
|
-
end
|
24
|
+
self.bypass_value = BypassValue.new(input, sent = false)
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
run_callbacks(:send_gadget_to_procon) do
|
27
|
+
begin
|
28
|
+
break if $will_terminate_token
|
29
|
+
# TODO blocking readにしたいが、接続時のフェーズによって長さが違うので厳しい
|
30
|
+
input = self.gadget.read_nonblock(64)
|
31
|
+
self.bypass_value.binary = input
|
32
|
+
rescue IO::EAGAINWaitReadable
|
33
|
+
monitor.record(:eagain_wait_readable_on_read)
|
34
|
+
sleep(0.001)
|
35
|
+
retry
|
36
|
+
end
|
37
|
+
|
38
|
+
begin
|
39
|
+
self.procon.write_nonblock(input)
|
40
|
+
self.bypass_value.sent = true
|
41
|
+
rescue IO::EAGAINWaitReadable
|
42
|
+
monitor.record(:eagain_wait_readable_on_write)
|
43
|
+
break
|
44
|
+
end
|
30
45
|
end
|
31
46
|
|
32
47
|
monitor.record(:end_function)
|
@@ -35,31 +50,35 @@ class ProconBypassMan::Bypass
|
|
35
50
|
def send_procon_to_gadget!
|
36
51
|
monitor.record(:start_function)
|
37
52
|
output = nil
|
53
|
+
self.bypass_value = BypassValue.new(output, sent = false)
|
38
54
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
55
|
+
run_callbacks(:send_procon_to_gadget) do
|
56
|
+
begin
|
57
|
+
break if $will_terminate_token
|
58
|
+
Timeout.timeout(1) do
|
59
|
+
output = self.procon.read(64)
|
60
|
+
self.bypass_value.binary = output
|
61
|
+
end
|
62
|
+
rescue Timeout::Error
|
63
|
+
ProconBypassMan.logger.debug { "read timeout! do sleep. by send_procon_to_gadget!" }
|
64
|
+
ProconBypassMan.error_logger.error { "read timeout! do sleep. by send_procon_to_gadget!" }
|
65
|
+
ProconBypassMan::SendErrorCommand.execute(error: "read timeout! do sleep. by send_procon_to_gadget!")
|
66
|
+
monitor.record(:eagain_wait_readable_on_read)
|
67
|
+
retry
|
68
|
+
rescue IO::EAGAINWaitReadable
|
69
|
+
ProconBypassMan.logger.debug { "EAGAINWaitReadable" }
|
70
|
+
monitor.record(:eagain_wait_readable_on_read)
|
71
|
+
sleep(0.005)
|
72
|
+
retry
|
44
73
|
end
|
45
|
-
rescue Timeout::Error
|
46
|
-
ProconBypassMan.logger.debug { "read timeout! do sleep. by send_procon_to_gadget!" }
|
47
|
-
ProconBypassMan.error_logger.error { "read timeout! do sleep. by send_procon_to_gadget!" }
|
48
|
-
monitor.record(:eagain_wait_readable_on_read)
|
49
|
-
retry
|
50
|
-
rescue IO::EAGAINWaitReadable
|
51
|
-
ProconBypassMan.logger.debug { "EAGAINWaitReadable" }
|
52
|
-
monitor.record(:eagain_wait_readable_on_read)
|
53
|
-
sleep(0.005)
|
54
|
-
retry
|
55
|
-
end
|
56
74
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
75
|
+
begin
|
76
|
+
self.gadget.write_nonblock(ProconBypassMan::Processor.new(output).process)
|
77
|
+
self.bypass_value.sent = true
|
78
|
+
rescue IO::EAGAINWaitReadable
|
79
|
+
monitor.record(:eagain_wait_readable_on_write)
|
80
|
+
break
|
81
|
+
end
|
63
82
|
end
|
64
83
|
monitor.record(:end_function)
|
65
84
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
class ProconBypassMan::BypassCommand
|
2
|
+
include ProconBypassMan::SignalHandler
|
3
|
+
|
4
|
+
def initialize(gadget:, procon:)
|
5
|
+
@gadget = gadget
|
6
|
+
@procon = procon
|
7
|
+
|
8
|
+
ProconBypassMan::IOMonitor.start!
|
9
|
+
ProconBypassMan::Background::JobRunner.queue.clear # forkしたときに残留物も移ってしまうため
|
10
|
+
ProconBypassMan::Background::JobRunner.start!
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute
|
14
|
+
self_read, self_write = IO.pipe
|
15
|
+
%w(TERM INT).each do |sig|
|
16
|
+
begin
|
17
|
+
trap sig do
|
18
|
+
self_write.puts(sig)
|
19
|
+
end
|
20
|
+
rescue ArgumentError
|
21
|
+
puts "プロセスでSignal #{sig} not supported"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# gadget => procon
|
26
|
+
# 遅くていい
|
27
|
+
monitor1 = ProconBypassMan::IOMonitor.new(label: "switch -> procon")
|
28
|
+
monitor2 = ProconBypassMan::IOMonitor.new(label: "procon -> switch")
|
29
|
+
ProconBypassMan.logger.info "Thread1を起動します"
|
30
|
+
t1 = Thread.new do
|
31
|
+
timer = ProconBypassMan::SafeTimeout.new(timeout: Time.now + 10)
|
32
|
+
bypass = ProconBypassMan::Bypass.new(gadget: @gadget, procon: @procon, monitor: monitor1)
|
33
|
+
loop do
|
34
|
+
break if $will_terminate_token
|
35
|
+
timer.throw_if_timeout!
|
36
|
+
bypass.send_gadget_to_procon!
|
37
|
+
sleep(0.005)
|
38
|
+
rescue ProconBypassMan::SafeTimeout::Timeout
|
39
|
+
ProconBypassMan.logger.info "10秒経過したのでThread1を終了します"
|
40
|
+
monitor1.shutdown
|
41
|
+
puts "10秒経過したのでThread1を終了します"
|
42
|
+
break
|
43
|
+
rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError => e
|
44
|
+
ProconBypassMan::SendErrorCommand.execute(error: "Switchとの切断されました.終了処理を開始します. #{e.full_message}")
|
45
|
+
Process.kill "TERM", Process.ppid
|
46
|
+
rescue Errno::ETIMEDOUT => e
|
47
|
+
# TODO まれにこれが発生する. 再接続したい
|
48
|
+
ProconBypassMan::SendErrorCommand.execute(error: "Switchと意図せず切断されました.終了処理を開始します. #{e.full_message}")
|
49
|
+
Process.kill "TERM", Process.ppid
|
50
|
+
end
|
51
|
+
ProconBypassMan.logger.info "Thread1を終了します"
|
52
|
+
end
|
53
|
+
|
54
|
+
# procon => gadget
|
55
|
+
# シビア
|
56
|
+
ProconBypassMan.logger.info "Thread2を起動します"
|
57
|
+
t2 = Thread.new do
|
58
|
+
bypass = ProconBypassMan::Bypass.new(gadget: @gadget, procon: @procon, monitor: monitor2)
|
59
|
+
loop do
|
60
|
+
break if $will_terminate_token
|
61
|
+
bypass.send_procon_to_gadget!
|
62
|
+
rescue EOFError => e
|
63
|
+
ProconBypassMan::SendErrorCommand.execute(error: "Proconが切断されました。終了処理を開始します. #{e.full_message}")
|
64
|
+
Process.kill "TERM", Process.ppid
|
65
|
+
rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError => e
|
66
|
+
ProconBypassMan::SendErrorCommand.execute(error: "Proconが切断されました。終了処理を開始します2. #{e.full_message}")
|
67
|
+
Process.kill "TERM", Process.ppid
|
68
|
+
end
|
69
|
+
ProconBypassMan.logger.info "Thread2を終了します"
|
70
|
+
end
|
71
|
+
|
72
|
+
ProconBypassMan.logger.info "子プロセスでgraceful shutdownの準備ができました"
|
73
|
+
begin
|
74
|
+
while(readable_io = IO.select([self_read]))
|
75
|
+
signal = readable_io.first[0].gets.strip
|
76
|
+
handle_signal(signal)
|
77
|
+
end
|
78
|
+
rescue Interrupt
|
79
|
+
$will_terminate_token = true
|
80
|
+
[t1, t2].each(&:join)
|
81
|
+
@gadget&.close
|
82
|
+
@procon&.close
|
83
|
+
exit 1
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class ProconBypassMan::ConnectDeviceCommand
|
2
|
+
# @return [void]
|
3
|
+
def self.execute!
|
4
|
+
gadget, procon = ProconBypassMan::DeviceConnector.connect
|
5
|
+
rescue ProconBypassMan::SafeTimeout::Timeout
|
6
|
+
::ProconBypassMan.logger.error "デバイスとの通信でタイムアウトが起きて接続ができませんでした。"
|
7
|
+
gadget&.close
|
8
|
+
procon&.close
|
9
|
+
raise ::ProconBypassMan::EternalConnectionError
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class ProconBypassMan::PrintBootMessageCommand
|
2
|
+
# @return [void]
|
3
|
+
def self.execute
|
4
|
+
message = ProconBypassMan::BootMessage.new
|
5
|
+
ProconBypassMan::ReportBootJob.perform_async(message.to_hash)
|
6
|
+
ProconBypassMan::ReportLoadConfigJob.perform_async(ProconBypassMan.config.raw_setting)
|
7
|
+
puts message.to_s
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class ProconBypassMan::SendErrorCommand
|
2
|
+
# @param [String, Hash, Exception] error
|
3
|
+
# @return [void]
|
4
|
+
def self.execute(error: )
|
5
|
+
body =
|
6
|
+
case error
|
7
|
+
when String, Hash
|
8
|
+
error
|
9
|
+
else
|
10
|
+
error.full_message
|
11
|
+
end
|
12
|
+
|
13
|
+
ProconBypassMan.logger.error body
|
14
|
+
ProconBypassMan.error_logger.error body
|
15
|
+
puts body
|
16
|
+
|
17
|
+
ProconBypassMan::ReportErrorJob.perform_async(error)
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class ProconBypassMan::SendReloadConfigEventCommand
|
2
|
+
# @return [void]
|
3
|
+
def self.execute
|
4
|
+
puts "設定ファイルの再読み込みができました"
|
5
|
+
ProconBypassMan.logger.info "設定ファイルの再読み込みができました"
|
6
|
+
ProconBypassMan::ReportReloadConfigJob.perform_async(
|
7
|
+
ProconBypassMan.config.raw_setting
|
8
|
+
)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class ProconBypassMan::WriteDeviceIdCommand
|
2
|
+
# @return [String]
|
3
|
+
def self.execute
|
4
|
+
path = "#{ProconBypassMan.root}/device_id"
|
5
|
+
if(sid = File.read(path))
|
6
|
+
return sid
|
7
|
+
end
|
8
|
+
rescue Errno::ENOENT
|
9
|
+
File.write(path, "m_#{SecureRandom.uuid}")
|
10
|
+
return SecureRandom.uuid
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class ProconBypassMan::WriteSessionIdCommand
|
2
|
+
# @return [String] session_id ラズパイが起動してからshutdownするまで同じ文字列を返す
|
3
|
+
# 起動すると/tmp がなくなる前提の実装
|
4
|
+
def self.execute
|
5
|
+
path = "/tmp/pbm_session_id"
|
6
|
+
if(sid = File.read(path))
|
7
|
+
return sid
|
8
|
+
end
|
9
|
+
rescue Errno::ENOENT
|
10
|
+
File.write(path, "s_#{SecureRandom.uuid}")
|
11
|
+
return SecureRandom.uuid
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
require "procon_bypass_man/commands/print_boot_message_command"
|
2
|
+
require "procon_bypass_man/commands/write_session_id_command"
|
3
|
+
require "procon_bypass_man/commands/write_device_id_command"
|
4
|
+
require "procon_bypass_man/commands/send_reload_config_event_command"
|
5
|
+
require "procon_bypass_man/commands/send_error_command"
|
6
|
+
require "procon_bypass_man/commands/connect_device_command"
|
7
|
+
require "procon_bypass_man/commands/bypass_command"
|