Class: WifiWand::StatusWaiter

Inherits:
Object
  • Object
show all
Defined in:
lib/wifi_wand/services/status_waiter.rb

Constant Summary collapse

PERMITTED_STATES =
%i[wifi_on wifi_off associated disassociated internet_on internet_off].freeze
LEGACY_STATE_HINTS =

Migration hints for removed legacy state names. Shown in error messages so users know exactly what to use instead.

{
  on:   "':on' was removed. Use ':wifi_on' to wait for the WiFi radio to be powered on.",
  off:  "':off' was removed. Use ':wifi_off' to wait for the WiFi radio to be powered off.",
  conn: "':conn' was removed. Use ':internet_on' to wait for full Internet reachability " \
    "(TCP + DNS + no captive-portal login), or ':associated' to wait for WiFi SSID association.",
  disc: "':disc' was removed. Use ':internet_off' to wait for Internet reachability to be " \
    "lost, or ':disassociated' to wait for WiFi to leave the current SSID.",
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(model, verbose: false, output: $stdout, runtime_config: nil) ⇒ StatusWaiter

Returns a new instance of StatusWaiter.



23
24
25
26
27
28
29
# File 'lib/wifi_wand/services/status_waiter.rb', line 23

def initialize(model, verbose: false, output: $stdout, runtime_config: nil)
  @model = model
  @runtime_config = runtime_config || RuntimeConfig.new(
    verbose:    verbose,
    out_stream: output
  )
end

Instance Method Details

#wait_for(target_status, timeout_in_secs: nil, wait_interval_in_secs: nil, stringify_permitted_values_in_error_msg: false) ⇒ Object

Waits for the WiFi/Internet connection to be in the desired state.

Parameters:

  • target_status

    one of PERMITTED_STATES: :wifi_on – WiFi hardware is powered on :wifi_off – WiFi hardware is powered off :associated – WiFi is associated with an SSID (at the WiFi layer) :disassociated – WiFi is not associated with any SSID :internet_on – Full Internet reachability (TCP + DNS + no captive-portal login) :internet_off – Internet reachability check fails

  • timeout_in_secs (defaults to: nil)

    after this many seconds the method raises WaitTimeoutError; if nil (default), waits indefinitely

  • wait_interval_in_secs (defaults to: nil)

    sleeps this interval between retries; if nil, uses default



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/wifi_wand/services/status_waiter.rb', line 43

def wait_for(target_status, timeout_in_secs: nil, wait_interval_in_secs: nil,
  stringify_permitted_values_in_error_msg: false)
  wait_interval_in_secs ||= TimingConstants::DEFAULT_WAIT_INTERVAL
  validate_timing_value!(timeout_in_secs, :timeout_in_secs)
  validate_wait_interval!(wait_interval_in_secs)
  validate_target!(target_status, stringify_permitted_values_in_error_msg)
  message_prefix = "StatusWaiter (#{target_status}):"

  if verbose?
    timeout_display = timeout_in_secs ? "#{timeout_in_secs}s" : 'never'
    err_output.puts <<~MESSAGE.chomp
      #{message_prefix} starting, timeout: #{timeout_display}, interval: #{wait_interval_in_secs}s
    MESSAGE
  end

  finished_predicate = finished_predicates.fetch(target_status)
  expensive_predicate = %i[internet_on internet_off].include?(target_status)

  start_time = current_time
  deadline = timeout_in_secs && (start_time + timeout_in_secs)

  if predicate_satisfied?(
    finished_predicate,
    target_status:       target_status,
    timeout_in_secs:     timeout_in_secs,
    deadline:            deadline,
    expensive_predicate: expensive_predicate
  )
    err_output.puts "#{message_prefix} completed without needing to wait" if verbose?
    return nil
  elsif verbose?
    err_output.puts "#{message_prefix} First attempt failed, entering waiting loop"
  end

  loop do
    raise_timeout_if_deadline_exceeded!(target_status, timeout_in_secs, deadline)

    err_output.puts "#{message_prefix} checking predicate..." if verbose?
    if predicate_satisfied?(
      finished_predicate,
      target_status:       target_status,
      timeout_in_secs:     timeout_in_secs,
      deadline:            deadline,
      expensive_predicate: expensive_predicate
    )
      if verbose?
        end_time = current_time
        err_output.puts "#{message_prefix} wait time (seconds): #{end_time - start_time}"
      end
      return nil
    end

    sleep_duration = sleep_duration_for(wait_interval_in_secs, deadline)
    raise_timeout_if_deadline_exceeded!(target_status, timeout_in_secs, deadline) if sleep_duration <= 0

    sleep(sleep_duration)
  end
end