procon_bypass_man 0.3.6 → 0.3.8

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +4 -0
  3. data/.github/workflows/gitleacks.yml +1 -1
  4. data/.github/workflows/release.yml +1 -1
  5. data/.github/workflows/ruby.yml +2 -2
  6. data/CHANGELOG.md +10 -0
  7. data/Gemfile +1 -0
  8. data/Gemfile.lock +4 -2
  9. data/README.md +2 -2
  10. data/bin/validate_external_input +19 -0
  11. data/docs/getting_started.md +28 -0
  12. data/docs/setting/integration_external_input_serial_port.md +56 -0
  13. data/docs/setting/integration_external_input_serial_port_format.md +36 -0
  14. data/lib/procon_bypass_man/background/jobs/report_procon_performance_measurements_job.rb +1 -0
  15. data/lib/procon_bypass_man/bypass/procon_to_switch.rb +16 -1
  16. data/lib/procon_bypass_man/commands/print_boot_message_command.rb +4 -1
  17. data/lib/procon_bypass_man/configuration.rb +31 -14
  18. data/lib/procon_bypass_man/external_input/boot_message.rb +21 -0
  19. data/lib/procon_bypass_man/external_input/channels/base.rb +22 -0
  20. data/lib/procon_bypass_man/external_input/channels/serial_port_channel.rb +56 -0
  21. data/lib/procon_bypass_man/external_input/channels/tcpip_channel.rb +131 -0
  22. data/lib/procon_bypass_man/external_input/channels.rb +12 -0
  23. data/lib/procon_bypass_man/external_input/external_data.rb +79 -0
  24. data/lib/procon_bypass_man/external_input.rb +31 -0
  25. data/lib/procon_bypass_man/processor.rb +3 -2
  26. data/lib/procon_bypass_man/procon/button_collection.rb +5 -0
  27. data/lib/procon_bypass_man/procon/performance_measurement/measurements_summarizer.rb +4 -0
  28. data/lib/procon_bypass_man/procon/performance_measurement.rb +7 -1
  29. data/lib/procon_bypass_man/procon.rb +17 -2
  30. data/lib/procon_bypass_man/procon_display/status.rb +0 -2
  31. data/lib/procon_bypass_man/support/forever.rb +51 -0
  32. data/lib/procon_bypass_man/support/proccess_cheacker.rb +14 -0
  33. data/lib/procon_bypass_man/support/retryable.rb +5 -2
  34. data/lib/procon_bypass_man/support/simple_tcp_server.rb +63 -0
  35. data/lib/procon_bypass_man/support/watchdog.rb +23 -0
  36. data/lib/procon_bypass_man/support/web_connectivity_checker.rb +41 -0
  37. data/lib/procon_bypass_man/version.rb +1 -1
  38. data/lib/procon_bypass_man/websocket/client.rb +11 -9
  39. data/lib/procon_bypass_man.rb +16 -3
  40. data/project_template/app.rb +11 -1
  41. data/project_template/app.rb.erb +11 -1
  42. data/sig/main.rbs +2 -2
  43. metadata +17 -4
  44. data/lib/procon_bypass_man/websocket/forever.rb +0 -47
  45. data/lib/procon_bypass_man/websocket/watchdog.rb +0 -19
@@ -0,0 +1,131 @@
1
+ module ProconBypassMan
2
+ module ExternalInput
3
+ module Channels
4
+ class TCPIPChannel < Base
5
+ class ShutdownSignal < StandardError; end
6
+
7
+ class AppServer < SimpleTCPServer
8
+ @command_queue = Queue.new
9
+
10
+ class << self
11
+ attr_accessor :command_queue
12
+ end
13
+
14
+ def post_init
15
+ ProconBypassMan.logger.info { "[ExternalInput][TCPIPChannel] A client has connected" }
16
+ end
17
+
18
+ def unbind
19
+ ProconBypassMan.logger.info { "[ExternalInput][TCPIPChannel] A client has disconnected" }
20
+ end
21
+
22
+ # @return [String]
23
+ def receive_data(client, data)
24
+ case data
25
+ when /^{/
26
+ self.class.command_queue.push(data)
27
+ client.write("OK\n")
28
+ return
29
+ when /^\n/
30
+ if self.class.command_queue.empty?
31
+ client.write("EMPTY\n")
32
+ return
33
+ end
34
+
35
+ data = self.class.command_queue.pop
36
+ client.write("#{data}\n")
37
+ return
38
+ else
39
+ client.write("Unknown command\n")
40
+ return
41
+ end
42
+ end
43
+ end
44
+
45
+ def initialize(port: )
46
+ @port = port
47
+ super()
48
+
49
+ begin
50
+ @server = AppServer.new('0.0.0.0', @port)
51
+ rescue Errno::EADDRINUSE # NOTE: Address already in use - bind(2) for "0.0.0.0" port XXXX
52
+ ProconBypassMan::SendErrorCommand.execute(error: "[ExternalInput][TCPIPChannel] 起動に失敗しました。#{e.message}")
53
+ @server_thread = Thread.start {}
54
+ return
55
+ end
56
+
57
+ # NOTE: masterプロセスで起動する
58
+ @server_thread = Thread.start do
59
+ begin
60
+ loop do
61
+ @server.start_server
62
+ @server.run
63
+ end
64
+ rescue Errno::EPIPE, EOFError, Errno::ECONNRESET => e
65
+ ProconBypassMan::SendErrorCommand.execute(error: "[ExternalInput][TCPIPChannel] #{e.message}(#{e})")
66
+ sleep(5)
67
+
68
+ @server.shutdown
69
+ retry
70
+ rescue ShutdownSignal => e
71
+ ProconBypassMan::SendErrorCommand.execute(error: "[ExternalInput][TCPIPChannel] ShutdownSignalを受け取りました。終了します。")
72
+ @server.shutdown
73
+ rescue => e
74
+ ProconBypassMan::SendErrorCommand.execute(error: "[ExternalInput][TCPIPChannel] #{e.message}(#{e})")
75
+ end
76
+ end
77
+ end
78
+
79
+ # NOTE: bypassプロセスから呼ばれ、masterプロセスへ繋ぐ
80
+ # @return [String, NilClass]
81
+ def read
82
+ @socket ||= TCPSocket.new('0.0.0.0', @port)
83
+ read_command = "\n"
84
+ @socket.write(read_command)
85
+ response = @socket.gets&.strip
86
+ # ProconBypassMan.logger.debug { "Received: #{response}" }
87
+
88
+ case response
89
+ when /^{/
90
+ return response
91
+ when /^EMPTY/, ''
92
+ return nil
93
+ else
94
+ ProconBypassMan.logger.warn { "[ExternalInput][TCPIPChannel] Unknown response(#{response}, codepoints: #{response.codepoints})" }
95
+ return nil
96
+ end
97
+ rescue Errno::EPIPE, EOFError => e
98
+ @socket = nil
99
+ sleep(10)
100
+ ProconBypassMan.logger.error { "[ExternalInput][TCPIPChannel] #{e.message}!!!!!!!(#{e})" }
101
+ retry
102
+ rescue => e
103
+ @socket = nil
104
+ ProconBypassMan.logger.error { "[ExternalInput][TCPIPChannel] #{e.message} が起きました(#{e})" }
105
+ return nil
106
+ end
107
+
108
+ def shutdown
109
+ ProconBypassMan.logger.info { "[ExternalInput][TCPIPChannel] shutdown" }
110
+ @server_thread.raise(ShutdownSignal)
111
+ end
112
+
113
+ def alive_server?
114
+ return false if not @server_thread.alive?
115
+
116
+ begin
117
+ TCPSocket.new('0.0.0.0', @port).close
118
+ rescue Errno::ECONNREFUSED, Errno::ECONNRESET
119
+ return false
120
+ end
121
+
122
+ true
123
+ end
124
+
125
+ def display_name_for_boot_message
126
+ "TCPIP(port: #{@port})"
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProconBypassMan
4
+ module ExternalInput
5
+ module Channels
6
+ end
7
+ end
8
+ end
9
+
10
+ require "procon_bypass_man/external_input/channels/base"
11
+ require "procon_bypass_man/external_input/channels/serial_port_channel"
12
+ require "procon_bypass_man/external_input/channels/tcpip_channel"
@@ -0,0 +1,79 @@
1
+ module ProconBypassMan
2
+ module ExternalInput
3
+ class ExternalData
4
+ UNPRESS_BUTTONS = Set.new(ProconBypassMan::Procon::ButtonCollection.available.map { |x| "un#{x}".to_sym })
5
+
6
+ # @return [String, NilClass] 16進数表現のデータ
7
+ attr_reader :hex
8
+
9
+ # @return [String, NilClass] ログに表示する用
10
+ attr_reader :raw_data
11
+
12
+ # @raise [ParseError]
13
+ # @return [ExternalData] JSON か カンマ区切りのbuttons
14
+ def self.parse!(raw_data)
15
+ raise ParseError unless raw_data.ascii_only?
16
+
17
+ if is_json(raw_data)
18
+ begin
19
+ json = JSON.parse(raw_data)
20
+ return new(hex: json['hex'], buttons: json['buttons'])
21
+ rescue JSON::ParserError
22
+ raise ParseError
23
+ end
24
+ end
25
+
26
+ return new(hex: nil, buttons: raw_data.scan(/:\w+:/).map { |x| x.gsub(':', '') }, raw_data: raw_data)
27
+ end
28
+
29
+ # @param [String] raw_data
30
+ # @return [Boolean]
31
+ def self.is_json(raw_data)
32
+ raw_data.start_with?('{')
33
+ end
34
+
35
+ # @param [String, NilClass] hex
36
+ # @param [Array<String>, NilClass] buttons
37
+ # @param [String, NilClass] raw_data
38
+ def initialize(hex: , buttons: , raw_data: nil)
39
+ @hex = hex
40
+ @buttons = buttons || []
41
+ @raw_data = raw_data
42
+ end
43
+
44
+ # @return [String, NilClass]
45
+ def to_binary
46
+ return nil if @hex.nil?
47
+ [@hex].pack('H*')
48
+ end
49
+
50
+ # @return [Array<Symbol>]
51
+ def press_buttons
52
+ buttons.select do |button|
53
+ ProconBypassMan::Procon::ButtonCollection::BUTTONS_MAP[button]
54
+ end
55
+ end
56
+
57
+ # @return [Array<Symbol>]
58
+ def unpress_buttons
59
+ buttons.select { |button|
60
+ UNPRESS_BUTTONS.include?(button)
61
+ }.map { |b| to_button(b.to_s).to_sym }
62
+ end
63
+
64
+ # NOTE: ログに表示する用
65
+ # @return [Array<Symbol>]
66
+ def buttons
67
+ @buttons.map(&:to_sym)
68
+ end
69
+
70
+ private
71
+
72
+ # @return [String]
73
+ # NOTE: un#{button} って名前をbuttonに変換する
74
+ def to_button(button)
75
+ button.sub(/^un/, '')
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProconBypassMan
4
+ module ExternalInput
5
+ class ParseError < StandardError; end
6
+
7
+ # @return [Array<ProconBypassMan::ExternalInput::Channels::Base>]
8
+ def self.channels
9
+ @@channels ||= ProconBypassMan.config.external_input_channels
10
+ end
11
+
12
+ def self.shutdown
13
+ channels.each(&:shutdown)
14
+ end
15
+
16
+ # @return [NilClass, String]
17
+ # NOTE: 外部入力からのreadがボトルネックになるなら、Concurrent::Futureを使ってプロコンからの読み出しと並列化することを検討する
18
+ def self.read
19
+ value = nil
20
+ channels.each do |channel|
21
+ value = channel.read
22
+ break if value
23
+ end
24
+ value
25
+ end
26
+ end
27
+ end
28
+
29
+ require "procon_bypass_man/external_input/external_data"
30
+ require "procon_bypass_man/external_input/channels.rb"
31
+ require "procon_bypass_man/external_input/boot_message"
@@ -5,12 +5,13 @@ class ProconBypassMan::Processor
5
5
  @binary = binary
6
6
  end
7
7
 
8
+ # @param [ProconBypassMan::ExternalInput::ExternalData, NilClass] external_input_data
8
9
  # @return [String] 加工後の入力データ
9
- def process
10
+ def process(external_input_data: nil)
10
11
  return @binary.raw unless @binary.user_operation_data?
11
12
 
12
13
  procon = ProconBypassMan::Procon.new(@binary.raw)
13
14
  procon.apply!
14
- procon.to_binary
15
+ procon.to_binary(external_input_data: external_input_data)
15
16
  end
16
17
  end
@@ -37,4 +37,9 @@ class ProconBypassMan::Procon::ButtonCollection
37
37
  BUTTONS = ProconBypassMan::Procon::ButtonCollection::BUTTONS_MAP.keys.freeze
38
38
 
39
39
  LEFT_ANALOG_STICK = { byte_position: 6..8 }
40
+
41
+ # @return [Array<Symbol>]
42
+ def self.available
43
+ BUTTONS
44
+ end
40
45
  end
@@ -9,6 +9,7 @@ class ProconBypassMan::Procon::PerformanceMeasurement::MeasurementsSummarizer
9
9
  :time_taken_p95,
10
10
  :time_taken_p99,
11
11
  :time_taken_max,
12
+ :external_input_time_max,
12
13
  :read_error_count,
13
14
  :write_error_count,
14
15
  :gc_count,
@@ -26,6 +27,7 @@ class ProconBypassMan::Procon::PerformanceMeasurement::MeasurementsSummarizer
26
27
  write_time_max = 0
27
28
  read_time_max = 0
28
29
  time_taken_max = 0
30
+ external_input_time_max = 0
29
31
  interval_from_previous_succeed_max = 0
30
32
  @spans.each do |span|
31
33
  # NOTE @spans.map(&:write_time).sort.last と同じことだけど、処理コストを軽くするためにループを共通化する
@@ -33,6 +35,7 @@ class ProconBypassMan::Procon::PerformanceMeasurement::MeasurementsSummarizer
33
35
  read_time_max = span.read_time if write_time_max < span.read_time
34
36
  time_taken_max = span.time_taken if span.succeed && time_taken_max < span.time_taken
35
37
  interval_from_previous_succeed_max = span.interval_from_previous_succeed if span.succeed && interval_from_previous_succeed_max < span.interval_from_previous_succeed
38
+ external_input_time_max = span.external_input_time if span.succeed && external_input_time_max < span.external_input_time
36
39
  end
37
40
 
38
41
  # NOTE 今はGCを無効にしており、集計するまでもないのでコメントアウトにする. 今後GCを有効にしたバイパスをするかもしれないので残しておく
@@ -79,6 +82,7 @@ class ProconBypassMan::Procon::PerformanceMeasurement::MeasurementsSummarizer
79
82
  time_taken_p95,
80
83
  time_taken_p99,
81
84
  time_taken_max,
85
+ external_input_time_max,
82
86
  total_read_error_count,
83
87
  total_write_error_count,
84
88
  gc_count,
@@ -12,7 +12,7 @@ require 'procon_bypass_man/procon/performance_measurement/last_bypass_at'
12
12
  module ProconBypassMan::Procon::PerformanceMeasurement
13
13
  class PerformanceSpan
14
14
  attr_accessor :time_taken, :succeed, :interval_from_previous_succeed, :gc_count, :gc_time
15
- attr_reader :write_error_count, :read_error_count, :write_time, :read_time
15
+ attr_reader :write_error_count, :read_error_count, :write_time, :read_time, :external_input_time
16
16
 
17
17
  def initialize
18
18
  @write_error_count = 0
@@ -40,9 +40,15 @@ module ProconBypassMan::Procon::PerformanceMeasurement
40
40
  return result
41
41
  end
42
42
 
43
+ # @return [void]
43
44
  def record_read_time(&block)
44
45
  @read_time = Benchmark.realtime { block.call }
45
46
  end
47
+
48
+ # @return [void]
49
+ def record_external_input_time(&block)
50
+ @external_input_time = Benchmark.realtime { block.call }
51
+ end
46
52
  end
47
53
 
48
54
  # 全部送ると負荷になるので適当にまびく
@@ -128,7 +128,7 @@ class ProconBypassMan::Procon
128
128
  end
129
129
 
130
130
  # remote macro or pbm action
131
- if task = ProconBypassMan::RemoteAction::TaskQueueInProcess.non_blocking_shift
131
+ if(task = ProconBypassMan::RemoteAction::TaskQueueInProcess.non_blocking_shift)
132
132
  case task.type
133
133
  when ProconBypassMan::RemoteAction::Task::TYPE_MACRO
134
134
  no_op_step = :wait_for_0_3 # マクロの最後に固まって最後の入力をし続けるので、無の状態を最後に注入する
@@ -187,12 +187,27 @@ class ProconBypassMan::Procon
187
187
  status
188
188
  end
189
189
 
190
+ # @param [ProconBypassMan::ExternalInput::ExternalData, NilClass] external_input_data
190
191
  # @return [String]
191
- def to_binary
192
+ def to_binary(external_input_data: nil)
192
193
  if ongoing_mode.name != :manual
193
194
  return user_operation.binary.raw
194
195
  end
195
196
 
197
+ if external_input_data
198
+ if(external_input_data_raw_binary = external_input_data.to_binary)
199
+ self.user_operation.merge(external_input_data_raw_binary)
200
+ else
201
+ external_input_data.press_buttons.each do |button|
202
+ self.user_operation.press_button(button)
203
+ end
204
+ external_input_data.unpress_buttons.each do |button|
205
+ self.user_operation.unpress_button(button)
206
+ end
207
+ end
208
+ return self.user_operation.binary.raw
209
+ end
210
+
196
211
  if ongoing_macro.ongoing? && (step = ongoing_macro.next_step)
197
212
  BlueGreenProcess::SharedVariable.extend_run_on_this_process = true
198
213
  ongoing_macro.force_neutral_buttons&.each do |force_neutral_button|
@@ -1,5 +1,3 @@
1
- require 'singleton'
2
-
3
1
  class ProconBypassMan::ProconDisplay::Status
4
2
  include Singleton
5
3
 
@@ -0,0 +1,51 @@
1
+ module ProconBypassMan
2
+ class Forever
3
+ # 動作確認方法
4
+ # - 10秒ごとにrefreshするのでタイムアウトは起きない
5
+ # - ProconBypassMan::Forever.run { |watchdog| loop { puts(:hi); sleep(10); watchdog.active! } }
6
+ # - タイムアウトが起きること
7
+ # - ProconBypassMan::Forever.run { |watchdog| loop { puts(:hi); sleep(10); } }
8
+ def self.run(&block)
9
+ loop do
10
+ new.run(&block)
11
+ end
12
+ end
13
+
14
+ # @return [void]
15
+ def run(&block)
16
+ raise(ArgumentError, "need a block") unless block_given?
17
+
18
+ thread, watchdog = work_one(callable: block)
19
+ wait_and_kill_if_outdated(thread, watchdog)
20
+ end
21
+
22
+ # @param [Proc] callable
23
+ # @return [Array<Thread, ProconBypassMan::Watchdog>]
24
+ def work_one(callable: )
25
+ watchdog = ProconBypassMan::Watchdog.new
26
+ thread = Thread.start do
27
+ callable.call(watchdog)
28
+ rescue => e
29
+ ProconBypassMan.logger.error("[Forever] #{e.full_message}")
30
+ end
31
+
32
+ return [thread, watchdog]
33
+ end
34
+
35
+ # @param [ProconBypassMan::Watchdog] watchdog
36
+ # @param [Thread] thread
37
+ # @return [void]
38
+ def wait_and_kill_if_outdated(thread, watchdog)
39
+ loop do
40
+ if watchdog.outdated?
41
+ watchdog.active!
42
+ ProconBypassMan.logger.error("watchdog timeout!!")
43
+ thread.kill
44
+ return
45
+ end
46
+
47
+ sleep(10)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,14 @@
1
+ class ProconBypassMan::ProcessChecker
2
+ # @param [integer] pid
3
+ # @return [Boolean]
4
+ def self.running?(pid)
5
+ begin
6
+ Process.kill(0, pid)
7
+ true
8
+ rescue Errno::ESRCH
9
+ false
10
+ rescue Errno::EPERM
11
+ true
12
+ end
13
+ end
14
+ end
@@ -1,14 +1,17 @@
1
1
  module ProconBypassMan
2
2
  class Retryable
3
- def self.retryable(tries: , retried: 0, on_no_retry: [])
3
+ def self.retryable(tries: , retried: 0, on_no_retry: [], log_label: nil, interval_on_retry: 0)
4
4
  return yield(retried)
5
5
  rescue *on_no_retry
6
6
  raise
7
- rescue
7
+ rescue => e
8
8
  if tries <= retried
9
9
  raise
10
10
  else
11
11
  retried = retried + 1
12
+ ProconBypassMan.logger.debug "[Retryable]#{log_label && "[#{log_label}]"} #{e}が起きました。retryします。#{retried} / #{tries}"
13
+
14
+ sleep(interval_on_retry)
12
15
  retry
13
16
  end
14
17
  end
@@ -0,0 +1,63 @@
1
+ require 'socket'
2
+
3
+ class SimpleTCPServer
4
+ def initialize(host, port)
5
+ @host = host
6
+ @port = port
7
+ end
8
+
9
+ def start_server
10
+ @connections = []
11
+ @server = TCPServer.new(@host, @port)
12
+ end
13
+
14
+ def run
15
+ loop do
16
+ timeout = 5 # 5秒のタイムアウト
17
+ readable, _ = IO.select(@connections + [@server], nil, nil, timeout)
18
+ next if readable.nil? # timeoutを迎えるとnilになる
19
+
20
+ readable.each do |socket|
21
+ if socket == @server
22
+ client = @server.accept
23
+ post_init
24
+ @connections << client
25
+ else
26
+ data = socket.gets
27
+ if data.nil?
28
+ @connections.delete(socket)
29
+ unbind
30
+ socket.close
31
+ else
32
+ receive_data(socket, data)
33
+ end
34
+ end
35
+ end
36
+ rescue Errno::EBADF, IOError => e
37
+ unbind
38
+ @connections = []
39
+ @server.close
40
+ end
41
+ end
42
+
43
+ def shutdown
44
+ @server.close
45
+ end
46
+
47
+ # @return [Integer]
48
+ def connections_size
49
+ @connections.size
50
+ end
51
+
52
+ def post_init
53
+ # Override this method
54
+ end
55
+
56
+ def receive_data(socket, data)
57
+ # Override this method
58
+ end
59
+
60
+ def unbind
61
+ # Override this method
62
+ end
63
+ end
@@ -0,0 +1,23 @@
1
+ module ProconBypassMan
2
+ class Watchdog
3
+ def initialize(timeout: 100)
4
+ @timeout = timeout
5
+ active!
6
+ end
7
+
8
+ # @return [Boolean]
9
+ def outdated?
10
+ @time < Time.now
11
+ end
12
+
13
+ # @return [Time]
14
+ def time
15
+ @time
16
+ end
17
+
18
+ # @return [void]
19
+ def active!
20
+ @time = Time.now + @timeout
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,41 @@
1
+ class ProconBypassMan::WebConnectivityChecker
2
+ # @param [String, NilClass] url
3
+ # @param [String, NilClass] ws_url
4
+ def initialize(url, ws_url)
5
+ @url = url
6
+ @ws_url = ws_url
7
+ end
8
+
9
+ # @return [String]
10
+ def to_s
11
+ if @url.nil?
12
+ return "DISABLE"
13
+ end
14
+
15
+ if alive?
16
+ return "ENABLE (#{@url}, #{@ws_url})"
17
+ else
18
+ return "UNREACHABLE (#{@url})"
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ # @return [Boolean]
25
+ def alive?
26
+ uri = URI.parse(@url)
27
+ response = nil
28
+
29
+ begin
30
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
31
+ request = Net::HTTP::Head.new(uri)
32
+ response = http.request(request)
33
+ end
34
+ rescue StandardError => e
35
+ ProconBypassMan.logger.error e
36
+ return false
37
+ end
38
+
39
+ response.is_a?(Net::HTTPSuccess) or response.is_a?(Net::HTTPMovedPermanently)
40
+ end
41
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ProconBypassMan
4
- VERSION = "0.3.6"
4
+ VERSION = "0.3.8"
5
5
  end
@@ -7,11 +7,13 @@ module ProconBypassMan
7
7
  return unless ProconBypassMan.config.enable_ws?
8
8
 
9
9
  Thread.start do
10
- Forever.run { run }
10
+ ProconBypassMan::Forever.run do |watchdog|
11
+ run(watchdog: watchdog)
12
+ end
11
13
  end
12
14
  end
13
15
 
14
- def self.run
16
+ def self.run(watchdog: )
15
17
  EventMachine.run do
16
18
  client = ActionCableClient.new(
17
19
  ProconBypassMan.config.current_ws_server_url, {
@@ -20,15 +22,15 @@ module ProconBypassMan
20
22
  )
21
23
 
22
24
  client.connected {
23
- ProconBypassMan.logger.info('websocket client: successfully connected in ProconBypassMan::Websocket::Client')
25
+ ProconBypassMan.logger.info('[WebsocketClient] successfully connected in ProconBypassMan::Websocket::Client')
24
26
  }
25
27
  client.subscribed { |msg|
26
- ProconBypassMan.logger.info("websocket client: subscribed(#{msg})")
28
+ ProconBypassMan.logger.info("[WebsocketClient] subscribed(#{msg})")
27
29
  ProconBypassMan::SyncDeviceStatsJob.perform(ProconBypassMan::DeviceStatus.current)
28
30
  }
29
31
 
30
32
  client.received do |data|
31
- ProconBypassMan.logger.info('websocket client: received!!')
33
+ ProconBypassMan.logger.info('[WebsocketClient] received!!')
32
34
  ProconBypassMan.logger.info(data)
33
35
 
34
36
  dispatch(data: data, client: client)
@@ -37,20 +39,20 @@ module ProconBypassMan
37
39
  end
38
40
 
39
41
  client.disconnected {
40
- ProconBypassMan.logger.info('websocket client: disconnected!!')
42
+ ProconBypassMan.logger.info('[WebsocketClient] disconnected!!')
41
43
  client.reconnect!
42
44
  sleep 2
43
45
  }
44
46
  client.errored { |msg|
45
- ProconBypassMan.logger.error("websocket client: errored!!, #{msg}")
47
+ ProconBypassMan.logger.error("[WebsocketClient] errored!!, #{msg}")
46
48
  client.reconnect!
47
49
  sleep 2
48
50
  }
49
51
  client.pinged { |msg|
50
- Watchdog.active!
52
+ watchdog.active!
51
53
 
52
54
  ProconBypassMan.cache.fetch key: 'ws_pinged', expires_in: 10 do
53
- ProconBypassMan.logger.info('websocket client: pinged!!')
55
+ ProconBypassMan.logger.info('[WebsocketClient] pinged!!')
54
56
  ProconBypassMan.logger.info(msg)
55
57
  end
56
58
  }