Class: WifiWand::NetworkStateManager

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

Constant Summary collapse

RESTORE_CONNECT_RETRY_WAIT_SECONDS =
5.0
RESTORE_CONNECT_MAX_ATTEMPTS =
5
RESTORE_CONNECT_SETTLE_SECONDS =
20.0
RESTORE_CONNECT_SETTLE_POLL_SECONDS =
2.0
RESTORE_CONNECT_RETRY_PATTERNS =
[
  /Error:\s*-3900/i,
  /tmpErr/i,
  /couldn(?:\?\?\?|'|’)t be completed/i,
].freeze
EXPECTED_RESTORE_ERRORS =
[
  WifiWand::Error,
  IOError,
  SocketError,
  Timeout::Error,
  Errno::ECONNREFUSED,
  Errno::ETIMEDOUT,
  Errno::EHOSTUNREACH,
  Errno::ENETUNREACH,
].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

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

Returns a new instance of NetworkStateManager.



30
31
32
33
34
35
36
# File 'lib/wifi_wand/services/network_state_manager.rb', line 30

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

Class Method Details

.restorable_network_name?(network_name) ⇒ Boolean

Returns:

  • (Boolean)


44
45
46
# File 'lib/wifi_wand/services/network_state_manager.rb', line 44

def self.restorable_network_name?(network_name)
  network_name && !network_name.empty?
end

.state_associated?(state) ⇒ Boolean

Returns:

  • (Boolean)


38
39
40
41
42
# File 'lib/wifi_wand/services/network_state_manager.rb', line 38

def self.state_associated?(state)
  return state[:associated] if state.key?(:associated)

  restorable_network_name?(state[:network_name])
end

Instance Method Details

#capture_network_stateObject

Network State Management for Testing These methods help capture and restore network state during disruptive tests



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
# File 'lib/wifi_wand/services/network_state_manager.rb', line 51

def capture_network_state
  identity_error = nil
  network_name = begin
    @model.connected_network_name
  rescue WifiWand::Error => e
    identity_error = e
    nil
  end
  associated = captured_association_state(network_name, identity_error)

  # Always attempt to capture password for consistent restoration
  # If we're capturing network state, we should have the password available
  # for reliable restoration without repeated keychain prompts
  network_password = if network_name
    begin
      connected_network_password
    rescue WifiWand::Error => e
      err_output.puts "Warning: Failed to retrieve password for #{network_name}: #{e.message}" if verbose?
      nil
    end
  end

  {
    wifi_enabled:     @model.wifi_on?,
    associated:       associated,
    network_name:     network_name,
    network_password: network_password,
    interface:        @model.wifi_interface,
  }
end

#restore_network_state(state, fail_silently: false) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/wifi_wand/services/network_state_manager.rb', line 82

def restore_network_state(state, fail_silently: false)
  err_output.puts "restore_network_state: #{state} called" if verbose?
  return :no_state_to_restore unless state

  begin
    # Restore WiFi enabled state
    if state[:wifi_enabled]
      unless @model.wifi_on?
        @model.wifi_on
        @model.till(:wifi_on, timeout_in_secs: TimingConstants::WIFI_STATE_CHANGE_WAIT)
      end
    else
      if @model.wifi_on?
        @model.wifi_off
        @model.till(:wifi_off, timeout_in_secs: TimingConstants::WIFI_STATE_CHANGE_WAIT)
      end
      return # If WiFi should be off, we're done
    end

    if originally_associated?(state)
      restore_associated_network_state(state)
    else
      restore_disassociated_network_state
    end
  rescue *EXPECTED_RESTORE_ERRORS => e
    raise unless fail_silently

    err_output.puts "Warning: Could not restore network state (#{e.class}): #{e.message}"
    if restorable_network_name?(state[:network_name])
      err_output.puts "You may need to manually reconnect to: #{state[:network_name]}"
    else
      err_output.puts 'You may need to manually restore the original WiFi state.'
    end
    nil
  end
end