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.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -0
  3. data/.rubocop.yml +2 -0
  4. data/CHANGELOG.md +14 -0
  5. data/Gemfile +1 -1
  6. data/Gemfile.lock +13 -12
  7. data/README.md +14 -16
  8. data/bin/console +4 -0
  9. data/bin/{report_receive_server.rb → dev_api_server.rb} +8 -1
  10. data/lib/procon_bypass_man/background/has_server_pool.rb +54 -0
  11. data/lib/procon_bypass_man/background/http_client.rb +67 -0
  12. data/lib/procon_bypass_man/background/job_performer.rb +16 -0
  13. data/lib/procon_bypass_man/background/job_runnable.rb +16 -0
  14. data/lib/procon_bypass_man/background/job_runner.rb +45 -0
  15. data/lib/procon_bypass_man/background/jobs/base_job.rb +12 -0
  16. data/lib/procon_bypass_man/background/jobs/report_boot_job.rb +10 -0
  17. data/lib/procon_bypass_man/background/jobs/report_error_job.rb +10 -0
  18. data/lib/procon_bypass_man/background/jobs/report_heartbeat_job.rb +10 -0
  19. data/lib/procon_bypass_man/background/jobs/report_load_config_job.rb +10 -0
  20. data/lib/procon_bypass_man/background/jobs/report_pressed_buttons_job.rb +18 -0
  21. data/lib/procon_bypass_man/background/jobs/report_reload_config_job.rb +10 -0
  22. data/lib/procon_bypass_man/background.rb +12 -0
  23. data/lib/procon_bypass_man/boot_message.rb +13 -9
  24. data/lib/procon_bypass_man/{configuration → buttons_setting_configuration}/layer.rb +51 -30
  25. data/lib/procon_bypass_man/{configuration → buttons_setting_configuration}/loader.rb +12 -11
  26. data/lib/procon_bypass_man/{configuration → buttons_setting_configuration}/validator.rb +1 -1
  27. data/lib/procon_bypass_man/buttons_setting_configuration.rb +101 -0
  28. data/lib/procon_bypass_man/bypass/usb_hid_logger.rb +42 -0
  29. data/lib/procon_bypass_man/bypass.rb +57 -38
  30. data/lib/procon_bypass_man/commands/bypass_command.rb +86 -0
  31. data/lib/procon_bypass_man/commands/connect_device_command.rb +11 -0
  32. data/lib/procon_bypass_man/commands/print_boot_message_command.rb +9 -0
  33. data/lib/procon_bypass_man/commands/send_error_command.rb +19 -0
  34. data/lib/procon_bypass_man/commands/send_reload_config_event_command.rb +11 -0
  35. data/lib/procon_bypass_man/commands/write_device_id_command.rb +12 -0
  36. data/lib/procon_bypass_man/commands/write_session_id_command.rb +13 -0
  37. data/lib/procon_bypass_man/commands.rb +7 -0
  38. data/lib/procon_bypass_man/configuration.rb +92 -78
  39. data/lib/procon_bypass_man/device_connector.rb +31 -25
  40. data/lib/procon_bypass_man/io_monitor.rb +9 -4
  41. data/lib/procon_bypass_man/procon/analog_stick.rb +31 -0
  42. data/lib/procon_bypass_man/procon/analog_stick_cap.rb +9 -32
  43. data/lib/procon_bypass_man/procon/button_collection.rb +1 -0
  44. data/lib/procon_bypass_man/procon/{data.rb → consts.rb} +1 -1
  45. data/lib/procon_bypass_man/procon/layer_changer.rb +40 -0
  46. data/lib/procon_bypass_man/procon/macro_registry.rb +2 -2
  47. data/lib/procon_bypass_man/procon/mode_registry.rb +2 -2
  48. data/lib/procon_bypass_man/procon/user_operation.rb +15 -17
  49. data/lib/procon_bypass_man/procon.rb +15 -15
  50. data/lib/procon_bypass_man/procon_reader.rb +31 -0
  51. data/lib/procon_bypass_man/runner.rb +15 -113
  52. data/lib/procon_bypass_man/splatoon2/macro/fast_return.rb +15 -0
  53. data/lib/procon_bypass_man/splatoon2/macro/jump_to_left_key.rb +15 -0
  54. data/lib/procon_bypass_man/splatoon2/macro/jump_to_right_key.rb +15 -0
  55. data/lib/procon_bypass_man/splatoon2/macro/jump_to_up_key.rb +15 -0
  56. data/lib/procon_bypass_man/splatoon2/mode/guruguru.rb +57 -0
  57. data/lib/procon_bypass_man/splatoon2/version.rb +7 -0
  58. data/lib/procon_bypass_man/splatoon2.rb +11 -0
  59. data/lib/procon_bypass_man/support/callbacks.rb +70 -0
  60. data/lib/procon_bypass_man/support/compress_array.rb +56 -0
  61. data/lib/procon_bypass_man/{on_memory_cache.rb → support/on_memory_cache.rb} +0 -0
  62. data/lib/procon_bypass_man/{timer.rb → support/safe_timeout.rb} +1 -1
  63. data/lib/procon_bypass_man/support/signal_handler.rb +11 -0
  64. data/lib/procon_bypass_man/support/uptime.rb +25 -0
  65. data/lib/procon_bypass_man/version.rb +1 -1
  66. data/lib/procon_bypass_man.rb +41 -82
  67. data/procon_bypass_man.gemspec +2 -2
  68. data/project_template/README.md +19 -12
  69. data/project_template/app.rb +7 -8
  70. data/project_template/systemd_units/pbm_web.service +11 -0
  71. data/project_template/web.rb +16 -0
  72. data/sig/{README.rb → README.md} +0 -0
  73. data/sig/main.rbs +54 -16
  74. metadata +53 -22
  75. data/examples/practical/app.rb +0 -21
  76. data/examples/practical/setting.yml +0 -24
  77. data/lib/procon_bypass_man/analog_stick_position.rb +0 -14
  78. data/lib/procon_bypass_man/error_reporter.rb +0 -44
  79. data/lib/procon_bypass_man/procon/debug_dumper.rb +0 -17
  80. data/lib/procon_bypass_man/procon/layer_changeable.rb +0 -28
  81. data/lib/procon_bypass_man/procon/pressed_button_helper.rb +0 -15
  82. data/lib/procon_bypass_man/reporter.rb +0 -42
  83. data/lib/procon_bypass_man/uptime.rb +0 -13
@@ -1,7 +1,7 @@
1
1
  module ProconBypassMan
2
- class Configuration
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, FalseClass
23
- # sono mama
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
- if force_neutral
29
- case force_neutral
30
- when TrueClass, FalseClass
31
- raise "ボタンを渡してください"
32
- when Symbol, String
33
- hash[:force_neutral] = [force_neutral]
34
- when Array
35
- hash[:force_neutral] = force_neutral
36
- end
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 "not support class"
85
+ when TrueClass, FalseClass
86
+ raise "ボタンを渡してください"
81
87
  when Symbol, String
82
88
  if_pressed = [if_pressed]
83
- when Array, FalseClass
84
- # sono mama
85
- when NilClass
86
- if_pressed = nil
89
+ when Array, NilClass
90
+ # no-op
87
91
  else
88
- raise "not support if_pressed"
92
+ raise "not support value"
89
93
  end
90
94
 
91
- if force_neutral
92
- case force_neutral
93
- when TrueClass, FalseClass
94
- raise "ボタンを渡してください"
95
- when Symbol, String
96
- hash[:force_neutral] = [force_neutral]
97
- when Array
98
- hash[:force_neutral] = force_neutral
99
- end
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 Configuration
2
+ class ButtonsSettingConfiguration
3
3
  module Loader
4
4
  require 'digest/md5'
5
5
 
6
6
  def self.load(setting_path: )
7
- ProconBypassMan::Configuration.switch_new_context(:validation) do |validation_instance|
7
+ ProconBypassMan::ButtonsSettingConfiguration.switch_new_context(:validation) do |new_instance|
8
8
  yaml = YAML.load_file(setting_path) or raise "読み込みに失敗しました"
9
- validation_instance.instance_eval(yaml["setting"])
10
- validator = Validator.new(validation_instance)
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
- yaml = YAML.load_file(setting_path)
23
- ProconBypassMan::Configuration.instance.setting_path = setting_path
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::Configuration.instance.instance_eval(yaml["setting"])
30
+ ProconBypassMan::ButtonsSettingConfiguration.instance.instance_eval(yaml["setting"])
30
31
  else
31
32
  ProconBypassMan.logger.warn "不明なバージョンです。failoverします"
32
- ProconBypassMan::Configuration.instance.instance_eval(yaml["setting"])
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::Configuration.instance
38
+ ProconBypassMan::ButtonsSettingConfiguration.instance
38
39
  end
39
40
 
40
41
  def self.reload_setting
41
- self.load(setting_path: ProconBypassMan::Configuration.instance.setting_path)
42
+ self.load(setting_path: ProconBypassMan::ButtonsSettingConfiguration.instance.setting_path)
42
43
  end
43
44
  end
44
45
  end
@@ -1,5 +1,5 @@
1
1
  module ProconBypassMan
2
- class Configuration
2
+ class ButtonsSettingConfiguration
3
3
  class Validator
4
4
  def initialize(config)
5
5
  @layers = config.layers
@@ -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
- attr_accessor :gadget, :procon, :monitor
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
- begin
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
- begin
26
- self.procon.write_nonblock(input)
27
- rescue IO::EAGAINWaitReadable
28
- monitor.record(:eagain_wait_readable_on_write)
29
- return
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
- begin
40
- return if $will_terminate_token
41
- Timeout.timeout(1) do
42
- output = self.procon.read(64)
43
- ProconBypassMan.logger.debug { "<<< #{output.unpack("H*")}" }
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
- begin
58
- # ProconBypassMan::Procon::DebugDumper.new(binary: output).dump_analog_sticks
59
- self.gadget.write_nonblock(ProconBypassMan::Processor.new(output).process)
60
- rescue IO::EAGAINWaitReadable
61
- monitor.record(:eagain_wait_readable_on_write)
62
- return
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"