procon_bypass_man 0.1.7 → 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +3 -2
  3. data/.github/workflows/ruby.yml +34 -0
  4. data/.gitignore +4 -0
  5. data/.rubocop.yml +2 -0
  6. data/.ruby-version +1 -1
  7. data/CHANGELOG.md +17 -0
  8. data/Gemfile +4 -0
  9. data/Gemfile.lock +54 -2
  10. data/README.md +13 -8
  11. data/Rakefile +10 -1
  12. data/Steepfile +39 -0
  13. data/bin/console +4 -0
  14. data/bin/dev_api_server.rb +18 -0
  15. data/docs/setup_raspi.mitamae.rb +17 -2
  16. data/docs/setup_raspi_by_mitamae.md +2 -1
  17. data/lib/procon_bypass_man/background/report_thread.rb +42 -0
  18. data/lib/procon_bypass_man/boot_message.rb +40 -0
  19. data/lib/procon_bypass_man/buttons_setting_configuration.rb +102 -0
  20. data/lib/procon_bypass_man/bypass/usb_hid_logger.rb +27 -0
  21. data/lib/procon_bypass_man/bypass.rb +60 -29
  22. data/lib/procon_bypass_man/callbacks.rb +70 -0
  23. data/lib/procon_bypass_man/configuration/layer.rb +50 -4
  24. data/lib/procon_bypass_man/configuration/loader.rb +8 -8
  25. data/lib/procon_bypass_man/configuration/validator.rb +1 -1
  26. data/lib/procon_bypass_man/configuration.rb +67 -64
  27. data/lib/procon_bypass_man/device_connector.rb +13 -30
  28. data/lib/procon_bypass_man/io_monitor.rb +7 -4
  29. data/lib/procon_bypass_man/on_memory_cache.rb +34 -0
  30. data/lib/procon_bypass_man/outbound/base.rb +53 -0
  31. data/lib/procon_bypass_man/outbound/error_reporter.rb +13 -0
  32. data/lib/procon_bypass_man/outbound/pressed_buttons_reporter.rb +13 -0
  33. data/lib/procon_bypass_man/outbound/reporter.rb +12 -0
  34. data/lib/procon_bypass_man/procon/analog_stick.rb +31 -0
  35. data/lib/procon_bypass_man/procon/analog_stick_cap.rb +65 -0
  36. data/lib/procon_bypass_man/procon/button_collection.rb +15 -6
  37. data/lib/procon_bypass_man/procon/layer_changeable.rb +2 -2
  38. data/lib/procon_bypass_man/procon/macro_registry.rb +2 -2
  39. data/lib/procon_bypass_man/procon/mode_registry.rb +4 -4
  40. data/lib/procon_bypass_man/procon/press_button_aware.rb +13 -0
  41. data/lib/procon_bypass_man/procon/pressed_button_helper.rb +1 -11
  42. data/lib/procon_bypass_man/procon/user_operation.rb +15 -4
  43. data/lib/procon_bypass_man/procon.rb +25 -5
  44. data/lib/procon_bypass_man/readonly_procon.rb +32 -0
  45. data/lib/procon_bypass_man/runner.rb +39 -48
  46. data/lib/procon_bypass_man/uptime.rb +15 -0
  47. data/lib/procon_bypass_man/version.rb +1 -1
  48. data/lib/procon_bypass_man.rb +26 -33
  49. data/project_template/README.md +3 -2
  50. data/project_template/app.rb +8 -6
  51. data/project_template/systemd_units/pbm.service +1 -1
  52. data/project_template/systemd_units/pbm_web.service +11 -0
  53. data/project_template/web.rb +16 -0
  54. data/sig/README.rb +4 -0
  55. data/sig/main.rbs +507 -0
  56. metadata +25 -5
  57. data/examples/practical/app.rb +0 -21
  58. data/examples/practical/setting.yml +0 -24
@@ -1,5 +1,16 @@
1
+ require "procon_bypass_man/bypass/usb_hid_logger"
2
+
1
3
  class ProconBypassMan::Bypass
2
- attr_accessor :gadget, :procon, :monitor
4
+ include ProconBypassMan::Bypass::UsbHidLogger
5
+
6
+ class BypassStatus < Struct.new(:binary, :sent)
7
+ def to_text
8
+ "#{binary.unpack("H*").first} #{'x' unless sent}"
9
+ end
10
+ end
11
+
12
+ attr_accessor :gadget, :procon, :monitor, :bypass_status
13
+
3
14
  def initialize(gadget: , procon: , monitor: )
4
15
  self.gadget = gadget
5
16
  self.procon = procon
@@ -10,43 +21,63 @@ class ProconBypassMan::Bypass
10
21
  def send_gadget_to_procon!
11
22
  monitor.record(:start_function)
12
23
  input = nil
13
- begin
14
- sleep($will_interval_1_6)
15
- input = self.gadget.read_nonblock(128)
16
- ProconBypassMan.logger.debug { ">>> #{input.unpack("H*")}" }
17
- rescue IO::EAGAINWaitReadable
18
- monitor.record(:eagain_wait_readable_on_read)
19
- return if $will_terminate_token
20
- retry
21
- end
24
+ self.bypass_status = BypassStatus.new(input, sent = false)
25
+
26
+ run_callbacks :send_gadget_to_procon do
27
+ begin
28
+ return if $will_terminate_token
29
+ # TODO blocking readにしたいが、接続時のフェーズによって長さが違宇野で厳しい
30
+ input = self.gadget.read_nonblock(64)
31
+ self.bypass_status.binary = input
32
+ rescue IO::EAGAINWaitReadable
33
+ monitor.record(:eagain_wait_readable_on_read)
34
+ sleep(0.001)
35
+ retry
36
+ end
22
37
 
23
- begin
24
- self.procon.write_nonblock(input)
25
- rescue IO::EAGAINWaitReadable
26
- monitor.record(:eagain_wait_readable_on_write)
27
- return
38
+ begin
39
+ self.procon.write_nonblock(input)
40
+ self.bypass_status.sent = true
41
+ rescue IO::EAGAINWaitReadable
42
+ monitor.record(:eagain_wait_readable_on_write)
43
+ return
44
+ end
28
45
  end
46
+
29
47
  monitor.record(:end_function)
30
48
  end
31
49
 
32
50
  def send_procon_to_gadget!
33
51
  monitor.record(:start_function)
34
52
  output = nil
35
- begin
36
- sleep($will_interval_0_0_0_5)
37
- output = self.procon.read_nonblock(128)
38
- ProconBypassMan.logger.debug { "<<< #{output.unpack("H*")}" }
39
- rescue IO::EAGAINWaitReadable
40
- monitor.record(:eagain_wait_readable_on_read)
41
- return if $will_terminate_token
42
- retry
43
- end
53
+ self.bypass_status = BypassStatus.new(output, sent = false)
54
+
55
+ run_callbacks(:send_procon_to_gadget) do
56
+ begin
57
+ return if $will_terminate_token
58
+ Timeout.timeout(1) do
59
+ output = self.procon.read(64)
60
+ self.bypass_status.binary = output
61
+ end
62
+ rescue Timeout::Error
63
+ ProconBypassMan.logger.debug { "read timeout! do sleep. by send_procon_to_gadget!" }
64
+ ProconBypassMan.error_logger.error { "read timeout! do sleep. by send_procon_to_gadget!" }
65
+ monitor.record(:eagain_wait_readable_on_read)
66
+ retry
67
+ rescue IO::EAGAINWaitReadable
68
+ ProconBypassMan.logger.debug { "EAGAINWaitReadable" }
69
+ monitor.record(:eagain_wait_readable_on_read)
70
+ sleep(0.005)
71
+ retry
72
+ end
44
73
 
45
- begin
46
- self.gadget.write_nonblock(ProconBypassMan::Processor.new(output).process)
47
- rescue IO::EAGAINWaitReadable
48
- monitor.record(:eagain_wait_readable_on_write)
49
- return
74
+ begin
75
+ self.gadget.write_nonblock(ProconBypassMan::Processor.new(output).process)
76
+ self.bypass_status.sent = true
77
+ rescue IO::EAGAINWaitReadable
78
+ monitor.record(:eagain_wait_readable_on_write)
79
+ return
80
+ end
50
81
  end
51
82
  monitor.record(:end_function)
52
83
  end
@@ -0,0 +1,70 @@
1
+ module ProconBypassMan
2
+ module Callbacks
3
+ class CallbacksChain
4
+ attr_accessor :filter, :chain_method
5
+ def initialize(filter: , chain_method: , block: )
6
+ @filter = filter
7
+ @chain_method = chain_method
8
+ @block = block
9
+ end
10
+ end
11
+
12
+ # TODO __callbacksをincludeしたクラス側で保持する. 今はnemespaceがない
13
+ module M
14
+ class << self
15
+ attr_accessor :__callbacks
16
+ end
17
+ end
18
+
19
+ module ClassMethods
20
+ def define_callbacks(name)
21
+ self.singleton_class.attr_accessor "_#{name}_callbacks"
22
+ send "_#{name}_callbacks=", [name] # CallbacksChain
23
+
24
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
25
+ def _run_#{name}_callbacks(&block)
26
+ __run_callbacks__(_#{name}_callbacks, &block)
27
+ end
28
+ RUBY
29
+ end
30
+
31
+ def set_callback(kind, filter, chain_method, &block)
32
+ ProconBypassMan::Callbacks::M.__callbacks ||= {}
33
+ ProconBypassMan::Callbacks::M.__callbacks[kind] = CallbacksChain.new(
34
+ filter: filter,
35
+ chain_method: chain_method,
36
+ block: block,
37
+ )
38
+ end
39
+ end
40
+
41
+ # TODO haltしたらcallbackを止める
42
+ # TODO 複数をチェインできるようにする
43
+ def run_callbacks(kind, &block)
44
+ chain = get_callbacks(kind) or raise("unknown callback")
45
+ case chain.filter
46
+ when :before
47
+ send chain.chain_method
48
+ block.call
49
+ when :after
50
+ block.call
51
+ send chain.chain_method
52
+ else
53
+ raise("unknown filter")
54
+ end
55
+ end
56
+
57
+ # def __run_callbacks__(name, &block)
58
+ # puts "called"
59
+ # end
60
+
61
+ def get_callbacks(kind) # :nodoc:
62
+ ProconBypassMan::Callbacks::M.__callbacks[kind.to_sym]
63
+ end
64
+
65
+ def set_callbacks(name, callbacks) # :nodoc:
66
+ send "_#{name}_callbacks=", callbacks
67
+ ProconBypassMan::Callbacks::M.__callbacks[kind.to_sym] = callbacks
68
+ end
69
+ end
70
+ end
@@ -1,13 +1,15 @@
1
1
  module ProconBypassMan
2
- class Configuration
2
+ class ButtonsSettingConfiguration
3
3
  class Layer
4
- attr_accessor :mode, :flips, :macros, :remaps
4
+ attr_accessor :mode, :flips, :macros, :remaps, :left_analog_stick_caps, :disables
5
5
 
6
- def initialize(mode: :manual, &block)
6
+ def initialize(mode: :manual)
7
7
  self.mode = mode
8
8
  self.flips = {}
9
9
  self.macros = {}
10
10
  self.remaps = {}
11
+ self.left_analog_stick_caps = {}
12
+ self.disables = []
11
13
  instance_eval(&block) if block_given?
12
14
  end
13
15
 
@@ -50,7 +52,6 @@ module ProconBypassMan
50
52
  end
51
53
  end
52
54
 
53
- PRESET_MACROS = [:fast_return]
54
55
  def macro(name, if_pressed: )
55
56
  if name.respond_to?(:name)
56
57
  macro_name = name.name.to_sym
@@ -72,6 +73,51 @@ module ProconBypassMan
72
73
  end
73
74
  end
74
75
 
76
+ def left_analog_stick_cap(cap: , if_pressed: nil, force_neutral: nil)
77
+ hash = { cap: cap }
78
+
79
+ case if_pressed
80
+ when TrueClass
81
+ raise "not support class"
82
+ when Symbol, String
83
+ if_pressed = [if_pressed]
84
+ when Array, FalseClass
85
+ # sono mama
86
+ when NilClass
87
+ if_pressed = nil
88
+ else
89
+ raise "not support if_pressed"
90
+ end
91
+
92
+ if force_neutral
93
+ case force_neutral
94
+ when TrueClass, FalseClass
95
+ raise "ボタンを渡してください"
96
+ when Symbol, String
97
+ hash[:force_neutral] = [force_neutral]
98
+ when Array
99
+ hash[:force_neutral] = force_neutral
100
+ end
101
+ end
102
+
103
+ left_analog_stick_caps[if_pressed] = hash
104
+ end
105
+
106
+ def disable(button)
107
+ case button
108
+ when TrueClass, FalseClass, NilClass
109
+ raise "not support class"
110
+ when Symbol
111
+ disables << button
112
+ when String
113
+ disables << button.to_sym
114
+ when Array
115
+ button.each { |b| disables << b }
116
+ else
117
+ raise "unknown"
118
+ end
119
+ end
120
+
75
121
  # @return [Array]
76
122
  def flip_buttons
77
123
  flips
@@ -1,10 +1,10 @@
1
1
  module ProconBypassMan
2
- class Configuration
2
+ class ButtonsSettingConfiguration
3
3
  module Loader
4
4
  require 'digest/md5'
5
5
 
6
6
  def self.load(setting_path: )
7
- ProconBypassMan::Configuration.switch_new_context(:validation) do |validation_instance|
7
+ ProconBypassMan::ButtonsSettingConfiguration.switch_new_context(:validation) do |validation_instance|
8
8
  yaml = YAML.load_file(setting_path) or raise "読み込みに失敗しました"
9
9
  validation_instance.instance_eval(yaml["setting"])
10
10
  validator = Validator.new(validation_instance)
@@ -20,25 +20,25 @@ module ProconBypassMan
20
20
  end
21
21
 
22
22
  yaml = YAML.load_file(setting_path)
23
- ProconBypassMan::Configuration.instance.setting_path = setting_path
24
- ProconBypassMan::Configuration.instance.reset!
23
+ ProconBypassMan::ButtonsSettingConfiguration.instance.setting_path = setting_path
24
+ ProconBypassMan::ButtonsSettingConfiguration.instance.reset!
25
25
  ProconBypassMan.reset!
26
26
 
27
27
  case yaml["version"]
28
28
  when 1.0, nil
29
- ProconBypassMan::Configuration.instance.instance_eval(yaml["setting"])
29
+ ProconBypassMan::ButtonsSettingConfiguration.instance.instance_eval(yaml["setting"])
30
30
  else
31
31
  ProconBypassMan.logger.warn "不明なバージョンです。failoverします"
32
- ProconBypassMan::Configuration.instance.instance_eval(yaml["setting"])
32
+ ProconBypassMan::ButtonsSettingConfiguration.instance.instance_eval(yaml["setting"])
33
33
  end
34
34
 
35
35
  File.write(ProconBypassMan.digest_path, Digest::MD5.hexdigest(yaml["setting"]))
36
36
 
37
- ProconBypassMan::Configuration.instance
37
+ ProconBypassMan::ButtonsSettingConfiguration.instance
38
38
  end
39
39
 
40
40
  def self.reload_setting
41
- self.load(setting_path: ProconBypassMan::Configuration.instance.setting_path)
41
+ self.load(setting_path: ProconBypassMan::ButtonsSettingConfiguration.instance.setting_path)
42
42
  end
43
43
  end
44
44
  end
@@ -1,5 +1,5 @@
1
1
  module ProconBypassMan
2
- class Configuration
2
+ class ButtonsSettingConfiguration
3
3
  class Validator
4
4
  def initialize(config)
5
5
  @layers = config.layers
@@ -1,86 +1,89 @@
1
- require "procon_bypass_man/configuration/validator"
2
- require "procon_bypass_man/configuration/loader"
3
- require "procon_bypass_man/configuration/layer"
1
+ class ProconBypassMan::Configuration
2
+ module ClassAttributes
3
+ def root
4
+ config.root
5
+ end
4
6
 
5
- module ProconBypassMan
6
- class Configuration
7
+ def logger
8
+ config.logger
9
+ end
7
10
 
8
- attr_accessor :layers,
9
- :setting_path,
10
- :mode_plugins,
11
- :macro_plugins,
12
- :context,
13
- :current_context_key
11
+ def error_logger
12
+ config.error_logger
13
+ end
14
14
 
15
- def self.instance
16
- @@current_context_key ||= :main
17
- @@context ||= {}
18
- @@context[@@current_context_key] ||= new
15
+ def pid_path
16
+ @@pid_path ||= File.expand_path("#{root}/pbm_pid", __dir__).freeze
19
17
  end
20
18
 
21
- def self.switch_new_context(key)
22
- @@context[key] = new
23
- previous_key = @@current_context_key
24
- if block_given?
25
- @@current_context_key = key
26
- value = yield(@@context[key])
27
- @@current_context_key = previous_key
28
- return value
29
- else
30
- @@current_context_key = key
31
- end
19
+ def digest_path
20
+ config.digest_path
32
21
  end
33
22
 
34
- def initialize
35
- reset!
23
+ def cache
24
+ @@cache_table ||= ProconBypassMan::OnMemoryCache.new
36
25
  end
26
+ end
37
27
 
38
- MODES = [:manual]
39
- def layer(direction, mode: :manual, &block)
40
- if mode.respond_to?(:name)
41
- mode_name = mode.name.to_sym
42
- else
43
- mode_name = mode
44
- end
45
- unless (MODES + ProconBypassMan::Procon::ModeRegistry.plugins.keys).include?(mode_name)
46
- raise("#{mode_name} mode is unknown")
47
- end
28
+ attr_reader :api_server
29
+ attr_accessor :enable_critical_error_logging
48
30
 
49
- layer = Layer.new(mode: mode_name)
50
- layer.instance_eval(&block) if block_given?
51
- self.layers[direction] = layer
52
- self
53
- end
31
+ def root=(path)
32
+ @root = path
33
+ return self
34
+ end
54
35
 
55
- def install_mode_plugin(klass)
56
- ProconBypassMan::Procon::ModeRegistry.install_plugin(klass)
57
- self
36
+ def root
37
+ if defined?(@root)
38
+ @root
39
+ else
40
+ File.expand_path('..', __dir__ || ".").freeze
58
41
  end
42
+ end
59
43
 
60
- def install_macro_plugin(klass)
61
- ProconBypassMan::Procon::MacroRegistry.install_plugin(klass)
62
- self
44
+ def api_server=(api_server)
45
+ @api_server = api_server
46
+ return self
47
+ end
48
+
49
+ def logger=(logger)
50
+ @logger = logger
51
+ return self
52
+ end
53
+
54
+ def logger
55
+ if ENV["PBM_ENV"] == 'test'
56
+ return Logger.new($stdout)
63
57
  end
64
58
 
65
- def prefix_keys_for_changing_layer(buttons)
66
- @prefix_keys_for_changing_layer = buttons
67
- self
59
+ if defined?(@logger) && @logger.is_a?(Logger)
60
+ @logger
61
+ else
62
+ Logger.new(File.open("/dev/null"))
68
63
  end
64
+ end
69
65
 
70
- def prefix_keys
71
- @prefix_keys_for_changing_layer
66
+ def error_logger
67
+ if enable_critical_error_logging
68
+ @@error_logger ||= Logger.new("#{ProconBypassMan.root}/error.log", 5, 1024 * 1024 * 10)
69
+ else
70
+ Logger.new(File.open("/dev/null"))
72
71
  end
72
+ self
73
+ end
74
+
75
+ def digest_path
76
+ "#{root}/.setting_yaml_digest"
77
+ end
73
78
 
74
- def reset!
75
- @prefix_keys_for_changing_layer = []
76
- self.mode_plugins = {}
77
- self.macro_plugins = {}
78
- self.layers = {
79
- up: Layer.new,
80
- down: Layer.new,
81
- left: Layer.new,
82
- right: Layer.new,
83
- }
79
+ # @return [String] pbm-webの接続先
80
+ def internal_api_servers
81
+ if !!ENV["INTERNAL_API_SERVER"]
82
+ [ENV["INTERNAL_API_SERVER"]]
83
+ else
84
+ [ 'http://localhost:9090',
85
+ 'http://localhost:8080',
86
+ ].compact
84
87
  end
85
88
  end
86
89
  end
@@ -12,23 +12,6 @@ class ProconBypassMan::DeviceConnector
12
12
  PROCON_PATH = "/dev/hidraw0"
13
13
  PROCON2_PATH = "/dev/hidraw1"
14
14
 
15
- # 画面で再接続ができたが状況は変わらない
16
- def self.reset_connection!
17
- s = new
18
- s.add([
19
- ["0000"],
20
- ["0000"],
21
- ["8005"],
22
- ["0000"],
23
- ["8001"],
24
- ], read_from: :switch)
25
- s.drain_all
26
- s.read_procon
27
- s.write_switch("213c910080005db7723d48720a800300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
28
- sleep(10) # いらないかも
29
- s
30
- end
31
-
32
15
  def self.connect
33
16
  s = new(throw_error_if_timeout: true, enable_at_exit: false)
34
17
  s.add([
@@ -37,16 +20,16 @@ class ProconBypassMan::DeviceConnector
37
20
  ["8005"],
38
21
  ["0010"],
39
22
  ], read_from: :switch)
40
- # 1
23
+ # 1. Sends current connection status, and if the Joy-Con are connected,
41
24
  s.add([["8001"]], read_from: :switch)
42
25
  s.add([/^8101/], read_from: :procon) # <<< 81010003176d96e7a5480000000, macaddressとコントローラー番号を返す
43
- # 2
26
+ # 2. Sends handshaking packets over UART to the Joy-Con or Pro Controller Broadcom chip. This command can only be called once per session.
44
27
  s.add([["8002"]], read_from: :switch)
45
28
  s.add([/^8102/], read_from: :procon)
46
29
  # 3
47
30
  s.add([/^0100/], read_from: :switch)
48
31
  s.add([/^21/], read_from: :procon)
49
- # 4
32
+ # 4. Forces the Joy-Con or Pro Controller to only talk over USB HID without any timeouts. This is required for the Pro Controller to not time out and revert to Bluetooth.
50
33
  s.add([["8004"]], read_from: :switch)
51
34
  s.drain_all
52
35
  return [s.switch, s.procon]
@@ -75,7 +58,7 @@ class ProconBypassMan::DeviceConnector
75
58
  timer = ProconBypassMan::Timer.new
76
59
  begin
77
60
  timer.throw_if_timeout!
78
- data = from_device(item).read_nonblock(128)
61
+ data = from_device(item).read_nonblock(64)
79
62
  rescue IO::EAGAINWaitReadable
80
63
  retry
81
64
  end
@@ -128,7 +111,7 @@ class ProconBypassMan::DeviceConnector
128
111
  timer = ProconBypassMan::Timer.new
129
112
  begin
130
113
  timer.throw_if_timeout!
131
- data = switch.read_nonblock(128)
114
+ data = switch.read_nonblock(64)
132
115
  ProconBypassMan.logger.debug { " >>> #{data.unpack("H*")})" }
133
116
  rescue IO::EAGAINWaitReadable
134
117
  retry
@@ -163,7 +146,7 @@ class ProconBypassMan::DeviceConnector
163
146
  timer = ProconBypassMan::Timer.new
164
147
  begin
165
148
  timer.throw_if_timeout!
166
- data = procon.read_nonblock(128)
149
+ data = procon.read_nonblock(64)
167
150
  ProconBypassMan.logger.error " <<< #{data.unpack("H*")})"
168
151
  rescue IO::EAGAINWaitReadable
169
152
  retry
@@ -184,7 +167,7 @@ class ProconBypassMan::DeviceConnector
184
167
  timer = ProconBypassMan::Timer.new
185
168
  begin
186
169
  timer.throw_if_timeout!
187
- data = procon.read_nonblock(128)
170
+ data = procon.read_nonblock(64)
188
171
  ProconBypassMan.logger.debug { " <<< #{data.unpack("H*")})" }
189
172
  rescue IO::EAGAINWaitReadable
190
173
  retry
@@ -217,7 +200,7 @@ class ProconBypassMan::DeviceConnector
217
200
  timer = ProconBypassMan::Timer.new
218
201
  begin
219
202
  timer.throw_if_timeout!
220
- data = switch.read_nonblock(128)
203
+ data = switch.read_nonblock(64)
221
204
  ProconBypassMan.logger.debug { " >>> #{data.unpack("H*")})" }
222
205
  rescue IO::EAGAINWaitReadable
223
206
  retry
@@ -281,7 +264,7 @@ class ProconBypassMan::DeviceConnector
281
264
 
282
265
  file = File.open(path, "w+")
283
266
  begin
284
- file.read_nonblock(128)
267
+ file.read_nonblock(64)
285
268
  rescue EOFError
286
269
  file.close
287
270
  return false
@@ -303,12 +286,12 @@ class ProconBypassMan::DeviceConnector
303
286
  case
304
287
  when is_available_device?(PROCON_PATH)
305
288
  ProconBypassMan.logger.info "proconのデバイスファイルは#{PROCON_PATH}を使います"
306
- @procon = File.open(PROCON_PATH, "w+")
307
- @gadget = File.open('/dev/hidg0', "w+")
289
+ @procon = File.open(PROCON_PATH, "w+b")
290
+ @gadget = File.open('/dev/hidg0', "w+b")
308
291
  when is_available_device?(PROCON2_PATH)
309
292
  ProconBypassMan.logger.info "proconのデバイスファイルは#{PROCON2_PATH}を使います"
310
- @procon = File.open(PROCON2_PATH, "w+")
311
- @gadget = File.open('/dev/hidg0', "w+")
293
+ @procon = File.open(PROCON2_PATH, "w+b")
294
+ @gadget = File.open('/dev/hidg0', "w+b")
312
295
  else
313
296
  raise "/dev/hidraw0, /dev/hidraw1の両方見つかりませんでした"
314
297
  end
@@ -62,10 +62,13 @@ module ProconBypassMan
62
62
  }.join(", ")
63
63
  max_output_length = line.length
64
64
  sleep 0.7
65
- print "\r"
66
- print " " * max_output_length
67
- print "\r"
68
- print line
65
+
66
+ if ENV["PBM_FOREGROUND"]
67
+ print "\r"
68
+ print " " * max_output_length
69
+ print "\r"
70
+ print line
71
+ end
69
72
  ProconBypassMan.logger.debug { line }
70
73
  break if $will_terminate_token
71
74
  end
@@ -0,0 +1,34 @@
1
+ class ProconBypassMan::OnMemoryCache
2
+ class CacheValue
3
+ attr_accessor :expired_at, :value
4
+
5
+ def initialize(expired_at: , value: )
6
+ self.expired_at = expired_at
7
+ self.value = value
8
+ end
9
+ end
10
+
11
+ def initialize
12
+ @table = {}
13
+ end
14
+
15
+ # @param [Integer] expires_in 秒数
16
+ # @param [String] key
17
+ def fetch(key: , expires_in: , &block)
18
+ now = Time.now
19
+ if @table[key].nil?
20
+ value = block.call
21
+ value_object = CacheValue.new(expired_at: now + expires_in, value: value)
22
+ @table[key] = value_object
23
+ return value
24
+ end
25
+
26
+ if @table[key].expired_at < now
27
+ value = block.call
28
+ @table[key] = CacheValue.new(expired_at: now + expires_in, value: value)
29
+ return value
30
+ else
31
+ return @table[key].value
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,53 @@
1
+ module ProconBypassMan
2
+ module Outbound
3
+ class Base
4
+ class Client
5
+ class Result < Struct.new(:stats); end
6
+
7
+ def initialize(path: , server: )
8
+ @path = path
9
+ if server.is_a?(Array)
10
+ # TODO エラーが起きたらローテーションする
11
+ @server = server.first
12
+ else
13
+ @server = server
14
+ end
15
+ @hostname = `hostname`.chomp
16
+ end
17
+
18
+ def post(body: )
19
+ # TODO ここでvalidationする
20
+ if @server.nil?
21
+ ProconBypassMan.logger.info('送信先が未設定なのでスキップしました')
22
+ return Result.new(false)
23
+ end
24
+
25
+ unless body.is_a?(Hash)
26
+ body = { value: body }
27
+ end
28
+
29
+ uri = URI.parse("#{@server}#{@path}")
30
+ http = Net::HTTP.new(uri.host, uri.port)
31
+ http.use_ssl = uri.scheme === "https"
32
+ params = { hostname: @hostname }.merge(body)
33
+ response = http.post(
34
+ uri.path,
35
+ params.to_json,
36
+ { "Content-Type" => "application/json" },
37
+ )
38
+ case response.code
39
+ when /^200/
40
+ return Result.new(true)
41
+ else
42
+ ProconBypassMan.logger.error("200以外(#{response.code})が帰ってきました. #{response.body}")
43
+ return Result.new(false)
44
+ end
45
+ rescue => e
46
+ puts e
47
+ ProconBypassMan.logger.error("erro: #{e}")
48
+ Result.new(false)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end