Class: PatronusFati::DataModels::Client

Inherits:
Object
  • Object
show all
Includes:
CommonState
Defined in:
lib/patronus_fati/data_models/client.rb

Constant Summary collapse

LOCAL_ATTRIBUTE_KEYS =
[ :mac, :channel ].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from CommonState

#active?, #data_dirty?, #dirty?, included, #mark_synced, #new?, #set_sync_flag, #status_dirty?, #sync_flag?

Constructor Details

#initialize(mac) ⇒ Client

Returns a new instance of Client.



72
73
74
75
76
77
# File 'lib/patronus_fati/data_models/client.rb', line 72

def initialize(mac)
  super
  self.access_point_bssids = []
  self.local_attributes = { channel: 0, mac: mac }
  self.probes = {}
end

Instance Attribute Details

#access_point_bssidsvoid

Returns the value of attribute access_point_bssids.



6
7
8
# File 'lib/patronus_fati/data_models/client.rb', line 6

def access_point_bssids
  @access_point_bssids
end

#last_dbmvoid

Returns the value of attribute last_dbm.



6
7
8
# File 'lib/patronus_fati/data_models/client.rb', line 6

def last_dbm
  @last_dbm
end

#local_attributesvoid

Returns the value of attribute local_attributes.



6
7
8
# File 'lib/patronus_fati/data_models/client.rb', line 6

def local_attributes
  @local_attributes
end

#probesvoid

Returns the value of attribute probes.



6
7
8
# File 'lib/patronus_fati/data_models/client.rb', line 6

def probes
  @probes
end

Class Method Details

.current_expiration_thresholdvoid



10
11
12
# File 'lib/patronus_fati/data_models/client.rb', line 10

def self.current_expiration_threshold
  Time.now.to_i - CLIENT_EXPIRATION
end

Instance Method Details

#add_access_point(bssid) ⇒ void



14
15
16
# File 'lib/patronus_fati/data_models/client.rb', line 14

def add_access_point(bssid)
  access_point_bssids << bssid unless access_point_bssids.include?(bssid)
end

#announce_changesvoid



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/patronus_fati/data_models/client.rb', line 18

def announce_changes
  return unless dirty? && valid? && worth_syncing?

  if active?
    status = new? ? :new : :changed
    PatronusFati.event_handler.event(:client, status, full_state, diagnostic_data)
  else
    PatronusFati.event_handler.event(
      :client, :offline, {
        'bssid' => local_attributes[:mac],
        'uptime' => presence.visible_time
      },
      diagnostic_data
    )

    # We need to reset the first seen so we get fresh duration information
    presence.first_seen = nil

    access_point_bssids.each do |bssid|
      DataModels::AccessPoint[bssid].remove_client(local_attributes[:mac])
      DataModels::Connection["#{bssid}^#{local_attributes[:mac]}"].link_lost = true
    end
  end

  mark_synced
end

#cleanup_probesvoid

Probes don’t have an explicit visibility window so this will only remove probes that haven’t been seen in the entire duration of the time we track any visibility.



48
49
50
51
52
# File 'lib/patronus_fati/data_models/client.rb', line 48

def cleanup_probes
  return if probes.select { |_, pres| pres.dead? }.empty?
  set_sync_flag(:dirtyChildren)
  probes.reject! { |_, pres| pres.dead? }
end

#diagnostic_datavoid



54
55
56
57
58
59
# File 'lib/patronus_fati/data_models/client.rb', line 54

def diagnostic_data
  dd = super
  dd[:last_dbm] = last_dbm if last_dbm
  dd[:visible_time] = presence.visible_time
  dd
end

#full_statevoid



61
62
63
64
65
66
67
68
69
70
# File 'lib/patronus_fati/data_models/client.rb', line 61

def full_state
  {
    active: active?,
    bssid: local_attributes[:mac],
    channel: local_attributes[:channel],
    connected_access_points: access_point_bssids,
    probes: probes.keys,
    vendor: vendor
  }
end

#remove_access_point(bssid) ⇒ void



79
80
81
# File 'lib/patronus_fati/data_models/client.rb', line 79

def remove_access_point(bssid)
  access_point_bssids.delete(bssid)
end

#track_probe(probe) ⇒ void



83
84
85
86
87
88
# File 'lib/patronus_fati/data_models/client.rb', line 83

def track_probe(probe)
  return unless probe && probe.length > 0

  self.probes[probe] ||= Presence.new
  self.probes[probe].mark_visible
end

#update(attrs) ⇒ void



90
91
92
93
94
95
96
97
98
# File 'lib/patronus_fati/data_models/client.rb', line 90

def update(attrs)
  attrs.each do |k, v|
    next unless LOCAL_ATTRIBUTE_KEYS.include?(k)
    next if v.nil? || local_attributes[k] == v

    set_sync_flag(:dirtyAttributes)
    local_attributes[k] = v
  end
end

#valid?Boolean

Returns:

  • (Boolean)


100
101
102
# File 'lib/patronus_fati/data_models/client.rb', line 100

def valid?
  !local_attributes[:mac].nil?
end

#vendorvoid



104
105
106
107
108
# File 'lib/patronus_fati/data_models/client.rb', line 104

def vendor
  return unless local_attributes[:mac]
  result = Louis.lookup(local_attributes[:mac])
  result['long_vendor'] || result['short_vendor']
end

#worth_syncing?Boolean

This is a safety mechanism to check whether or not a client device is actually ‘present’. This is intended to cut out the one time fake generated addresses from devices that generate random MAC addresses, probe quickly and disappear and requires us to either see a client connect to an access point, be visible for more than one interval, or have already been synced.

Returns:

  • (Boolean)


116
117
118
119
# File 'lib/patronus_fati/data_models/client.rb', line 116

def worth_syncing?
  access_point_bssids.any? || sync_flag?(:syncedOnline) || probes.any? ||
    (presence && presence.visible_time && presence.visible_time > INTERVAL_DURATION)
end