procon_bypass_man 0.1.12 → 0.1.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/release.yml +33 -0
  3. data/CHANGELOG.md +13 -0
  4. data/Gemfile +1 -1
  5. data/Gemfile.lock +35 -15
  6. data/README.md +19 -8
  7. data/lib/ext/em_pure_ruby.rb +25 -0
  8. data/lib/procon_bypass_man/background/job_runner.rb +6 -5
  9. data/lib/procon_bypass_man/background/jobs/base_job.rb +1 -6
  10. data/lib/procon_bypass_man/background/jobs/concerns/has_external_api_setting.rb +5 -0
  11. data/lib/procon_bypass_man/background/jobs/concerns/has_internal_api_setting.rb +5 -0
  12. data/lib/procon_bypass_man/background/{job_runnable.rb → jobs/concerns/job_runnable.rb} +0 -0
  13. data/lib/procon_bypass_man/background/jobs/report_boot_job.rb +5 -3
  14. data/lib/procon_bypass_man/background/jobs/report_error_job.rb +6 -5
  15. data/lib/procon_bypass_man/background/jobs/report_event_base_job.rb +5 -0
  16. data/lib/procon_bypass_man/background/jobs/report_load_config_job.rb +11 -0
  17. data/lib/procon_bypass_man/background/jobs/report_pressed_buttons_job.rb +7 -10
  18. data/lib/procon_bypass_man/background/jobs/report_reload_config_job.rb +5 -4
  19. data/lib/procon_bypass_man/background/jobs/sync_device_stats_job.rb +16 -0
  20. data/lib/procon_bypass_man/background.rb +7 -4
  21. data/lib/procon_bypass_man/buttons_setting_configuration/layer.rb +36 -35
  22. data/lib/procon_bypass_man/buttons_setting_configuration.rb +2 -2
  23. data/lib/procon_bypass_man/bypass/usb_hid_logger.rb +8 -6
  24. data/lib/procon_bypass_man/bypass.rb +13 -6
  25. data/lib/procon_bypass_man/commands/bypass_command.rb +86 -0
  26. data/lib/procon_bypass_man/commands/connect_device_command.rb +7 -2
  27. data/lib/procon_bypass_man/commands/print_boot_message_command.rb +51 -2
  28. data/lib/procon_bypass_man/commands/print_message_command.rb +8 -0
  29. data/lib/procon_bypass_man/commands/run_remote_pbm_action_dispatch_command.rb +21 -0
  30. data/lib/procon_bypass_man/commands/send_error_command.rb +2 -1
  31. data/lib/procon_bypass_man/commands/send_reload_config_event_command.rb +2 -2
  32. data/lib/procon_bypass_man/commands/write_device_id_command.rb +1 -0
  33. data/lib/procon_bypass_man/commands/write_session_id_command.rb +1 -7
  34. data/lib/procon_bypass_man/commands.rb +3 -0
  35. data/lib/procon_bypass_man/configuration.rb +51 -5
  36. data/lib/procon_bypass_man/device_connector.rb +32 -24
  37. data/lib/procon_bypass_man/device_status.rb +44 -0
  38. data/lib/procon_bypass_man/domains/binary/base.rb +11 -0
  39. data/lib/procon_bypass_man/domains/binary/has_immutable_binary.rb +5 -0
  40. data/lib/procon_bypass_man/domains/binary/has_mutable_binary.rb +5 -0
  41. data/lib/procon_bypass_man/domains/binary/inbound_procon_binary.rb +23 -0
  42. data/lib/procon_bypass_man/domains/binary/processing_procon_binary.rb +80 -0
  43. data/lib/procon_bypass_man/domains.rb +11 -0
  44. data/lib/procon_bypass_man/plugin/splatoon2/macro/fast_return.rb +17 -0
  45. data/lib/procon_bypass_man/plugin/splatoon2/macro/jump_to_left_key.rb +17 -0
  46. data/lib/procon_bypass_man/plugin/splatoon2/macro/jump_to_right_key.rb +17 -0
  47. data/lib/procon_bypass_man/plugin/splatoon2/macro/jump_to_up_key.rb +17 -0
  48. data/lib/procon_bypass_man/plugin/splatoon2/mode/guruguru.rb +59 -0
  49. data/lib/procon_bypass_man/plugin/splatoon2/version.rb +9 -0
  50. data/lib/procon_bypass_man/plugins.rb +11 -0
  51. data/lib/procon_bypass_man/processor.rb +4 -5
  52. data/lib/procon_bypass_man/procon/analog_stick_cap.rb +1 -1
  53. data/lib/procon_bypass_man/procon/button.rb +11 -0
  54. data/lib/procon_bypass_man/procon/button_collection.rb +2 -12
  55. data/lib/procon_bypass_man/procon/layer_changer.rb +3 -2
  56. data/lib/procon_bypass_man/procon/press_button_aware.rb +5 -4
  57. data/lib/procon_bypass_man/procon/user_operation.rb +46 -63
  58. data/lib/procon_bypass_man/procon/{analog_stick.rb → value_objects/analog_stick.rb} +3 -4
  59. data/lib/procon_bypass_man/procon/value_objects/procon_reader.rb +34 -0
  60. data/lib/procon_bypass_man/procon.rb +16 -14
  61. data/lib/procon_bypass_man/remote_pbm_action/base_action.rb +53 -0
  62. data/lib/procon_bypass_man/remote_pbm_action/change_pbm_version_action.rb +25 -0
  63. data/lib/procon_bypass_man/remote_pbm_action/commands/update_remote_pbm_action_status_command.rb +24 -0
  64. data/lib/procon_bypass_man/remote_pbm_action/reboot_os_action.rb +21 -0
  65. data/lib/procon_bypass_man/remote_pbm_action/restore_pbm_setting.rb +28 -0
  66. data/lib/procon_bypass_man/remote_pbm_action/stop_pbm_action.rb +21 -0
  67. data/lib/procon_bypass_man/remote_pbm_action/value_objects/remote_pbm_action_object.rb +38 -0
  68. data/lib/procon_bypass_man/remote_pbm_action.rb +32 -0
  69. data/lib/procon_bypass_man/runner.rb +8 -97
  70. data/lib/procon_bypass_man/scheduler.rb +85 -0
  71. data/lib/procon_bypass_man/{callbacks.rb → support/callbacks.rb} +0 -0
  72. data/lib/procon_bypass_man/support/compress_array.rb +56 -0
  73. data/lib/procon_bypass_man/support/http_client.rb +102 -0
  74. data/lib/procon_bypass_man/{on_memory_cache.rb → support/on_memory_cache.rb} +0 -0
  75. data/lib/procon_bypass_man/support/report_http_client.rb +19 -0
  76. data/lib/procon_bypass_man/{timer.rb → support/safe_timeout.rb} +1 -1
  77. data/lib/procon_bypass_man/support/send_device_stats_http_client.rb +9 -0
  78. data/lib/procon_bypass_man/{background/has_server_pool.rb → support/server_pool.rb} +3 -15
  79. data/lib/procon_bypass_man/support/signal_handler.rb +11 -0
  80. data/lib/procon_bypass_man/support/update_remote_pbm_action_status_http_client.rb +9 -0
  81. data/lib/procon_bypass_man/{uptime.rb → support/uptime.rb} +0 -0
  82. data/lib/procon_bypass_man/version.rb +1 -1
  83. data/lib/procon_bypass_man/websocket/pbm_job_client.rb +79 -0
  84. data/lib/procon_bypass_man.rb +68 -34
  85. data/procon_bypass_man.gemspec +5 -3
  86. data/project_template/README.md +18 -11
  87. data/project_template/app.rb +1 -2
  88. data/project_template/setting.yml +8 -8
  89. data/sig/{README.rb → README.md} +0 -0
  90. data/sig/main.rbs +16 -1
  91. metadata +102 -21
  92. data/lib/procon_bypass_man/background/http_client.rb +0 -70
  93. data/lib/procon_bypass_man/background/jobs/report_heartbeat_job.rb +0 -10
  94. data/lib/procon_bypass_man/boot_message.rb +0 -42
  95. data/lib/procon_bypass_man/procon_reader.rb +0 -31
@@ -5,7 +5,7 @@ class ProconBypassMan::Bypass
5
5
 
6
6
  class BypassValue < Struct.new(:binary, :sent)
7
7
  def to_text
8
- "#{binary.unpack("H*").first} #{'x' unless sent}"
8
+ "#{binary.unpack.first} #{'x' unless sent}"
9
9
  end
10
10
  end
11
11
 
@@ -21,14 +21,14 @@ class ProconBypassMan::Bypass
21
21
  def send_gadget_to_procon!
22
22
  monitor.record(:start_function)
23
23
  input = nil
24
- self.bypass_value = BypassValue.new(input, sent = false)
24
+ self.bypass_value = BypassValue.new(nil, sent = false)
25
25
 
26
26
  run_callbacks(:send_gadget_to_procon) do
27
27
  begin
28
28
  break if $will_terminate_token
29
29
  # TODO blocking readにしたいが、接続時のフェーズによって長さが違うので厳しい
30
30
  input = self.gadget.read_nonblock(64)
31
- self.bypass_value.binary = input
31
+ self.bypass_value.binary = ProconBypassMan::Domains::InboundProconBinary.new(binary: input)
32
32
  rescue IO::EAGAINWaitReadable
33
33
  monitor.record(:eagain_wait_readable_on_read)
34
34
  sleep(0.001)
@@ -50,14 +50,14 @@ class ProconBypassMan::Bypass
50
50
  def send_procon_to_gadget!
51
51
  monitor.record(:start_function)
52
52
  output = nil
53
- self.bypass_value = BypassValue.new(output, sent = false)
53
+ self.bypass_value = BypassValue.new(nil, sent = false)
54
54
 
55
55
  run_callbacks(:send_procon_to_gadget) do
56
56
  begin
57
57
  break if $will_terminate_token
58
58
  Timeout.timeout(1) do
59
59
  output = self.procon.read(64)
60
- self.bypass_value.binary = output
60
+ self.bypass_value.binary = ProconBypassMan::Domains::InboundProconBinary.new(binary: output)
61
61
  end
62
62
  rescue Timeout::Error
63
63
  ProconBypassMan.logger.debug { "read timeout! do sleep. by send_procon_to_gadget!" }
@@ -72,8 +72,15 @@ class ProconBypassMan::Bypass
72
72
  retry
73
73
  end
74
74
 
75
+ # blocking readをしているのでnilが入ることはないが、雑なテストでnilが通るので分岐を入れる。できれば消したい
76
+ break if output.nil?
77
+
75
78
  begin
76
- self.gadget.write_nonblock(ProconBypassMan::Processor.new(output).process)
79
+ self.gadget.write_nonblock(
80
+ ProconBypassMan::Processor.new(
81
+ ProconBypassMan::Domains::InboundProconBinary.new(binary: output)
82
+ ).process
83
+ )
77
84
  self.bypass_value.sent = true
78
85
  rescue IO::EAGAINWaitReadable
79
86
  monitor.record(:eagain_wait_readable_on_write)
@@ -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
@@ -2,8 +2,13 @@ class ProconBypassMan::ConnectDeviceCommand
2
2
  # @return [void]
3
3
  def self.execute!
4
4
  gadget, procon = ProconBypassMan::DeviceConnector.connect
5
- rescue ProconBypassMan::Timer::Timeout
6
- ::ProconBypassMan.logger.error "デバイスとの通信でタイムアウトが起きて接続ができませんでした。"
5
+ rescue ProconBypassMan::DeviceConnector::NotFoundProconError => e
6
+ ProconBypassMan.logger.error e
7
+ gadget&.close
8
+ procon&.close
9
+ raise ProconBypassMan::NotFoundProconError
10
+ rescue ProconBypassMan::SafeTimeout::Timeout
11
+ ProconBypassMan.logger.error "デバイスとの通信でタイムアウトが起きて接続ができませんでした。"
7
12
  gadget&.close
8
13
  procon&.close
9
14
  raise ::ProconBypassMan::EternalConnectionError
@@ -1,9 +1,58 @@
1
1
  class ProconBypassMan::PrintBootMessageCommand
2
+ class BootMessage
3
+ def initialize
4
+ @table = {}
5
+ @table[:ruby_version] = RUBY_VERSION
6
+ @table[:pbm_version] = ProconBypassMan::VERSION
7
+ @table[:pid] = $$
8
+ @table[:root_path] = ProconBypassMan.root
9
+ @table[:pid_path] = ProconBypassMan.pid_path
10
+ @table[:setting_path] = ProconBypassMan::ButtonsSettingConfiguration.instance.setting_path
11
+ @table[:uptime_from_boot] = ProconBypassMan::Uptime.from_boot
12
+ @table[:use_pbmenv] = !(!!`which pbmenv`.empty?)
13
+ @table[:session_id] = ProconBypassMan.session_id
14
+ @table[:device_id] = ProconBypassMan.device_id
15
+
16
+ # 開発中のHEADを取りたかったけど、Gem::Specification経由から取得する必要がありそう
17
+ # build_version = `git rev-parse --short HEAD`.chomp
18
+ # if build_version.empty?
19
+ # @table[:build_version] = 'release version'
20
+ # else
21
+ # @table[:build_version] = build_version
22
+ # end
23
+
24
+ # build version: #{@table[:build_version]}
25
+ end
26
+
27
+ # @return [String]
28
+ def to_s
29
+ booted_message = <<~EOF
30
+ ----
31
+ RUBY_VERSION: #{@table[:ruby_version]}
32
+ ProconBypassMan::VERSION: #{@table[:pbm_version]}
33
+ pid: #{@table[:pid]}
34
+ root: #{@table[:root_path]}
35
+ pid_path: #{@table[:pid_path]}
36
+ setting_path: #{@table[:setting_path]}
37
+ uptime from boot: #{@table[:uptime_from_boot]} sec
38
+ use_pbmenv: #{@table[:use_pbmenv]}
39
+ session_id: #{ProconBypassMan.session_id}
40
+ device_id: #{ProconBypassMan.device_id}
41
+ ----
42
+ EOF
43
+ end
44
+
45
+ # @return [Hash]
46
+ def to_hash
47
+ @table
48
+ end
49
+ end
50
+
2
51
  # @return [void]
3
52
  def self.execute
4
- message = ProconBypassMan::BootMessage.new
53
+ message = BootMessage.new
5
54
  ProconBypassMan::ReportBootJob.perform_async(message.to_hash)
6
- ProconBypassMan::ReportBootJob.perform_async(ProconBypassMan.config.raw_setting)
55
+ ProconBypassMan::ReportLoadConfigJob.perform_async(ProconBypassMan.config.raw_setting)
7
56
  puts message.to_s
8
57
  end
9
58
  end
@@ -0,0 +1,8 @@
1
+ class ProconBypassMan::PrintMessageCommand
2
+ # @return [void]
3
+ # @param [String] text
4
+ def self.execute(text: )
5
+ ProconBypassMan.logger.info text
6
+ puts text
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ class ProconBypassMan::RunRemotePbmActionDispatchCommand
2
+ # @param [String] action
3
+ # @param [String] uuid
4
+ # @return [void]
5
+ def self.execute(action: , uuid: , job_args: )
6
+ case action
7
+ when ProconBypassMan::RemotePbmAction::ACTION_CHANGE_PBM_VERSION
8
+ ProconBypassMan::RemotePbmAction::ChangePbmVersionAction.new(pbm_job_uuid: uuid).run!(job_args: job_args)
9
+ when ProconBypassMan::RemotePbmAction::ACTION_STOP_PBM
10
+ ProconBypassMan::RemotePbmAction::StopPbmAction.new(pbm_job_uuid: uuid).run!(job_args: {})
11
+ when ProconBypassMan::RemotePbmAction::ACTION_REBOOT_OS
12
+ ProconBypassMan::RemotePbmAction::RebootOsAction.new(pbm_job_uuid: uuid).run!(job_args: {})
13
+ when ProconBypassMan::RemotePbmAction::ACTION_RESTORE_SETTING
14
+ ProconBypassMan::RemotePbmAction::RestorePbmSettingAction.new(pbm_job_uuid: uuid).run!(job_args: job_args)
15
+ else
16
+ raise "#{action}は対応していないアクションです"
17
+ end
18
+ rescue ProconBypassMan::RemotePbmAction::ActionUnexpectedError => e
19
+ ProconBypassMan::SendErrorCommand.execute(error: e)
20
+ end
21
+ end
@@ -11,8 +11,9 @@ class ProconBypassMan::SendErrorCommand
11
11
  end
12
12
 
13
13
  ProconBypassMan.logger.error body
14
+ ProconBypassMan.error_logger.error body
14
15
  puts body
15
16
 
16
- ProconBypassMan::ReportErrorJob.perform_async(error)
17
+ ProconBypassMan::ReportErrorJob.perform(error)
17
18
  end
18
19
  end
@@ -1,7 +1,7 @@
1
1
  class ProconBypassMan::SendReloadConfigEventCommand
2
+ # @return [void]
2
3
  def self.execute
3
- puts "設定ファイルの再読み込みができました"
4
- ProconBypassMan.logger.info "設定ファイルの再読み込みができました"
4
+ ProconBypassMan::PrintMessageCommand.execute(text: "設定ファイルの再読み込みができました")
5
5
  ProconBypassMan::ReportReloadConfigJob.perform_async(
6
6
  ProconBypassMan.config.raw_setting
7
7
  )
@@ -1,4 +1,5 @@
1
1
  class ProconBypassMan::WriteDeviceIdCommand
2
+ # @return [String]
2
3
  def self.execute
3
4
  path = "#{ProconBypassMan.root}/device_id"
4
5
  if(sid = File.read(path))
@@ -2,12 +2,6 @@ class ProconBypassMan::WriteSessionIdCommand
2
2
  # @return [String] session_id ラズパイが起動してからshutdownするまで同じ文字列を返す
3
3
  # 起動すると/tmp がなくなる前提の実装
4
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
5
+ @@session_id ||= "s_#{SecureRandom.uuid}"
12
6
  end
13
7
  end
@@ -1,6 +1,9 @@
1
1
  require "procon_bypass_man/commands/print_boot_message_command"
2
+ require "procon_bypass_man/commands/print_message_command"
2
3
  require "procon_bypass_man/commands/write_session_id_command"
3
4
  require "procon_bypass_man/commands/write_device_id_command"
4
5
  require "procon_bypass_man/commands/send_reload_config_event_command"
5
6
  require "procon_bypass_man/commands/send_error_command"
6
7
  require "procon_bypass_man/commands/connect_device_command"
8
+ require "procon_bypass_man/commands/bypass_command"
9
+ require "procon_bypass_man/commands/run_remote_pbm_action_dispatch_command"
@@ -16,6 +16,11 @@ class ProconBypassMan::Configuration
16
16
  @@pid_path ||= File.expand_path("#{root}/pbm_pid", __dir__).freeze
17
17
  end
18
18
 
19
+ # @return [Integer]
20
+ def pid
21
+ File.read(pid_path).to_i
22
+ end
23
+
19
24
  def digest_path
20
25
  config.digest_path
21
26
  end
@@ -31,12 +36,12 @@ class ProconBypassMan::Configuration
31
36
 
32
37
  # @return [String]
33
38
  def device_id
34
- ProconBypassMan::WriteDeviceIdCommand.execute
39
+ ENV["DEBUG_DEVICE_ID"] || ProconBypassMan::WriteDeviceIdCommand.execute
35
40
  end
36
41
  end
37
42
 
38
- attr_accessor :enable_critical_error_logging, :raw_setting
39
- attr_writer :verbose_bypass_log
43
+ attr_accessor :enable_critical_error_logging
44
+ attr_writer :verbose_bypass_log, :raw_setting
40
45
 
41
46
  def root=(path)
42
47
  @root = path
@@ -75,11 +80,10 @@ class ProconBypassMan::Configuration
75
80
 
76
81
  def error_logger
77
82
  if enable_critical_error_logging
78
- @@error_logger ||= Logger.new("#{ProconBypassMan.root}/error.log", 5, 1024 * 1024 * 10)
83
+ @error_logger ||= Logger.new("#{ProconBypassMan.root}/error.log", 5, 1024 * 1024 * 10)
79
84
  else
80
85
  Logger.new(File.open("/dev/null"))
81
86
  end
82
- self
83
87
  end
84
88
 
85
89
  def digest_path
@@ -97,6 +101,44 @@ class ProconBypassMan::Configuration
97
101
  end
98
102
  end
99
103
 
104
+ # @return [Array<ProconBypassMan::ServerPool>]
105
+ def internal_server_pool
106
+ @internal_server_pool ||= ProconBypassMan::ServerPool.new(servers: internal_api_servers)
107
+ end
108
+
109
+ # @return [Array<ProconBypassMan::ServerPool>]
110
+ def server_pool
111
+ @server_pool ||= ProconBypassMan::ServerPool.new(servers: api_servers)
112
+ end
113
+
114
+ # @return [String, NilClass]
115
+ def current_server
116
+ server_pool.server
117
+ end
118
+
119
+ # @return [String, NilClass]
120
+ def current_ws_server
121
+ if (uri = URI.parse(server_pool.server))
122
+ if uri.port == 443
123
+ return "ws://#{uri.host}"
124
+ else
125
+ return "ws://#{uri.host}:#{uri.port}"
126
+ end
127
+ end
128
+ rescue URI::InvalidURIError
129
+ nil
130
+ end
131
+
132
+ # @return [String, NilClass]
133
+ def current_ws_server_url
134
+ return unless current_ws_server
135
+ "#{current_ws_server}/websocket/"
136
+ end
137
+
138
+ # @return [Boolean]
139
+ def enable_ws?; !!current_server; end
140
+
141
+ # @return [Array<String>]
100
142
  def api_servers
101
143
  if !!ENV["API_SERVER"]
102
144
  [ENV["API_SERVER"]].reject(&:nil?)
@@ -108,4 +150,8 @@ class ProconBypassMan::Configuration
108
150
  def verbose_bypass_log
109
151
  @verbose_bypass_log || !!ENV["VERBOSE_BYPASS_LOG"]
110
152
  end
153
+
154
+ def raw_setting
155
+ @raw_setting ||= {}
156
+ end
111
157
  end
@@ -1,5 +1,6 @@
1
1
  class ProconBypassMan::DeviceConnector
2
2
  class BytesMismatchError < StandardError; end
3
+ class NotFoundProconError < StandardError; end
3
4
 
4
5
  class Value
5
6
  attr_accessor :read_from, :values
@@ -48,6 +49,7 @@ class ProconBypassMan::DeviceConnector
48
49
  end
49
50
 
50
51
  def drain_all
52
+ debug_log_buffer = []
51
53
  unless @initialized_devices
52
54
  init_devices
53
55
  end
@@ -55,11 +57,13 @@ class ProconBypassMan::DeviceConnector
55
57
  while(item = @stack.shift)
56
58
  item.values.each do |value|
57
59
  data = nil
58
- timer = ProconBypassMan::Timer.new
60
+ timer = ProconBypassMan::SafeTimeout.new
59
61
  begin
60
62
  timer.throw_if_timeout!
61
63
  data = from_device(item).read_nonblock(64)
64
+ debug_log_buffer << "read_from(#{item.read_from}): #{data}"
62
65
  rescue IO::EAGAINWaitReadable
66
+ debug_log_buffer << "read_from(#{item.read_from}): IO::EAGAINWaitReadable"
63
67
  retry
64
68
  end
65
69
 
@@ -74,15 +78,19 @@ class ProconBypassMan::DeviceConnector
74
78
  end
75
79
  if result
76
80
  ProconBypassMan.logger.info "OK(expected: #{value}, got: #{data.unpack("H*")})"
81
+ debug_log_buffer << "OK(expected: #{value}, got: #{data.unpack("H*")})"
77
82
  else
78
83
  ProconBypassMan.logger.info "NG(expected: #{value}, got: #{data.unpack("H*")})"
84
+ debug_log_buffer << "NG(expected: #{value}, got: #{data.unpack("H*")})"
79
85
  raise BytesMismatchError if @throw_error_if_mismatch
80
86
  end
81
87
  to_device(item).write_nonblock(data)
82
88
  end
83
89
  end
84
- rescue ProconBypassMan::Timer::Timeout
90
+ rescue ProconBypassMan::SafeTimeout::Timeout
85
91
  ProconBypassMan.logger.error "timeoutになりました"
92
+ copressed_buffer_text = ProconBypassMan::CompressArray.new(debug_log_buffer).compress.join("\n")
93
+ ProconBypassMan::SendErrorCommand.execute(error: copressed_buffer_text)
86
94
  raise if @throw_error_if_timeout
87
95
  end
88
96
 
@@ -95,31 +103,31 @@ class ProconBypassMan::DeviceConnector
95
103
  init_devices
96
104
  end
97
105
 
98
- timer = ProconBypassMan::Timer.new
106
+ timer = ProconBypassMan::SafeTimeout.new
99
107
  data = nil
100
108
  begin
101
109
  timer.throw_if_timeout!
102
110
  switch.write_nonblock(data)
103
111
  rescue IO::EAGAINWaitReadable
104
112
  retry
105
- rescue ProconBypassMan::Timer::Timeout
113
+ rescue ProconBypassMan::SafeTimeout::Timeout
106
114
  ProconBypassMan.logger.error "writeでtimeoutになりました"
107
115
  raise
108
116
  end
109
117
  return(data.unpack("H*")) if only_write
110
118
 
111
- timer = ProconBypassMan::Timer.new
119
+ timer = ProconBypassMan::SafeTimeout.new
112
120
  begin
113
121
  timer.throw_if_timeout!
114
122
  data = switch.read_nonblock(64)
115
123
  ProconBypassMan.logger.debug { " >>> #{data.unpack("H*")})" }
116
124
  rescue IO::EAGAINWaitReadable
117
125
  retry
118
- rescue ProconBypassMan::Timer::Timeout
126
+ rescue ProconBypassMan::SafeTimeout::Timeout
119
127
  ProconBypassMan.logger.error "readでtimeoutになりました"
120
128
  raise
121
129
  end
122
- rescue ProconBypassMan::Timer::Timeout
130
+ rescue ProconBypassMan::SafeTimeout::Timeout
123
131
  raise if @throw_error_if_timeout
124
132
  end
125
133
 
@@ -131,30 +139,30 @@ class ProconBypassMan::DeviceConnector
131
139
  init_devices
132
140
  end
133
141
 
134
- timer = ProconBypassMan::Timer.new
142
+ timer = ProconBypassMan::SafeTimeout.new
135
143
  begin
136
144
  timer.throw_if_timeout!
137
145
  procon.write_nonblock(data)
138
146
  rescue IO::EAGAINWaitReadable
139
147
  retry
140
- rescue ProconBypassMan::Timer::Timeout
148
+ rescue ProconBypassMan::SafeTimeout::Timeout
141
149
  ProconBypassMan.logger.error "writeでtimeoutになりました"
142
150
  raise
143
151
  end
144
152
  return(data.unpack("H*")) if only_write
145
153
 
146
- timer = ProconBypassMan::Timer.new
154
+ timer = ProconBypassMan::SafeTimeout.new
147
155
  begin
148
156
  timer.throw_if_timeout!
149
157
  data = procon.read_nonblock(64)
150
158
  ProconBypassMan.logger.error " <<< #{data.unpack("H*")})"
151
159
  rescue IO::EAGAINWaitReadable
152
160
  retry
153
- rescue ProconBypassMan::Timer::Timeout
161
+ rescue ProconBypassMan::SafeTimeout::Timeout
154
162
  ProconBypassMan.logger.error "readでtimeoutになりました"
155
163
  raise
156
164
  end
157
- rescue ProconBypassMan::Timer::Timeout
165
+ rescue ProconBypassMan::SafeTimeout::Timeout
158
166
  raise if @throw_error_if_timeout
159
167
  end
160
168
 
@@ -164,30 +172,30 @@ class ProconBypassMan::DeviceConnector
164
172
  end
165
173
 
166
174
  data = nil
167
- timer = ProconBypassMan::Timer.new
175
+ timer = ProconBypassMan::SafeTimeout.new
168
176
  begin
169
177
  timer.throw_if_timeout!
170
178
  data = procon.read_nonblock(64)
171
179
  ProconBypassMan.logger.debug { " <<< #{data.unpack("H*")})" }
172
180
  rescue IO::EAGAINWaitReadable
173
181
  retry
174
- rescue ProconBypassMan::Timer::Timeout
182
+ rescue ProconBypassMan::SafeTimeout::Timeout
175
183
  ProconBypassMan.logger.error "readでtimeoutになりました"
176
184
  raise
177
185
  end
178
186
  return(data.unpack("H*")) if only_read
179
187
 
180
- timer = ProconBypassMan::Timer.new
188
+ timer = ProconBypassMan::SafeTimeout.new
181
189
  begin
182
190
  timer.throw_if_timeout!
183
191
  switch.write_nonblock(data)
184
192
  rescue IO::EAGAINWaitReadable
185
193
  retry
186
- rescue ProconBypassMan::Timer::Timeout
194
+ rescue ProconBypassMan::SafeTimeout::Timeout
187
195
  ProconBypassMan.logger.error "writeでtimeoutになりました"
188
196
  raise
189
197
  end
190
- rescue ProconBypassMan::Timer::Timeout
198
+ rescue ProconBypassMan::SafeTimeout::Timeout
191
199
  raise if @throw_error_if_timeout
192
200
  end
193
201
 
@@ -197,30 +205,30 @@ class ProconBypassMan::DeviceConnector
197
205
  end
198
206
 
199
207
  data = nil
200
- timer = ProconBypassMan::Timer.new
208
+ timer = ProconBypassMan::SafeTimeout.new
201
209
  begin
202
210
  timer.throw_if_timeout!
203
211
  data = switch.read_nonblock(64)
204
212
  ProconBypassMan.logger.debug { " >>> #{data.unpack("H*")})" }
205
213
  rescue IO::EAGAINWaitReadable
206
214
  retry
207
- rescue ProconBypassMan::Timer::Timeout
215
+ rescue ProconBypassMan::SafeTimeout::Timeout
208
216
  ProconBypassMan.logger.error "readでtimeoutになりました"
209
217
  raise
210
218
  end
211
219
  return(data.unpack("H*")) if only_read
212
220
 
213
- timer = ProconBypassMan::Timer.new
221
+ timer = ProconBypassMan::SafeTimeout.new
214
222
  begin
215
223
  timer.throw_if_timeout!
216
224
  procon.write_nonblock(data)
217
225
  rescue IO::EAGAINWaitReadable
218
226
  retry
219
- rescue ProconBypassMan::Timer::Timeout
227
+ rescue ProconBypassMan::SafeTimeout::Timeout
220
228
  ProconBypassMan.logger.error "writeでtimeoutになりました"
221
229
  raise
222
230
  end
223
- rescue ProconBypassMan::Timer::Timeout
231
+ rescue ProconBypassMan::SafeTimeout::Timeout
224
232
  raise if @throw_error_if_timeout
225
233
  end
226
234
 
@@ -293,7 +301,7 @@ class ProconBypassMan::DeviceConnector
293
301
  @procon = File.open(PROCON2_PATH, "w+b")
294
302
  @gadget = File.open('/dev/hidg0', "w+b")
295
303
  else
296
- raise "/dev/hidraw0, /dev/hidraw1の両方見つかりませんでした"
304
+ raise NotFoundProconError, "/dev/hidraw0, /dev/hidraw1の両方見つかりませんでした"
297
305
  end
298
306
  system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
299
307
  system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
@@ -312,7 +320,7 @@ class ProconBypassMan::DeviceConnector
312
320
  ProconBypassMan::SendErrorCommand.execute(error: "Errno::ENXIO (No such device or address @ rb_sysopen - /dev/hidg0)が起きました。resetします. #{e.full_message}")
313
321
  system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
314
322
  system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
315
- sleep 2
323
+ sleep 0.5
316
324
  retry
317
325
  end
318
326
  end
@@ -0,0 +1,44 @@
1
+ class ProconBypassMan::DeviceStatus
2
+ INITIALIZED = :initialized
3
+ RUNNING = :running
4
+ CONNECTED_BUT_SLEEPING = :connected_but_sleeping # コードはつながっているが、switchがsleepしているとき
5
+ PROCON_NOT_FOUND_ERROR = :procon_not_found_error # 繋がっていないとか、デバイスが使えない時
6
+ CONNECTED_BUT_ERROR = :connected_but_error # 実行時エラーあたり
7
+ SETTING_SYNTAX_ERROR_AND_SHUTDOWN = :setting_syntax_error_and_shutdown
8
+
9
+ @@status = nil
10
+
11
+ def self.current
12
+ @@status || INITIALIZED
13
+ end
14
+
15
+ def self.change_to_running!
16
+ @@status = RUNNING
17
+ ProconBypassMan::SyncDeviceStatsJob.perform_async(ProconBypassMan::DeviceStatus.current)
18
+ end
19
+
20
+ def self.change_to_connected_but_sleeping!
21
+ @@status = CONNECTED_BUT_SLEEPING
22
+ ProconBypassMan::SyncDeviceStatsJob.perform_async(ProconBypassMan::DeviceStatus.current)
23
+ end
24
+
25
+ def self.change_to_procon_not_found_error!
26
+ @@status = PROCON_NOT_FOUND_ERROR
27
+ ProconBypassMan::SyncDeviceStatsJob.perform_async(ProconBypassMan::DeviceStatus.current)
28
+ end
29
+
30
+ def self.change_to_device_error!
31
+ @@status = DEVICE_ERROR
32
+ ProconBypassMan::SyncDeviceStatsJob.perform_async(ProconBypassMan::DeviceStatus.current)
33
+ end
34
+
35
+ def self.change_to_connected_but_error!
36
+ @@status = CONNECTED_BUT_ERROR
37
+ ProconBypassMan::SyncDeviceStatsJob.perform_async(ProconBypassMan::DeviceStatus.current)
38
+ end
39
+
40
+ def self.change_to_setting_syntax_error_and_shutdown!
41
+ @@status = SETTING_SYNTAX_ERROR_AND_SHUTDOWN
42
+ ProconBypassMan::SyncDeviceStatsJob.perform_async(ProconBypassMan::DeviceStatus.current)
43
+ end
44
+ end
@@ -0,0 +1,11 @@
1
+ class ProconBypassMan::Domains::Binary::Base
2
+ # @param [String] binary
3
+ def initialize(binary: )
4
+ @binary = binary
5
+ end
6
+
7
+ # @return [String] バイナリ
8
+ def binary
9
+ raise NotImplementedError
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ module ProconBypassMan::Domains::HasImmutableBinary
2
+ def binary
3
+ @binary.freeze
4
+ end
5
+ end