procon_bypass_man 0.2.2 → 0.2.3

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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +6 -6
  3. data/.rubocop.yml +4 -0
  4. data/.ruby-version +1 -1
  5. data/CHANGELOG.md +5 -0
  6. data/Gemfile.lock +1 -1
  7. data/README.md +15 -6
  8. data/Steepfile +0 -1
  9. data/docs/getting_started.md +48 -20
  10. data/docs/setup_raspi_by_mitamae.md +44 -2
  11. data/lib/procon_bypass_man/background/job_performer.rb +1 -2
  12. data/lib/procon_bypass_man/background/job_queue.rb +50 -0
  13. data/lib/procon_bypass_man/background/jobs/concerns/has_external_api_setting.rb +2 -2
  14. data/lib/procon_bypass_man/background/jobs/concerns/job_performable.rb +2 -2
  15. data/lib/procon_bypass_man/background/jobs/post_completed_remote_macro_job.rb +1 -1
  16. data/lib/procon_bypass_man/background/jobs/report_boot_job.rb +1 -1
  17. data/lib/procon_bypass_man/background/jobs/report_completed_upgrade_pbm_job.rb +1 -1
  18. data/lib/procon_bypass_man/background/jobs/report_error_job.rb +1 -1
  19. data/lib/procon_bypass_man/background/jobs/report_error_reload_config_job.rb +1 -1
  20. data/lib/procon_bypass_man/background/jobs/report_load_config_job.rb +1 -1
  21. data/lib/procon_bypass_man/background/jobs/report_procon_performance_measurements_job.rb +43 -0
  22. data/lib/procon_bypass_man/background/jobs/report_reload_config_job.rb +1 -1
  23. data/lib/procon_bypass_man/background/jobs/report_start_reboot_job.rb +1 -1
  24. data/lib/procon_bypass_man/background/jobs/sync_device_stats_job.rb +1 -1
  25. data/lib/procon_bypass_man/background.rb +2 -3
  26. data/lib/procon_bypass_man/bypass/bypass_command.rb +6 -15
  27. data/lib/procon_bypass_man/bypass/bypass_value.rb +6 -0
  28. data/lib/procon_bypass_man/bypass/procon_to_switch.rb +107 -0
  29. data/lib/procon_bypass_man/bypass/switch_to_procon.rb +64 -0
  30. data/lib/procon_bypass_man/bypass.rb +5 -110
  31. data/lib/procon_bypass_man/configuration.rb +15 -39
  32. data/lib/procon_bypass_man/device_connection/procon_setting_overrider.rb +12 -3
  33. data/lib/procon_bypass_man/procon/macro.rb +1 -1
  34. data/lib/procon_bypass_man/procon/performance_measurement/last_bypass_at.rb +17 -0
  35. data/lib/procon_bypass_man/procon/performance_measurement/measurement_collection.rb +9 -0
  36. data/lib/procon_bypass_man/procon/performance_measurement/measurements_summarizer.rb +84 -0
  37. data/lib/procon_bypass_man/procon/performance_measurement/procon_performance_span_transfer_job.rb +8 -0
  38. data/lib/procon_bypass_man/procon/performance_measurement/queue_over_process.rb +38 -0
  39. data/lib/procon_bypass_man/procon/performance_measurement/span_queue.rb +42 -0
  40. data/lib/procon_bypass_man/procon/performance_measurement/span_transfer_buffer.rb +39 -0
  41. data/lib/procon_bypass_man/procon/performance_measurement.rb +103 -0
  42. data/lib/procon_bypass_man/procon.rb +2 -1
  43. data/lib/procon_bypass_man/procon_display/bypass_hook.rb +4 -3
  44. data/lib/procon_bypass_man/remote_macro/queue_over_process.rb +26 -44
  45. data/lib/procon_bypass_man/remote_macro/remote_macro_object.rb +22 -24
  46. data/lib/procon_bypass_man/remote_macro/remote_macro_receiver.rb +1 -1
  47. data/lib/procon_bypass_man/remote_macro/remote_macro_sender.rb +1 -1
  48. data/lib/procon_bypass_man/remote_macro/task.rb +1 -5
  49. data/lib/procon_bypass_man/remote_macro/task_queue.rb +6 -10
  50. data/lib/procon_bypass_man/remote_pbm_action/commands/update_remote_pbm_action_status_command.rb +1 -1
  51. data/lib/procon_bypass_man/runner.rb +4 -10
  52. data/lib/procon_bypass_man/scheduler.rb +15 -6
  53. data/lib/procon_bypass_man/support/callbacks.rb +8 -4
  54. data/lib/procon_bypass_man/support/can_over_process.rb +60 -0
  55. data/lib/procon_bypass_man/support/gc.rb +8 -0
  56. data/lib/procon_bypass_man/support/http_client.rb +9 -6
  57. data/lib/procon_bypass_man/support/load_agv.rb +20 -0
  58. data/lib/procon_bypass_man/support/procon_performance_http_client.rb +7 -0
  59. data/lib/procon_bypass_man/support/retryable.rb +16 -0
  60. data/lib/procon_bypass_man/support/signal_handler.rb +1 -1
  61. data/lib/procon_bypass_man/version.rb +1 -1
  62. data/lib/procon_bypass_man/websocket/client.rb +2 -2
  63. data/lib/procon_bypass_man/worker.rb +32 -0
  64. data/lib/procon_bypass_man.rb +40 -10
  65. data/project_template/app.rb +4 -6
  66. data/project_template/app.rb.erb +4 -6
  67. data/sig/main.rbs +10 -52
  68. metadata +21 -8
  69. data/lib/procon_bypass_man/background/job_runner.rb +0 -45
  70. data/lib/procon_bypass_man/background/jobs/concerns/has_internal_api_setting.rb +0 -5
  71. data/lib/procon_bypass_man/background/jobs/report_pressed_buttons_job.rb +0 -15
  72. data/lib/procon_bypass_man/bypass/usb_hid_logger.rb +0 -43
  73. data/lib/procon_bypass_man/io_monitor.rb +0 -108
  74. data/lib/procon_bypass_man/support/server_pool.rb +0 -46
@@ -6,13 +6,9 @@ class ProconBypassMan::BypassCommand
6
6
  RESTART = :restart
7
7
  end
8
8
 
9
- def initialize(gadget:, procon:)
9
+ def initialize(gadget: , procon: )
10
10
  @gadget = gadget
11
11
  @procon = procon
12
-
13
- ProconBypassMan::IOMonitor.start! if ProconBypassMan.io_monitor_logging
14
- ProconBypassMan::Background::JobRunner.queue.clear # forkしたときに残留物も移ってしまうため
15
- ProconBypassMan::Background::JobRunner.start!
16
12
  end
17
13
 
18
14
  def execute
@@ -29,8 +25,6 @@ class ProconBypassMan::BypassCommand
29
25
 
30
26
  # gadget => procon
31
27
  # 遅くていい
32
- monitor1 = ProconBypassMan::IOMonitor.new(label: "switch -> procon")
33
- monitor2 = ProconBypassMan::IOMonitor.new(label: "procon -> switch")
34
28
  ProconBypassMan.logger.info "Thread1を起動します"
35
29
 
36
30
  cycle_sleep = ProconBypassMan::CycleSleep.new(cycle_interval: 1, execution_cycle: ProconBypassMan.config.bypass_mode.gadget_to_procon_interval)
@@ -38,16 +32,15 @@ class ProconBypassMan::BypassCommand
38
32
  t1 = Thread.new do
39
33
  if ProconBypassMan.config.bypass_mode.mode == ProconBypassMan::BypassMode::TYPE_AGGRESSIVE
40
34
  ProconBypassMan.logger.info "TYPE_AGGRESSIVEなのでThread1を終了します"
41
- monitor1.shutdown
42
35
  next
43
36
  end
44
37
 
38
+ bypass = ProconBypassMan::Bypass::SwitchToProcon.new(gadget: @gadget, procon: @procon)
45
39
  loop do
46
40
  break if $will_terminate_token
47
41
 
48
42
  cycle_sleep.sleep_or_execute do
49
- bypass = ProconBypassMan::Bypass.new(gadget: @gadget, procon: @procon, monitor: monitor1)
50
- bypass.send_gadget_to_procon!
43
+ bypass.run
51
44
  end
52
45
  rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError, Errno::ESHUTDOWN => e
53
46
  ProconBypassMan::SendErrorCommand.execute(error: "Switchとの切断されました.終了処理を開始します. #{e.full_message}")
@@ -63,9 +56,8 @@ class ProconBypassMan::BypassCommand
63
56
 
64
57
  # procon => gadget
65
58
  # シビア
66
- ProconBypassMan.logger.info "Thread2を起動します"
67
59
  t2 = Thread.new do
68
- bypass = ProconBypassMan::Bypass.new(gadget: @gadget, procon: @procon, monitor: monitor2)
60
+ bypass = ProconBypassMan::Bypass::ProconToSwitch.new(gadget: @gadget, procon: @procon)
69
61
  loop do
70
62
  if $will_terminate_token
71
63
  if $will_terminate_token == WILL_TERMINATE_TOKEN::TERMINATE
@@ -74,7 +66,7 @@ class ProconBypassMan::BypassCommand
74
66
  break
75
67
  end
76
68
 
77
- bypass.send_procon_to_gadget!
69
+ bypass.run
78
70
  rescue EOFError => e
79
71
  ProconBypassMan::SendErrorCommand.execute(error: "Proconが切断されました。終了処理を開始します. #{e.full_message}")
80
72
  Process.kill "TERM", Process.ppid
@@ -84,7 +76,6 @@ class ProconBypassMan::BypassCommand
84
76
  Process.kill "TERM", Process.ppid
85
77
  break
86
78
  end
87
- ProconBypassMan.logger.info "Thread2を終了します"
88
79
  end
89
80
 
90
81
  ProconBypassMan.logger.info "子プロセスでgraceful shutdownの準備ができました"
@@ -93,7 +84,7 @@ class ProconBypassMan::BypassCommand
93
84
  signal = readable_io.first[0].gets.strip
94
85
  handle_signal(signal)
95
86
  end
96
- rescue ProconBypassMan::Runner::InterruptForRestart
87
+ rescue ProconBypassMan::InterruptForRestart
97
88
  $will_terminate_token = WILL_TERMINATE_TOKEN::RESTART
98
89
  [t1, t2].each(&:join)
99
90
  @gadget&.close
@@ -0,0 +1,6 @@
1
+ class ProconBypassMan::Bypass::BypassValue < Struct.new(:binary)
2
+ def to_text
3
+ return unless binary
4
+ binary.unpack.first
5
+ end
6
+ end
@@ -0,0 +1,107 @@
1
+ require "procon_bypass_man/bypass/bypass_command"
2
+
3
+ class ProconBypassMan::Bypass::ProconToSwitch
4
+ extend ProconBypassMan::CallbacksRegisterable
5
+ include ProconBypassMan::Callbacks
6
+
7
+ class CouldNotReadFromProconError < StandardError; end
8
+ class CouldNotWriteToSwitchError < StandardError; end
9
+
10
+ define_callbacks :run
11
+ set_callback :run, :after, :log_after_run
12
+
13
+ register_callback_module(ProconBypassMan::ProconDisplay::BypassHook)
14
+
15
+ attr_accessor :gadget, :procon, :bypass_value, :procon_binary_queue
16
+
17
+ def initialize(gadget: , procon: )
18
+ self.gadget = gadget
19
+ self.procon = procon
20
+ end
21
+
22
+ # @raise [Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError, Errno::ESHUTDOWN, Errno::ETIMEDOUT]
23
+ # @return [void]
24
+ def run
25
+ ProconBypassMan::Procon::PerformanceMeasurement.measure do |measurement|
26
+ self.bypass_value = ProconBypassMan::Bypass::BypassValue.new(nil)
27
+
28
+ next(run_callbacks(:run) {
29
+ next(false) if $will_terminate_token
30
+
31
+ raw_output = nil
32
+ measurement.record_read_time do
33
+ begin
34
+ ProconBypassMan::GC.stop_gc_in do
35
+ return(false) if $will_terminate_token
36
+ raw_output = self.procon.read_nonblock(64)
37
+ end
38
+ rescue IO::EAGAINWaitReadable
39
+ sleep(0.002)
40
+ retry
41
+ rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError, Errno::ESHUTDOWN, Errno::ETIMEDOUT => e
42
+ return(false) if $will_terminate_token
43
+ raise
44
+ end
45
+ end
46
+
47
+ self.bypass_value.binary = ProconBypassMan::Domains::InboundProconBinary.new(binary: raw_output)
48
+
49
+ result = ProconBypassMan::GC.stop_gc_in do
50
+ result = measurement.record_write_time do
51
+ begin
52
+ ProconBypassMan::Retryable.retryable(tries: 5, on_no_retry: [Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError, Errno::ESHUTDOWN, Errno::ETIMEDOUT]) do
53
+ begin
54
+ # 終了処理を希望されているのでブロックを無視してメソッドを抜けてOK
55
+ return(false) if $will_terminate_token # rubocop:disable Lint/NoReturnInBeginEndBlocks
56
+ self.gadget.write_nonblock(
57
+ ProconBypassMan::Processor.new(bypass_value.binary).process
58
+ )
59
+ next(true)
60
+ rescue IO::EAGAINWaitReadable
61
+ return(false) if $will_terminate_token # rubocop:disable Lint/NoReturnInBeginEndBlocks
62
+ measurement.record_write_error
63
+ raise CouldNotWriteToSwitchError
64
+ rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError, Errno::ESHUTDOWN, Errno::ETIMEDOUT => e
65
+ return(false) if $will_terminate_token # rubocop:disable Lint/NoReturnInBeginEndBlocks
66
+ raise
67
+ end
68
+ end
69
+ rescue CouldNotWriteToSwitchError
70
+ next(false)
71
+ end
72
+ end
73
+
74
+ next(result)
75
+ end
76
+
77
+ next(result)
78
+ })
79
+ end
80
+ end
81
+
82
+ # @return [void]
83
+ def direct_connect_switch_via_bluetooth
84
+ ProconBypassMan.logger.debug { "direct_connect_switch_via_bluetooth!" }
85
+ self.procon.write_nonblock(["010500000000000000003800"].pack("H*")) # home led off
86
+ self.procon.write_nonblock(["010600000000000000003800"].pack("H*")) # home led off
87
+ self.procon.write_nonblock(["010700000000000000003800"].pack("H*")) # home led off
88
+ self.procon.write_nonblock(["010800000000000000003800"].pack("H*")) # home led off
89
+ self.procon.write_nonblock(["8005"].pack("H*"))
90
+ self.procon.write_nonblock(["8005"].pack("H*"))
91
+ self.procon.write_nonblock(["8005"].pack("H*"))
92
+ end
93
+
94
+ private
95
+
96
+ def log_after_run
97
+ return unless bypass_value.to_text
98
+
99
+ if ProconBypassMan.config.verbose_bypass_log
100
+ ProconBypassMan.logger.debug { "<<< #{bypass_value.to_text}" }
101
+ else
102
+ ProconBypassMan.cache.fetch key: 'bypass_log', expires_in: 1 do
103
+ ProconBypassMan.logger.debug { "<<< #{bypass_value.to_text}" }
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,64 @@
1
+ require "procon_bypass_man/bypass/bypass_command"
2
+
3
+ class ProconBypassMan::Bypass::SwitchToProcon
4
+ include ProconBypassMan::Callbacks
5
+
6
+ define_callbacks :run
7
+ set_callback :run, :after, :log_after_run
8
+
9
+ attr_accessor :gadget, :procon, :bypass_value
10
+
11
+ def initialize(gadget: , procon: )
12
+ self.gadget = gadget
13
+ self.procon = procon
14
+ end
15
+
16
+ # ゆっくりでいい
17
+ def run
18
+ self.bypass_value = ProconBypassMan::Bypass::BypassValue.new(nil)
19
+
20
+ run_callbacks(:run) do
21
+ next if $will_terminate_token
22
+
23
+ raw_input = nil
24
+ begin
25
+ raw_input = self.gadget.read_nonblock(64)
26
+ self.bypass_value.binary = ProconBypassMan::Domains::InboundProconBinary.new(binary: raw_input)
27
+ rescue IO::EAGAINWaitReadable
28
+ next
29
+ end
30
+
31
+ if self.bypass_value.binary
32
+ begin
33
+ raw_data =
34
+ case
35
+ when self.bypass_value.binary.rumble_data? # TODO そもそも無効になっているので消していい
36
+ binary = ProconBypassMan::RumbleBinary.new(binary: self.bypass_value.binary.raw)
37
+ binary.noop!
38
+ binary.raw
39
+ else
40
+ self.bypass_value.binary.raw
41
+ end
42
+ # バイブレーションを無効にしているのでおそらく書き込む必要はない
43
+ # self.procon.write_nonblock(raw_data)
44
+ rescue IO::EAGAINWaitReadable
45
+ next
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def log_after_run
54
+ return unless bypass_value.to_text
55
+
56
+ if ProconBypassMan.config.verbose_bypass_log
57
+ ProconBypassMan.logger.debug { ">>> #{bypass_value.to_text}" }
58
+ else
59
+ ProconBypassMan.cache.fetch key: 'bypass_log', expires_in: 1 do
60
+ ProconBypassMan.logger.debug { ">>> #{bypass_value.to_text}" }
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,111 +1,6 @@
1
- require "procon_bypass_man/bypass/usb_hid_logger"
2
- require "procon_bypass_man/bypass/bypass_command"
3
-
4
- class ProconBypassMan::Bypass
5
- extend ProconBypassMan::CallbacksRegisterable
6
-
7
- register_callback_module(ProconBypassMan::Bypass::UsbHidLogger)
8
- register_callback_module(ProconBypassMan::ProconDisplay::BypassHook)
9
-
10
- class BypassValue < Struct.new(:binary)
11
- def to_text
12
- return unless binary
13
- binary.unpack.first
14
- end
15
- end
16
-
17
- attr_accessor :gadget, :procon, :monitor, :bypass_value
18
-
19
- def initialize(gadget: , procon: , monitor: )
20
- self.gadget = gadget
21
- self.procon = procon
22
- self.monitor = monitor
23
- end
24
-
25
- # ゆっくりでいい
26
- def send_gadget_to_procon!
27
- monitor.record(:start_function)
28
- self.bypass_value = BypassValue.new(nil)
29
-
30
- run_callbacks(:send_gadget_to_procon) do
31
- break if $will_terminate_token
1
+ module ProconBypassMan::Bypass; end
32
2
 
33
- raw_input = nil
34
- begin
35
- raw_input = self.gadget.read_nonblock(64)
36
- self.bypass_value.binary = ProconBypassMan::Domains::InboundProconBinary.new(binary: raw_input)
37
- rescue IO::EAGAINWaitReadable
38
- monitor.record(:eagain_wait_readable_on_read)
39
- end
40
-
41
- if self.bypass_value.binary
42
- begin
43
- raw_data =
44
- case
45
- when self.bypass_value.binary.rumble_data?
46
- binary = ProconBypassMan::RumbleBinary.new(binary: self.bypass_value.binary.raw)
47
- binary.noop!
48
- binary.raw
49
- else
50
- self.bypass_value.binary.raw
51
- end
52
- self.procon.write_nonblock(raw_data)
53
- rescue IO::EAGAINWaitReadable
54
- monitor.record(:eagain_wait_readable_on_write)
55
- break
56
- end
57
- end
58
- end
59
-
60
- monitor.record(:end_function)
61
- end
62
-
63
- def send_procon_to_gadget!
64
- monitor.record(:start_function)
65
- self.bypass_value = BypassValue.new(nil)
66
-
67
- run_callbacks(:send_procon_to_gadget) do
68
- break if $will_terminate_token
69
-
70
- begin
71
- Timeout.timeout(1) do
72
- raw_output = self.procon.read(64)
73
- self.bypass_value.binary = ProconBypassMan::Domains::InboundProconBinary.new(binary: raw_output)
74
- end
75
- rescue Timeout::Error
76
- ProconBypassMan.logger.debug { "read timeout! do sleep. by send_procon_to_gadget!" }
77
- ProconBypassMan.error_logger.error { "read timeout! do sleep. by send_procon_to_gadget!" }
78
- ProconBypassMan::SendErrorCommand.execute(error: "read timeout! do sleep. by send_procon_to_gadget!")
79
- monitor.record(:eagain_wait_readable_on_read)
80
- retry
81
- rescue IO::EAGAINWaitReadable
82
- ProconBypassMan.logger.debug { "EAGAINWaitReadable" }
83
- monitor.record(:eagain_wait_readable_on_read)
84
- sleep(0.005)
85
- retry
86
- end
87
-
88
- begin
89
- self.gadget.write_nonblock(
90
- ProconBypassMan::Processor.new(bypass_value.binary).process
91
- )
92
- rescue IO::EAGAINWaitReadable
93
- monitor.record(:eagain_wait_readable_on_write)
94
- break
95
- end
96
- end
97
- monitor.record(:end_function)
98
- end
99
-
100
- # @return [void]
101
- def direct_connect_switch_via_bluetooth
102
- ProconBypassMan.logger.debug { "direct_connect_switch_via_bluetooth!" }
103
- self.procon.write_nonblock(["010500000000000000003800"].pack("H*")) # home led off
104
- self.procon.write_nonblock(["010600000000000000003800"].pack("H*")) # home led off
105
- self.procon.write_nonblock(["010700000000000000003800"].pack("H*")) # home led off
106
- self.procon.write_nonblock(["010800000000000000003800"].pack("H*")) # home led off
107
- self.procon.write_nonblock(["8005"].pack("H*"))
108
- self.procon.write_nonblock(["8005"].pack("H*"))
109
- self.procon.write_nonblock(["8005"].pack("H*"))
110
- end
111
- end
3
+ require "procon_bypass_man/bypass/bypass_command"
4
+ require "procon_bypass_man/bypass/bypass_value"
5
+ require "procon_bypass_man/bypass/procon_to_switch"
6
+ require "procon_bypass_man/bypass/switch_to_procon"
@@ -47,14 +47,15 @@ class ProconBypassMan::Configuration
47
47
  def fallback_setting_path
48
48
  "/tmp/procon_bypass_man_fallback_setting.yaml"
49
49
  end
50
-
51
- def io_monitor_logging
52
- config.io_monitor_logging
53
- end
54
50
  end
55
51
 
56
52
  attr_accessor :enable_critical_error_logging
57
- attr_writer :verbose_bypass_log, :raw_setting, :enable_reporting_pressed_buttons, :never_exit_accidentally, :io_monitor_logging, :enable_home_led_on_connect
53
+ attr_writer :verbose_bypass_log, :raw_setting, :never_exit_accidentally, :enable_home_led_on_connect
54
+ # 削除予定
55
+ attr_writer :enable_reporting_pressed_buttons
56
+
57
+ # NOTE 非推奨. 削除したいが設定ファイルに残っているときにエラーにしたくないので互換性維持のため残す
58
+ attr_writer :io_monitor_logging
58
59
 
59
60
  def root=(path)
60
61
  @root = path
@@ -114,35 +115,14 @@ class ProconBypassMan::Configuration
114
115
  "#{root}/.setting_yaml_digest"
115
116
  end
116
117
 
117
- # @return [String] pbm-webの接続先
118
- def internal_api_servers
119
- if !!ENV["INTERNAL_API_SERVER"]
120
- [ENV["INTERNAL_API_SERVER"]]
121
- else
122
- [ 'http://localhost:9090',
123
- 'http://localhost:8080',
124
- ].compact
125
- end
126
- end
127
-
128
- # @return [Array<ProconBypassMan::ServerPool>]
129
- def internal_server_pool
130
- @internal_server_pool ||= ProconBypassMan::ServerPool.new(servers: internal_api_servers)
131
- end
132
-
133
- # @return [Array<ProconBypassMan::ServerPool>]
134
- def server_pool
135
- @server_pool ||= ProconBypassMan::ServerPool.new(servers: api_servers)
136
- end
137
-
138
118
  # @return [String, NilClass]
139
- def current_server
140
- server_pool.server
119
+ def api_server
120
+ api_servers&.first
141
121
  end
142
122
 
143
123
  # @return [String, NilClass]
144
124
  def current_ws_server
145
- if (uri = URI.parse(server_pool.server))
125
+ if (uri = URI.parse(api_server))
146
126
  if uri.port == 443
147
127
  return "ws://#{uri.host}"
148
128
  else
@@ -161,7 +141,7 @@ class ProconBypassMan::Configuration
161
141
 
162
142
  # @return [Boolean]
163
143
  def enable_ws?
164
- !!current_server
144
+ !!api_server
165
145
  end
166
146
 
167
147
  # @return [Boolean]
@@ -178,8 +158,9 @@ class ProconBypassMan::Configuration
178
158
  end
179
159
  end
180
160
 
161
+ # @return [Boolean]
181
162
  def has_api_server?
182
- not api_servers.length.zero?
163
+ !!api_server
183
164
  end
184
165
 
185
166
  def verbose_bypass_log
@@ -190,19 +171,14 @@ class ProconBypassMan::Configuration
190
171
  @raw_setting ||= {}
191
172
  end
192
173
 
193
- # @return [Boolean] default false
194
- def enable_reporting_pressed_buttons
195
- @enable_reporting_pressed_buttons ||= false
196
- end
197
-
198
174
  # @return [Boolean] default false
199
175
  def never_exit_accidentally
200
176
  @never_exit_accidentally || false
201
177
  end
202
178
 
203
- # @return [Boolean] default false
204
- def io_monitor_logging
205
- @io_monitor_logging ||= false
179
+ # @return [Boolean] プロコンから「入力にかかっている時間」と「1秒間あたり何回入力できているか」をサーバに送信する
180
+ def enable_procon_performance_measurement?
181
+ has_api_server?
206
182
  end
207
183
 
208
184
  # @return [Boolean] default true
@@ -2,17 +2,26 @@ class ProconBypassMan::DeviceConnection::ProconSettingOverrider
2
2
  attr_accessor :procon, :output_report_watcher, :output_report_generator
3
3
 
4
4
  SUB_COMMAND_HOME_LED_ON = "38"
5
+ SUB_COMMAND_VIBRATION = "48"
6
+
5
7
  SUB_COMMAND_ARG_HOME_LED_ON = "1FF0FF"
8
+ SUB_COMMAND_ARG_VIBRATION_OFF = "00"
9
+
10
+ ALL_SETTINGS = {
11
+ home_led_on: [SUB_COMMAND_HOME_LED_ON, SUB_COMMAND_ARG_HOME_LED_ON],
12
+ vibration_off: [SUB_COMMAND_VIBRATION, SUB_COMMAND_ARG_VIBRATION_OFF],
13
+ }
14
+
15
+ # TODO 自動生成する
6
16
  SPECIAL_SUB_COMMAND_ARGS = {
7
17
  SUB_COMMAND_HOME_LED_ON => SUB_COMMAND_ARG_HOME_LED_ON,
18
+ SUB_COMMAND_VIBRATION => SUB_COMMAND_ARG_VIBRATION_OFF,
8
19
  }
9
- SETTING_HOME_LED_ON = { home_led_on: [SUB_COMMAND_HOME_LED_ON, SUB_COMMAND_ARG_HOME_LED_ON] }
10
- ALL_SETTINGS = SETTING_HOME_LED_ON
11
20
 
12
21
  def initialize(procon: )
13
22
  use_steps = {}
14
23
  if ProconBypassMan.config.enable_home_led_on_connect
15
- use_steps.merge!(SETTING_HOME_LED_ON)
24
+ use_steps.merge!(ALL_SETTINGS)
16
25
  end
17
26
 
18
27
  @setting_steps = use_steps.keys
@@ -99,7 +99,7 @@ class ProconBypassMan::Procon::Macro
99
99
 
100
100
  if nested_step.over?
101
101
  steps.shift # NestedStepを破棄する
102
- self.after_callback_block.call if self.after_callback_block
102
+ self.after_callback_block.call if self.after_callback_block && steps.empty?
103
103
  return next_step
104
104
  else
105
105
  return nested_step.next_step
@@ -0,0 +1,17 @@
1
+ class ProconBypassMan::Procon::PerformanceMeasurement::LastBypassAt
2
+ include Singleton
3
+
4
+ attr_accessor :mutex, :last_bypass_at
5
+
6
+ def initialize
7
+ self.mutex = Mutex.new
8
+ self.last_bypass_at = Time.now
9
+ end
10
+
11
+ def self.touch(&block)
12
+ instance.mutex.synchronize do
13
+ block.call(Time.now - instance.last_bypass_at)
14
+ instance.last_bypass_at = Time.now
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ # TODO SpanCollection にする
2
+ class ProconBypassMan::Procon::PerformanceMeasurement::MeasurementCollection
3
+ attr_accessor :timestamp_key, :spans
4
+
5
+ def initialize(timestamp_key: , spans: )
6
+ self.timestamp_key = timestamp_key
7
+ self.spans = spans
8
+ end
9
+ end
@@ -0,0 +1,84 @@
1
+ class ProconBypassMan::Procon::PerformanceMeasurement::MeasurementsSummarizer
2
+ class PerformanceMetric < Struct.new(:interval_from_previous_succeed_max,
3
+ :interval_from_previous_succeed_p50,
4
+ :write_time_max,
5
+ :write_time_p50,
6
+ :read_time_max,
7
+ :read_time_p50,
8
+ :time_taken_p50,
9
+ :time_taken_p95,
10
+ :time_taken_p99,
11
+ :time_taken_max,
12
+ :read_error_count,
13
+ :write_error_count,
14
+ :gc_count,
15
+ :gc_time,
16
+ :succeed_rate); end
17
+
18
+ def initialize(spans: )
19
+ @spans = spans
20
+ end
21
+
22
+ # @return [PerformanceMetric]
23
+ def summarize
24
+ sorted_write_time = @spans.map(&:write_time).sort
25
+ sorted_read_time = @spans.map(&:read_time).sort
26
+ gc_count = @spans.map(&:gc_count).sum
27
+ gc_time = @spans.map(&:gc_time).sum
28
+
29
+ sorted_time_taken = @spans.select(&:succeed).map(&:time_taken).sort
30
+ sorted_interval_from_previous_succeed = @spans.select(&:succeed).map(&:interval_from_previous_succeed).sort
31
+
32
+ interval_from_previous_succeed_max = sorted_interval_from_previous_succeed.last || 0
33
+ interval_from_previous_succeed_p50 = percentile(sorted_list: sorted_interval_from_previous_succeed , percentile: 0.50)
34
+
35
+ write_time_max = sorted_write_time.last || 0
36
+ write_time_p50 = percentile(sorted_list: sorted_write_time , percentile: 0.50)
37
+
38
+ read_time_max = sorted_read_time.last || 0
39
+ read_time_p50 = percentile(sorted_list: sorted_read_time , percentile: 0.50)
40
+
41
+ time_taken_p50 = percentile(sorted_list: sorted_time_taken, percentile: 0.50)
42
+ time_taken_p95 = percentile(sorted_list: sorted_time_taken, percentile: 0.95)
43
+ time_taken_p99 = percentile(sorted_list: sorted_time_taken, percentile: 0.99)
44
+ time_taken_max = sorted_time_taken.last || 0
45
+
46
+ total_read_error_count = @spans.map(&:read_error_count).sum
47
+ total_write_error_count = @spans.map(&:write_error_count).sum
48
+ succeed_rate =
49
+ if @spans.length.zero?
50
+ 0
51
+ else
52
+ succeed_rate = (sorted_time_taken.length / @spans.length.to_f).floor(3)
53
+ end
54
+
55
+ PerformanceMetric.new(interval_from_previous_succeed_max,
56
+ interval_from_previous_succeed_p50,
57
+ write_time_max,
58
+ write_time_p50,
59
+ read_time_max,
60
+ read_time_p50,
61
+ time_taken_p50,
62
+ time_taken_p95,
63
+ time_taken_p99,
64
+ time_taken_max,
65
+ total_read_error_count,
66
+ total_write_error_count,
67
+ gc_count,
68
+ gc_time,
69
+ succeed_rate)
70
+ end
71
+
72
+ private
73
+
74
+ # @param [Array<Numeric>] sorted_list
75
+ # @param [Float] percentile
76
+ # @return [Float]
77
+ def percentile(sorted_list: , percentile: )
78
+ return 0.0 if sorted_list.empty?
79
+ values_sorted = sorted_list
80
+ k = ((percentile*(values_sorted.length-1))+1).floor - 1
81
+ f = ((percentile*(values_sorted.length-1))+1).modulo(1)
82
+ return(values_sorted[k] + (f * (values_sorted[k+1] - values_sorted[k]))).floor(3)
83
+ end
84
+ end
@@ -0,0 +1,8 @@
1
+ # Bypassプロセスが収集したパフォーマンスメトリクスを、集計するためにmasterプロセスに転送するためジョブ
2
+ class ProconBypassMan::ProconPerformanceSpanTransferJob
3
+ extend ProconBypassMan::Background::JobPerformable
4
+
5
+ def self.perform(spans)
6
+ ProconBypassMan::Procon::PerformanceMeasurement::QueueOverProcess.push(spans)
7
+ end
8
+ end
@@ -0,0 +1,38 @@
1
+ class ProconBypassMan::Procon::PerformanceMeasurement::QueueOverProcess
2
+ extend ProconBypassMan::CanOverProcess
3
+
4
+ include Singleton
5
+
6
+ attr_reader :distributed_queue
7
+
8
+ # @override
9
+ def self.enable?
10
+ ProconBypassMan.config.enable_procon_performance_measurement?
11
+ end
12
+
13
+ # @override
14
+ def self.distributed_class
15
+ ProconBypassMan::Procon::PerformanceMeasurement::SpanQueue
16
+ end
17
+
18
+ # @override
19
+ def self.socket_file_path
20
+ "/tmp/procon_bypass_man_procon_performance_queue".freeze
21
+ end
22
+
23
+ def self.push(value)
24
+ return unless enable?
25
+
26
+ instance.distributed_queue.push(value)
27
+ end
28
+
29
+ def self.pop
30
+ return unless enable?
31
+
32
+ instance.distributed_queue.pop
33
+ end
34
+
35
+ def initialize
36
+ @distributed_queue = DRbObject.new_with_uri(self.class.socket_path)
37
+ end
38
+ end