procon_bypass_man 0.2.3 → 0.3.0

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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/Gemfile.lock +4 -2
  4. data/README.md +11 -33
  5. data/docs/getting_started.md +8 -0
  6. data/docs/setup_raspi_by_mitamae.md +0 -1
  7. data/lib/procon_bypass_man/bypass/bypass_command.rb +11 -6
  8. data/lib/procon_bypass_man/bypass/procon_to_switch.rb +34 -42
  9. data/lib/procon_bypass_man/bypass/switch_to_procon.rb +2 -0
  10. data/lib/procon_bypass_man/commands/print_boot_message_command.rb +0 -2
  11. data/lib/procon_bypass_man/configuration.rb +3 -0
  12. data/lib/procon_bypass_man/procon/analog_stick_manipulator.rb +2 -0
  13. data/lib/procon_bypass_man/procon/layer_changer.rb +2 -0
  14. data/lib/procon_bypass_man/procon/macro.rb +2 -0
  15. data/lib/procon_bypass_man/procon/macro_builder.rb +2 -0
  16. data/lib/procon_bypass_man/procon/macro_registry.rb +2 -0
  17. data/lib/procon_bypass_man/procon/performance_measurement/measurements_summarizer.rb +41 -24
  18. data/lib/procon_bypass_man/procon/performance_measurement/span_transfer_buffer.rb +1 -1
  19. data/lib/procon_bypass_man/procon/performance_measurement.rb +12 -5
  20. data/lib/procon_bypass_man/procon/suppress_rumble.rb +2 -0
  21. data/lib/procon_bypass_man/procon/user_operation.rb +2 -0
  22. data/lib/procon_bypass_man/procon/value_objects/analog_stick.rb +2 -0
  23. data/lib/procon_bypass_man/procon/value_objects/binary/inbound_procon_binary.rb +2 -0
  24. data/lib/procon_bypass_man/procon/value_objects/binary/processing_procon_binary.rb +2 -0
  25. data/lib/procon_bypass_man/procon/value_objects/rumble_binary.rb +2 -0
  26. data/lib/procon_bypass_man/procon.rb +24 -6
  27. data/lib/procon_bypass_man/remote_macro.rb +2 -0
  28. data/lib/procon_bypass_man/remote_pbm_action.rb +2 -0
  29. data/lib/procon_bypass_man/support/callbacks.rb +10 -3
  30. data/lib/procon_bypass_man/support/http_client.rb +3 -0
  31. data/lib/procon_bypass_man/support/renice_command.rb +17 -0
  32. data/lib/procon_bypass_man/version.rb +1 -1
  33. data/lib/procon_bypass_man.rb +18 -5
  34. data/procon_bypass_man.gemspec +3 -1
  35. data/project_template/app.rb +1 -4
  36. data/project_template/app.rb.erb +1 -4
  37. metadata +17 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dddf32b941507a57c7b2c5656879e132132f51eefcd64f29788567c81566c235
4
- data.tar.gz: e3649afcdb4877b41c6d05754ed77176d46a1fcc46a3d45751e15b1c91f6a23d
3
+ metadata.gz: 556a827cf03895e4212aa4c524963ca7efd24499c2ea14edff2d692bc3e1e63f
4
+ data.tar.gz: bf7cf5a735fffa13e1ff99c259a329a4c6981be755440477884ece0246188f21
5
5
  SHA512:
6
- metadata.gz: 231bb01ab26c17cdd6d044030a71479dfd1016d05e353de537e3ecd3978f5f4d23b2d8c4058e4f86cadbd555e3762e6124f7cb36920df2544c306e154d568bfe
7
- data.tar.gz: 8ae5c0a6b510d9b6dc22eb54fbf748e21e9b2b90671f00dc197baad2f90d00473ba4ee64f6ff148e7a200498df8f22edd738281979ab5e1240233a6bbc9e349b
6
+ metadata.gz: 7bdfd9d2c5bee033c8f6a1f87acebcf3374e353c0ea4d373c76f86ee33b87b248665b087276998f20dee9f0d1258ab2c7c49906cc55b94b51a5e35d84712da5c
7
+ data.tar.gz: 176ac515a48935df2953c36fb747e09be71c31f7850b09397e338bc0685b5da25bcd7ff81795d235287f2a5870fcdec3fec5aa9334e12ba90ca26662fe8807e7
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## [0.3.0] - 2022-9-9
2
+ * 表示入力機能を一時的に削除しました #185
3
+ * バイパス処理中の小さなラグがほぼなくなりました #185
4
+ * バイパス処理をマルチプロセスで行うようにしたのでGCによる停止時間がほぼなくなったため
5
+
1
6
  ## [0.2.3] - 2022-8-27
2
7
  * プロコンのラグ具合をpbm-cloudに送信し、グラフで見れるようになりました #158
3
8
  * 非同期ジョブをmasterプロセス経由で実行するようになりました #191
data/Gemfile.lock CHANGED
@@ -1,8 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- procon_bypass_man (0.2.3)
4
+ procon_bypass_man (0.3.0)
5
5
  action_cable_client
6
+ blue_green_process
6
7
  pbmenv (>= 0.1.9)
7
8
  sorted_set
8
9
 
@@ -18,6 +19,7 @@ GEM
18
19
  tzinfo (~> 2.0)
19
20
  zeitwerk (~> 2.3)
20
21
  ast (2.4.2)
22
+ blue_green_process (0.1.3)
21
23
  coderay (1.1.3)
22
24
  concurrent-ruby (1.1.9)
23
25
  diff-lcs (1.4.4)
@@ -78,7 +80,7 @@ GEM
78
80
  parser (>= 3.0.1.1)
79
81
  ruby-progressbar (1.11.0)
80
82
  ruby2_keywords (0.0.5)
81
- set (1.0.2)
83
+ set (1.0.3)
82
84
  sinatra (2.2.0)
83
85
  mustermann (~> 1.0)
84
86
  rack (~> 2.2)
data/README.md CHANGED
@@ -3,9 +3,7 @@
3
3
 
4
4
  [![Ruby](https://github.com/splaplapla/procon_bypass_man/actions/workflows/ruby.yml/badge.svg?branch=master)](https://github.com/splaplapla/procon_bypass_man/actions/workflows/ruby.yml)
5
5
 
6
- * Switchに繋いだプロコンを連射機にしたり、ボタンのリマップをしたり、マクロを実行できる、Raspberry Pi上で動かすツールです
7
- * 設定ファイルはrubyスクリプトで記述します
8
- * 特定のタイトルに特化した振る舞いにしたい時は各プラグインを使ってください
6
+ * Nintendo Switch Proコントローラーを連射機などにするRaspberry Pi上で動かすコンバータです
9
7
  * ドキュメントは [getting_started.md](docs/getting_started.md) にまとめています
10
8
  * https://pbm-cloud.herokuapp.com を使うと、webだけで運用が可能です
11
9
 
@@ -14,44 +12,17 @@
14
12
 
15
13
  https://user-images.githubusercontent.com/1664497/171327108-f12f56a5-fc36-48da-95a5-65e976553a20.mov
16
14
 
17
- <!--
18
- ![image](https://user-images.githubusercontent.com/1664497/123414210-942f6980-d5ee-11eb-8192-955bd9e37e0b.png)
19
- ```
20
- @startuml
21
- ProController \-\-> (PBM): ZR押しっぱなし
22
- Switch <-- (PBM): ZR連打
23
- @enduml
24
- ```
25
- -->
26
-
27
15
  ## 使うハードウェア
28
- * プロコン
16
+ * Nintendo Switch Proコントローラー
29
17
  * Switch本体とドック
30
- * Raspberry Pi4 Model B/4GB(Raspberry Pi OS (32-bit))
18
+ * Raspberry Pi4 (Raspberry Pi OS)
31
19
  * 他のシリーズは未確認です
32
- * zeroは非対応
33
20
  * データ通信が可能なUSBケーブル
34
21
 
35
22
  ## 使うソフトウェア
36
23
  * ruby 2.5 以上
37
24
 
38
- ## Usage
39
- * USBガジェットモードで起動するRaspberry Pi4を用意する
40
- * https://github.com/splaplapla/procon_bypass_man/blob/master/docs/setup_raspi.md
41
- * Raspberry Pi4 でprocon_bypass_manを実行するための準備
42
- * rubyのインストール
43
- * sudo apt-get install rbenv
44
- * git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build
45
- * rbenv install 3.0.1
46
- * gem install pbmenv
47
- * sudo [pbmenv](https://github.com/splaplapla/pbmenv) install latest
48
- * Raspberry Pi4 でprocon_bypass_manを実行する
49
- * cd /usr/share/pbm/current
50
- * sudo /home/pi/.rbenv/versions/3.0.1/bin/ruby app.rb
51
- * 動いたのを確認したらserviceとして登録にするなどしてください
52
- * [serviceとして登録する方法](https://github.com/splaplapla/procon_bypass_man/tree/master/project_template#systemd%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AB%E7%99%BB%E9%8C%B2%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95)
53
-
54
- ## Plugins
25
+ ## プラグイン
55
26
  * https://github.com/splaplapla/procon_bypass_man-splatoon2
56
27
 
57
28
  ## FAQ
@@ -109,6 +80,13 @@ sudo kill -USR2 `cat ./pbm_pid`
109
80
  * githubのreleaseを作成する
110
81
  -->
111
82
 
83
+ ## Raspberry Pi4のセットアップを代行します
84
+ * Raspberry Pi4を開発者である私の家に配送してくれれば、セットアップを代行します。セットアップが終わり次第送り返します
85
+ * 使い方に関しては、https://pbm-cloud.herokuapp.com ですべて完結するので、Linuxの知識は不要です
86
+ * 何か問題が起きた時はリモートログインでサポート可能です
87
+ * 希望者はDiscordの `kawagu#7684` にDMを送ってください
88
+ * お金はかかりません
89
+
112
90
  ## 開発を支援してくれる人を募集しています
113
91
  * https://jiikko.fanbox.cc/
114
92
  * procon_bypassの運営・開発・サーバー費用に充てさせていただきます。また、問い合わせに優先して対応します。
@@ -3,6 +3,7 @@
3
3
  * [はじめに](#はじめに)
4
4
  * [procon_bypass_manで解決したいこと](#procon_bypass_manで解決したいこと)
5
5
  * [procon_bypass_manでできること](#procon_bypass_manでできること)
6
+ * [セットアップを代行できます](#セットアップを代行できます)
6
7
  * [セットアップ](#セットアップ)
7
8
  * [ラズベリーパイのセットアップ](#ラズベリーパイのセットアップ)
8
9
  * [procon_bypass_manのインストール](#procon_bypass_manのインストール)
@@ -45,6 +46,13 @@
45
46
  * 入力表示
46
47
  * https://github.com/splaplapla/switch-procon-input-viewer
47
48
 
49
+ ## セットアップを代行できます
50
+ * Raspberry Pi4を開発者である私の家に配送してくれれば、セットアップを代行します。セットアップが終わり次第送り返します
51
+ * 使い方に関しては、https://pbm-cloud.herokuapp.com ですべて完結するので、Linuxの知識は不要です
52
+ * 何か問題が起きた時はリモートログインでサポート可能です
53
+ * 希望者はDiscordの `kawagu#7684` にDMを送ってください
54
+ * お金はかかりません
55
+
48
56
  ## セットアップ
49
57
  ### ラズベリーパイのセットアップ
50
58
 
@@ -38,7 +38,6 @@ sudo /home/pi/.rbenv/versions/3.0.1/bin/ruby app.rb
38
38
  use_pbmenv: true
39
39
  session_id: s_c6f36422-c20f-4a04-a446-b4a235c2face
40
40
  device_id: d_8b0c90d8-90*************************
41
- bypass_mode: normal(5)
42
41
  ----
43
42
  ```
44
43
 
@@ -30,11 +30,6 @@ class ProconBypassMan::BypassCommand
30
30
  cycle_sleep = ProconBypassMan::CycleSleep.new(cycle_interval: 1, execution_cycle: ProconBypassMan.config.bypass_mode.gadget_to_procon_interval)
31
31
 
32
32
  t1 = Thread.new do
33
- if ProconBypassMan.config.bypass_mode.mode == ProconBypassMan::BypassMode::TYPE_AGGRESSIVE
34
- ProconBypassMan.logger.info "TYPE_AGGRESSIVEなのでThread1を終了します"
35
- next
36
- end
37
-
38
33
  bypass = ProconBypassMan::Bypass::SwitchToProcon.new(gadget: @gadget, procon: @procon)
39
34
  loop do
40
35
  break if $will_terminate_token
@@ -58,22 +53,32 @@ class ProconBypassMan::BypassCommand
58
53
  # シビア
59
54
  t2 = Thread.new do
60
55
  bypass = ProconBypassMan::Bypass::ProconToSwitch.new(gadget: @gadget, procon: @procon)
56
+ process = BlueGreenProcess.new(worker_instance: bypass, max_work: 200)
61
57
  loop do
62
58
  if $will_terminate_token
63
59
  if $will_terminate_token == WILL_TERMINATE_TOKEN::TERMINATE
64
60
  bypass.direct_connect_switch_via_bluetooth
61
+ process.shutdown
65
62
  end
66
63
  break
67
64
  end
68
65
 
69
- bypass.run
66
+ process.work
67
+
68
+ process_switching_time_before_work = BlueGreenProcess.performance.process_switching_time_before_work
69
+ if process_switching_time_before_work > 0.1
70
+ ProconBypassMan.logger.info("slow process_switching_time_before_work: #{process_switching_time_before_work}")
71
+ end
72
+
70
73
  rescue EOFError => e
71
74
  ProconBypassMan::SendErrorCommand.execute(error: "Proconが切断されました。終了処理を開始します. #{e.full_message}")
72
75
  Process.kill "TERM", Process.ppid
76
+ process.shutdown
73
77
  break
74
78
  rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError, Errno::ESHUTDOWN => e
75
79
  ProconBypassMan::SendErrorCommand.execute(error: "Proconが切断されました。終了処理を開始します2. #{e.full_message}")
76
80
  Process.kill "TERM", Process.ppid
81
+ process.shutdown
77
82
  break
78
83
  end
79
84
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "procon_bypass_man/bypass/bypass_command"
2
4
 
3
5
  class ProconBypassMan::Bypass::ProconToSwitch
@@ -7,12 +9,13 @@ class ProconBypassMan::Bypass::ProconToSwitch
7
9
  class CouldNotReadFromProconError < StandardError; end
8
10
  class CouldNotWriteToSwitchError < StandardError; end
9
11
 
10
- define_callbacks :run
11
- set_callback :run, :after, :log_after_run
12
+ define_callbacks :work
13
+ set_callback :work, :after, :log_after_run
12
14
 
13
- register_callback_module(ProconBypassMan::ProconDisplay::BypassHook)
15
+ # マルチプロセス化したので一旦無効にする
16
+ # register_callback_module(ProconBypassMan::ProconDisplay::BypassHook)
14
17
 
15
- attr_accessor :gadget, :procon, :bypass_value, :procon_binary_queue
18
+ attr_accessor :gadget, :procon, :bypass_value
16
19
 
17
20
  def initialize(gadget: , procon: )
18
21
  self.gadget = gadget
@@ -21,20 +24,18 @@ class ProconBypassMan::Bypass::ProconToSwitch
21
24
 
22
25
  # @raise [Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError, Errno::ESHUTDOWN, Errno::ETIMEDOUT]
23
26
  # @return [void]
24
- def run
27
+ def work(*)
25
28
  ProconBypassMan::Procon::PerformanceMeasurement.measure do |measurement|
26
29
  self.bypass_value = ProconBypassMan::Bypass::BypassValue.new(nil)
27
30
 
28
- next(run_callbacks(:run) {
31
+ next(run_callbacks(:work) {
29
32
  next(false) if $will_terminate_token
30
33
 
31
34
  raw_output = nil
32
35
  measurement.record_read_time do
33
36
  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
37
+ return(false) if $will_terminate_token
38
+ raw_output = self.procon.read_nonblock(64)
38
39
  rescue IO::EAGAINWaitReadable
39
40
  sleep(0.002)
40
41
  retry
@@ -42,36 +43,32 @@ class ProconBypassMan::Bypass::ProconToSwitch
42
43
  return(false) if $will_terminate_token
43
44
  raise
44
45
  end
46
+
47
+ self.bypass_value.binary = ProconBypassMan::Domains::InboundProconBinary.new(binary: raw_output)
45
48
  end
46
49
 
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
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
68
67
  end
69
- rescue CouldNotWriteToSwitchError
70
- next(false)
71
68
  end
69
+ rescue CouldNotWriteToSwitchError
70
+ next(false)
72
71
  end
73
-
74
- next(result)
75
72
  end
76
73
 
77
74
  next(result)
@@ -94,14 +91,9 @@ class ProconBypassMan::Bypass::ProconToSwitch
94
91
  private
95
92
 
96
93
  def log_after_run
94
+ return unless ProconBypassMan.config.verbose_bypass_log
97
95
  return unless bypass_value.to_text
98
96
 
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
97
+ ProconBypassMan.logger.debug { "<<< #{bypass_value.to_text}" }
106
98
  end
107
99
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "procon_bypass_man/bypass/bypass_command"
2
4
 
3
5
  class ProconBypassMan::Bypass::SwitchToProcon
@@ -13,7 +13,6 @@ class ProconBypassMan::PrintBootMessageCommand
13
13
  @table[:use_pbmenv] = !(!!`which pbmenv`.empty?)
14
14
  @table[:session_id] = ProconBypassMan.session_id
15
15
  @table[:device_id] = ProconBypassMan.device_id
16
- @table[:bypass_mode] = ProconBypassMan.config.bypass_mode.to_s
17
16
  @table[:never_exit_accidentally] = ProconBypassMan.config.never_exit_accidentally
18
17
  @table[:uname] = `uname -a`.chomp
19
18
 
@@ -43,7 +42,6 @@ class ProconBypassMan::PrintBootMessageCommand
43
42
  use_pbmenv: #{@table[:use_pbmenv]}
44
43
  session_id: #{ProconBypassMan.session_id}
45
44
  device_id: #{ProconBypassMan.device_id.gsub(/.{25}$/, "*"*25)}
46
- bypass_mode: #{ProconBypassMan.config.bypass_mode}
47
45
  ----
48
46
  EOF
49
47
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ProconBypassMan::Configuration
2
4
  module ClassMethods
3
5
  def root
@@ -70,6 +72,7 @@ class ProconBypassMan::Configuration
70
72
  end
71
73
  end
72
74
 
75
+ # NOTE 不具合の原因は修正済みなので可変である必要は無くなった。削除したいが各端末内の設定ファイルに存在している場合があるのでしばらく残す
73
76
  def bypass_mode=(value)
74
77
  @bypass_mode = ProconBypassMan::BypassMode.new(
75
78
  mode: value[:mode],
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ProconBypassMan::Procon::AnalogStickManipulator
2
4
  attr_accessor :manipulated_abs_x, :manipulated_abs_y
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ProconBypassMan::Procon::LayerChanger
2
4
  # @param [ProconBypassMan::Domains::ProcessingProconBinary] binary
3
5
  def initialize(binary: )
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ProconBypassMan::Procon::Macro
2
4
  class BaseNestedStep
3
5
  def initialize(value)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ProconBypassMan::Procon::MacroBuilder
2
4
  class SubjectMerger
3
5
  def self.merge(subjects)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ProconBypassMan::Procon::MacroRegistry
2
4
  PRESETS = {
3
5
  null: [],
@@ -20,37 +20,54 @@ class ProconBypassMan::Procon::PerformanceMeasurement::MeasurementsSummarizer
20
20
  end
21
21
 
22
22
  # @return [PerformanceMetric]
23
+ # NOTE 中央値の表示価値が低いのでコメントアウト
23
24
  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
25
 
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
26
+ write_time_max = 0
27
+ read_time_max = 0
28
+ time_taken_max = 0
29
+ interval_from_previous_succeed_max = 0
30
+ @spans.each do |span|
31
+ # NOTE @spans.map(&:write_time).sort.last と同じことだけど、処理コストを軽くするためにループを共通化する
32
+ write_time_max = span.write_time if write_time_max < span.write_time
33
+ read_time_max = span.read_time if write_time_max < span.read_time
34
+ time_taken_max = span.time_taken if span.succeed && time_taken_max < span.time_taken
35
+ interval_from_previous_succeed_max = span.interval_from_previous_succeed if span.succeed && interval_from_previous_succeed_max < span.interval_from_previous_succeed
36
+ end
31
37
 
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)
38
+ # NOTE 今はGCを無効にしており、集計するまでもないのでコメントアウトにする. 今後GCを有効にしたバイパスをするかもしれないので残しておく
39
+ gc_count = 0 # @spans.map(&:gc_count).sum
40
+ gc_time = 0 # @spans.map(&:gc_time).sum
34
41
 
35
- write_time_max = sorted_write_time.last || 0
36
- write_time_p50 = percentile(sorted_list: sorted_write_time , percentile: 0.50)
42
+ # sorted_interval_from_previous_succeed = @spans.select(&:succeed).map(&:interval_from_previous_succeed).sort
43
+ # interval_from_previous_succeed_max = sorted_interval_from_previous_succeed.last || 0
44
+ interval_from_previous_succeed_p50 = 0 # percentile(sorted_list: sorted_interval_from_previous_succeed , percentile: 0.50)
37
45
 
38
- read_time_max = sorted_read_time.last || 0
39
- read_time_p50 = percentile(sorted_list: sorted_read_time , percentile: 0.50)
46
+ # sorted_read_time = @spans.map(&:read_time).sort
47
+ read_time_p50 = 0 # percentile(sorted_list: sorted_read_time , percentile: 0.50)
48
+ # read_time_max = sorted_read_time.last || 0
40
49
 
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
50
+ # sorted_write_time = @spans.map(&:write_time).sort
51
+ write_time_p50 = 0 # percentile(sorted_list: sorted_write_time , percentile: 0.50)
52
+ # write_time_max = sorted_write_time.last || 0
45
53
 
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
+ # sorted_time_taken = @spans.select(&:succeed).map(&:time_taken).sort
55
+ time_taken_p50 = 0 # percentile(sorted_list: sorted_time_taken, percentile: 0.50)
56
+ time_taken_p95 = 0 # percentile(sorted_list: sorted_time_taken, percentile: 0.95)
57
+ time_taken_p99 = 0 # percentile(sorted_list: sorted_time_taken, percentile: 0.99)
58
+ # time_taken_max = sorted_time_taken.last || 0
59
+
60
+ # NOTE webに表示していないのでコメントアウト. デバッグ時に見ることがあるので残しておく
61
+ total_read_error_count = 0 # @spans.map(&:read_error_count).sum
62
+ total_write_error_count = 0 # @spans.map(&:write_error_count).sum
63
+
64
+ # succeed_rate =
65
+ # if @spans.length.zero?
66
+ # 0
67
+ # else
68
+ # succeed_rate = (sorted_time_taken.length / @spans.length.to_f).floor(3)
69
+ # end
70
+ succeed_rate = 1 # Switchへの書き込みに失敗した時にretryしているので100%になるようになってる. succeedの個数をカウントコストを減らすためにハードコード
54
71
 
55
72
  PerformanceMetric.new(interval_from_previous_succeed_max,
56
73
  interval_from_previous_succeed_p50,
@@ -34,6 +34,6 @@ class ProconBypassMan::Procon::PerformanceMeasurement::SpanTransferBuffer
34
34
  end
35
35
 
36
36
  def max_buffer
37
- 200
37
+ 50
38
38
  end
39
39
  end
@@ -45,6 +45,13 @@ module ProconBypassMan::Procon::PerformanceMeasurement
45
45
  end
46
46
  end
47
47
 
48
+ # 全部送ると負荷になるので適当にまびく
49
+ def self.is_not_measure_with_random_or_if_fast(span: )
50
+ return false if span.time_taken > 0.1
51
+ return true if rand(20) != 0 # 19/20は捨てる
52
+ return false
53
+ end
54
+
48
55
  # measureをして、measureの結果をためる
49
56
  # @return [Boolean] 成功したか. テスト時に戻り値を使いたい
50
57
  def self.measure(&bypass_process_block)
@@ -63,6 +70,8 @@ module ProconBypassMan::Procon::PerformanceMeasurement
63
70
  span.succeed = bypass_process_block.call(span)
64
71
  }.floor(3)
65
72
 
73
+ return if is_not_measure_with_random_or_if_fast(span: span)
74
+
66
75
  if span.succeed
67
76
  ProconBypassMan::Procon::PerformanceMeasurement::LastBypassAt.touch do |interval_from_previous_succeed|
68
77
  span.interval_from_previous_succeed = interval_from_previous_succeed.floor(3)
@@ -79,11 +88,9 @@ module ProconBypassMan::Procon::PerformanceMeasurement
79
88
  end
80
89
  end
81
90
 
82
- ProconBypassMan::GC.stop_gc_in do
83
- # measureするたびにperform_asyncしているとjob queueが詰まるのでbufferingしている
84
- ProconBypassMan::Procon::PerformanceMeasurement::SpanTransferBuffer.instance.push_and_run_block_if_buffer_over(span) do |spans|
85
- ProconBypassMan::ProconPerformanceSpanTransferJob.perform_async(spans.dup)
86
- end
91
+ # measureするたびにperform_asyncしているとjob queueが詰まるのでbufferingしている
92
+ ProconBypassMan::Procon::PerformanceMeasurement::SpanTransferBuffer.instance.push_and_run_block_if_buffer_over(span) do |spans|
93
+ ProconBypassMan::ProconPerformanceSpanTransferJob.perform_async(spans)
87
94
  end
88
95
  return span.succeed
89
96
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ProconBypassMan::SuppressRumble
2
4
  # @param [String] binary
3
5
  def initialize(binary: )
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # ボタンを押しているか判断するクラス。バイナリの書き換えはしない
2
4
  class ProconBypassMan::Procon::UserOperation
3
5
  attr_reader :binary
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ProconBypassMan::Procon::AnalogStick
2
4
  attr_accessor :neutral_position
3
5
  attr_writer :bin_x, :bin_y
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # proconから取得したばかりのバイナリ
2
4
  class ProconBypassMan::Domains::InboundProconBinary < ProconBypassMan::Domains::Binary::Base
3
5
  include ProconBypassMan::Domains::HasImmutableBinary
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # バイナリの書き換えのみをする
2
4
  class ProconBypassMan::Domains::ProcessingProconBinary < ProconBypassMan::Domains::Binary::Base
3
5
  include ProconBypassMan::Domains::HasMutableBinary
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ProconBypassMan::RumbleBinary
2
4
  # @param [String] binary
3
5
  def initialize(binary: )
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "procon_bypass_man/procon/macro_plugin_map"
2
4
 
3
5
  class ProconBypassMan::Procon
@@ -25,11 +27,11 @@ class ProconBypassMan::Procon
25
27
 
26
28
  def self.reset!
27
29
  @@status = {
28
- buttons: {},
29
- current_layer_key: :up,
30
30
  ongoing_macro: MacroRegistry.load(:null),
31
- ongoing_mode: ModeRegistry.load(:manual),
31
+ ongoing_mode: ModeRegistry.load(:manual), # 削除予定
32
32
  }
33
+ BlueGreenProcess::SharedVariable.instance.data["buttons"] = {}
34
+ BlueGreenProcess::SharedVariable.instance.data["current_layer_key"] = :up
33
35
  @@left_stick_tilting_power_scaler = ProconBypassMan::AnalogStickTiltingPowerScaler.new
34
36
  end
35
37
  reset!
@@ -41,10 +43,20 @@ class ProconBypassMan::Procon
41
43
  )
42
44
  end
43
45
 
44
- def status; @@status[:buttons]; end
46
+ def status
47
+ BlueGreenProcess::SharedVariable.instance.data["buttons"]
48
+ end
49
+
50
+ def current_layer_key
51
+ BlueGreenProcess::SharedVariable.instance.data["current_layer_key"].to_sym
52
+ end
53
+
54
+ def current_layer_key=(layer)
55
+ BlueGreenProcess::SharedVariable.instance.data["current_layer_key"] = layer
56
+ end
57
+
45
58
  def ongoing_macro; @@status[:ongoing_macro]; end
46
59
  def ongoing_mode; @@status[:ongoing_mode]; end
47
- def current_layer_key; @@status[:current_layer_key]; end
48
60
 
49
61
  def current_layer
50
62
  ProconBypassMan::ButtonsSettingConfiguration.instance.layers[current_layer_key]
@@ -54,7 +66,7 @@ class ProconBypassMan::Procon
54
66
  def apply!
55
67
  layer_changer = ProconBypassMan::Procon::LayerChanger.new(binary: user_operation.binary)
56
68
  if layer_changer.change_layer?
57
- @@status[:current_layer_key] = layer_changer.next_layer_key if layer_changer.pressed_next_layer?
69
+ self.current_layer_key = layer_changer.next_layer_key if layer_changer.pressed_next_layer?
58
70
  user_operation.set_no_action!
59
71
  return
60
72
  end
@@ -97,10 +109,14 @@ class ProconBypassMan::Procon
97
109
 
98
110
  # remote macro
99
111
  if task = ProconBypassMan::RemoteMacro::TaskQueueInProcess.non_blocking_shift
112
+ no_op_step = :wait_for_0_3 # マクロの最後に固まって最後の入力をし続けるので、無の状態を最後に注入する
113
+ BlueGreenProcess::SharedVariable.extend_run_on_this_process = true
100
114
  ProconBypassMan::Procon::MacroRegistry.cleanup_remote_macros!
101
115
  macro_name = task.name || "RemoteMacro-#{task.steps.join}".to_sym
116
+ task.steps << no_op_step
102
117
  ProconBypassMan::Procon::MacroRegistry.install_plugin(macro_name, steps: task.steps, macro_type: :remote)
103
118
  @@status[:ongoing_macro] = MacroRegistry.load(macro_name, macro_type: :remote) do
119
+ GC.start # NOTE: extend_run_on_this_process = true するとGCされなくなるので手動で呼び出す
104
120
  ProconBypassMan::PostCompletedRemoteMacroJob.perform_async(task.uuid)
105
121
  end
106
122
  end
@@ -110,6 +126,7 @@ class ProconBypassMan::Procon
110
126
  @@status[:ongoing_mode] = ModeRegistry.load(:manual)
111
127
  current_layer.flip_buttons.each do |button, options|
112
128
  if !options[:if_pressed]
129
+ # FIXME マルチプロセス化したので、クラス変数に状態を保持するFlipCacheは意図した挙動にならない. BlueGreenProcess.shared_variables を使って状態をプロセス間で共有すれば動く
113
130
  FlipCache.fetch(key: button, expires_in: options[:flip_interval]) do
114
131
  status[button] = !status[button]
115
132
  end
@@ -146,6 +163,7 @@ class ProconBypassMan::Procon
146
163
  end
147
164
 
148
165
  if ongoing_macro.ongoing? && (step = ongoing_macro.next_step)
166
+ BlueGreenProcess::SharedVariable.extend_run_on_this_process = true
149
167
  ongoing_macro.force_neutral_buttons&.each do |force_neutral_button|
150
168
  user_operation.unpress_button(force_neutral_button)
151
169
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ProconBypassMan
2
4
  module RemoteMacro
3
5
  require "procon_bypass_man/remote_macro/remote_macro_object"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ProconBypassMan
2
4
  module RemotePbmAction
3
5
  require "procon_bypass_man/remote_pbm_action/base_action"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ProconBypassMan
2
4
  module CallbacksRegisterable
3
5
  attr_accessor :callbacks
@@ -93,9 +95,14 @@ module ProconBypassMan
93
95
  return self.class.__callbacks[kind.to_sym]
94
96
  end
95
97
 
96
- list = self.class.callbacks.flat_map { |callback_mod|
97
- callback_mod.__callbacks && callback_mod.__callbacks[kind.to_sym]
98
- }.compact
98
+ list =
99
+ if self.class.callbacks.nil?
100
+ []
101
+ else
102
+ self.class.callbacks.flat_map { |callback_mod|
103
+ callback_mod.__callbacks && callback_mod.__callbacks[kind.to_sym]
104
+ }.compact
105
+ end
99
106
  if(self.class.respond_to?(:__callbacks) && chain = self.class.__callbacks[kind.to_sym])
100
107
  list << chain
101
108
  end
@@ -34,6 +34,7 @@ module ProconBypassMan
34
34
 
35
35
  def get
36
36
  handle_request do
37
+ ProconBypassMan.logger.info "[HTTP] GET #{@uri}"
37
38
  response = HttpRequest::Get.request!(
38
39
  uri: @uri,
39
40
  )
@@ -44,6 +45,7 @@ module ProconBypassMan
44
45
  def post(request_body: )
45
46
  handle_request do
46
47
  body = {}.merge!(request_body)
48
+ ProconBypassMan.logger.info "[HTTP] POST #{@uri}"
47
49
  response = HttpRequest::Post.request!(
48
50
  uri: @uri,
49
51
  request_body: body,
@@ -57,6 +59,7 @@ module ProconBypassMan
57
59
  body = {
58
60
  hostname: `hostname`.chomp,
59
61
  }.merge!(request_body)
62
+ ProconBypassMan.logger.info "[HTTP] PUT #{@uri}"
60
63
  response = HttpRequest::Put.request!(
61
64
  uri: @uri,
62
65
  request_body: body,
@@ -0,0 +1,17 @@
1
+ module ProconBypassMan
2
+ class ReniceCommand
3
+ def self.change_priority(to: , pid: )
4
+ cmd =
5
+ case to
6
+ when :high
7
+ "renice -n -20 -p #{pid}"
8
+ when :low
9
+ "renice -n 20 -p #{pid}"
10
+ else
11
+ raise "unknown priority"
12
+ end
13
+ ProconBypassMan.logger.debug { "[SHELL] #{cmd}" }
14
+ `#{cmd}`
15
+ end
16
+ end
17
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ProconBypassMan
4
- VERSION = "0.2.3"
4
+ VERSION = "0.3.0"
5
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "logger"
2
4
  require 'yaml'
3
5
  require "json"
@@ -10,6 +12,7 @@ require "ext/em_pure_ruby"
10
12
  require "ext/module"
11
13
  require "resolv-replace"
12
14
  require "pbmenv"
15
+ require "blue_green_process"
13
16
 
14
17
  require_relative "procon_bypass_man/version"
15
18
 
@@ -38,6 +41,7 @@ require_relative "procon_bypass_man/support/cycle_sleep"
38
41
  require_relative "procon_bypass_man/support/can_over_process"
39
42
  require_relative "procon_bypass_man/support/gc"
40
43
  require_relative "procon_bypass_man/support/retryable"
44
+ require_relative "procon_bypass_man/support/renice_command"
41
45
  require_relative "procon_bypass_man/procon_display"
42
46
  require_relative "procon_bypass_man/background"
43
47
  require_relative "procon_bypass_man/commands"
@@ -149,7 +153,7 @@ module ProconBypassMan
149
153
 
150
154
  # @return [void]
151
155
  def self.initialize_pbm
152
- `renice -n 20 -p #{$$}`
156
+ ProconBypassMan::ReniceCommand.change_priority(to: :low, pid: $$)
153
157
  ProconBypassMan::Background::JobQueue.start!
154
158
  ProconBypassMan::Websocket::Client.start!
155
159
  # TODO ProconBypassMan::DrbObjects.start_all! みたいな感じで書きたい
@@ -173,18 +177,27 @@ module ProconBypassMan
173
177
 
174
178
  # @return [void]
175
179
  def self.after_fork_on_bypass_process
176
- `renice -n -20 -p #{$$}`
180
+ ProconBypassMan::ReniceCommand.change_priority(to: :high, pid: $$)
177
181
  ::GC.start
178
182
  DRb.start_service if defined?(DRb)
179
- ProconBypassMan::RemoteMacroReceiver.start!
180
- ProconBypassMan::ProconDisplay::Server.start!
183
+ # GC対策することによって一時的に削除した機能
184
+ # ProconBypassMan::ProconDisplay::Server.start!
185
+
186
+ DRb.start_service if defined?(DRb)
187
+ BlueGreenProcess.configure do |config|
188
+ config.after_fork = -> {
189
+ DRb.start_service if defined?(DRb)
190
+ ProconBypassMan::RemoteMacroReceiver.start!
191
+ BlueGreenProcess.config.logger = ProconBypassMan.logger
192
+ }
193
+ config.shared_variables = [:buttons, :current_layer_key]
194
+ end
181
195
  end
182
196
 
183
197
  # @return [void]
184
198
  def self.terminate_pbm
185
199
  FileUtils.rm_rf(ProconBypassMan.pid_path)
186
200
  FileUtils.rm_rf(ProconBypassMan.digest_path)
187
- ProconBypassMan::Background::JobQueue.shutdown
188
201
  ProconBypassMan::RemoteMacro::QueueOverProcess.shutdown
189
202
  ProconBypassMan::Procon::PerformanceMeasurement::QueueOverProcess.shutdown
190
203
  self.worker&.shutdown
@@ -28,9 +28,11 @@ Gem::Specification.new do |spec|
28
28
  spec.require_paths = ["lib"]
29
29
 
30
30
  # Uncomment to register a new dependency of your gem
31
- spec.add_dependency "pbmenv", ">= 0.1.9" # Pbmenv.installでのenable_pbm_cloudに依存している
31
+ spec.add_dependency "pbmenv", ">= 0.1.9" # enable_pbm_cloud連携機能でPbmenv.installを使っている.
32
32
  spec.add_dependency "action_cable_client"
33
33
  spec.add_dependency "sorted_set"
34
+ spec.add_dependency "blue_green_process"
35
+ # spec.add_dependency "blue_green_process"
34
36
 
35
37
  # For more information and examples about making a new gem, checkout our
36
38
  # guide at: https://bundler.io/guides/creating_gem.html
@@ -12,7 +12,7 @@ begin
12
12
  gemfile do
13
13
  source 'https://rubygems.org'
14
14
  git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
15
- gem 'procon_bypass_man', '0.2.3'
15
+ gem 'procon_bypass_man', '0.3.0'
16
16
  end
17
17
  rescue Bundler::Source::Git::GitCommandError => e
18
18
  retry_count_on_git_command_error = retry_count_on_git_command_error + 1
@@ -49,9 +49,6 @@ ProconBypassMan.configure do |config|
49
49
 
50
50
  # 接続に成功したらコントローラーのHOME LEDを光らせるか
51
51
  config.enable_home_led_on_connect = true
52
-
53
- # 操作が高頻度で固まるときは、 gadget_to_procon_interval の数値を大きくしてください
54
- config.bypass_mode = { mode: :normal, gadget_to_procon_interval: 10 }
55
52
  end
56
53
 
57
54
  ProconBypassMan.run(setting_path: "/usr/share/pbm/current/setting.yml")
@@ -12,7 +12,7 @@ begin
12
12
  gemfile do
13
13
  source 'https://rubygems.org'
14
14
  git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
15
- gem 'procon_bypass_man', '0.2.3'
15
+ gem 'procon_bypass_man', '0.3.0'
16
16
  end
17
17
  rescue Bundler::Source::Git::GitCommandError => e
18
18
  retry_count_on_git_command_error = retry_count_on_git_command_error + 1
@@ -54,9 +54,6 @@ ProconBypassMan.configure do |config|
54
54
 
55
55
  # 接続に成功したらコントローラーのHOME LEDを光らせるか
56
56
  config.enable_home_led_on_connect = true
57
-
58
- # 操作が高頻度で固まるときは、 gadget_to_procon_interval の数値を大きくしてください
59
- config.bypass_mode = { mode: :normal, gadget_to_procon_interval: 10 }
60
57
  end
61
58
 
62
59
  ProconBypassMan.run(setting_path: "/usr/share/pbm/current/setting.yml")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: procon_bypass_man
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - jiikko
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-08-26 00:00:00.000000000 Z
11
+ date: 2022-09-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pbmenv
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: blue_green_process
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  description: A programmable converter for Nintendo Switch Pro Controller
56
70
  email:
57
71
  - n905i.1214@gmail.com
@@ -232,6 +246,7 @@ files:
232
246
  - lib/procon_bypass_man/support/on_memory_cache.rb
233
247
  - lib/procon_bypass_man/support/procon_performance_http_client.rb
234
248
  - lib/procon_bypass_man/support/remote_macro_http_client.rb
249
+ - lib/procon_bypass_man/support/renice_command.rb
235
250
  - lib/procon_bypass_man/support/report_http_client.rb
236
251
  - lib/procon_bypass_man/support/retryable.rb
237
252
  - lib/procon_bypass_man/support/safe_timeout.rb