Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a dataclass abstraction for clients and other objects #5

Open
nickovs opened this issue Dec 31, 2019 · 3 comments
Open

Provide a dataclass abstraction for clients and other objects #5

nickovs opened this issue Dec 31, 2019 · 3 comments
Labels
enhancement New feature or request

Comments

@nickovs
Copy link
Owner

nickovs commented Dec 31, 2019

Currently the representation of clients in unificontrol is just the raw data that comes back from the underlying API. In a comment on another issue @wolph suggested that it would be useful to have an abstraction that represents clients as their own data objects and provide a higher level API for manipulating them.

@nickovs nickovs added the enhancement New feature or request label Dec 31, 2019
@wolph
Copy link
Contributor

wolph commented Dec 31, 2019

For Python 3.6 there's a backport available so that's easily fixed: https://pypi.org/project/dataclasses/
The requirement would be:

dataclasses; python_version < '3.7'

Another question would be how this new API would be exposed. The way I see it there are a few options:

  1. Add an option to client so client.list_clients() returns this object when the new API is enabled
  2. Add a parameter to methods such as client.list_client() so it returns the new style
  3. Add a new method for this so that client.clients would be a collection class that is both iterable and subscriptable using something like client.clients[mac_address].
  4. Add a dict api to the dataclasses to maintain backwards compatibility

My vote would be option 3, but that's your decision :)

@wolph
Copy link
Contributor

wolph commented Dec 31, 2019

Example:

@dataclasses.dataclass                       
class Client:                                
    _id: str                                 
    assoc_time: int                          
    authorized: bool                         
    first_seen: int                          
    ip: str                                  
    is_guest: bool                           
    is_wired: bool                           
    last_seen: int                           
    latest_assoc_time: int                   
    mac: str                                 
    oui: str                                 
    qos_policy_applied: bool                 
    rx_bytes: int                            
    rx_bytes_r: int                          
    rx_packets: int                          
    site_id: str                             
    tx_bytes: int                            
    tx_bytes_r: int                          
    tx_packets: int                          
    tx_retries: int                          
    uptime: int                              
    user_id: str                             
    wifi_tx_attempts: int                    
    _is_guest_by_uap: bool = None            
    _is_guest_by_ugw: bool = None            
    _is_guest_by_usw: bool = None            
    _last_seen_by_uap: int = 0               
    _last_seen_by_ugw: int = 0               
    _last_seen_by_usw: int = 0               
    _uptime_by_uap: int = 0                  
    _uptime_by_ugw: int = 0                  
    _uptime_by_usw: int = 0                  
    anomalies: int = 0                       
    ap_mac: str = ''                         
    bssid: str = ''                          
    bytes_r: int = 0                         
    ccq: int = 0                             
    channel: int = 0                         
    confidence: int = 0                      
    dev_cat: int = 0                         
    dev_family: int = 0                      
    dev_id: int = 0                          
    dev_vendor: int = 0                      
    device_name: str = ''                    
    dhcpend_time: int = 0                    
    essid: str = ''                          
    fingerprint_source: int = 0              
    fixed_ip: str = ''                       
    fw_version: str = ''                     
    gw_mac: str = ''                         
    hostname: str = ''                       
    idletime: int = 0                        
    is_11r: bool = None                      
    name: str = ''                           
    network: str = ''                        
    network_id: str = ''                     
    noise: int = 0                           
    noted: bool = None                       
    os_class: int = 0                        
    os_name: int = 0                         
    powersave_enabled: bool = None           
    priority: int = 0                        
    radio: str = ''                          
    radio_name: str = ''                     
    radio_proto: str = ''                    
    roam_count: int = 0                      
    rssi: int = 0                            
    rx_rate: int = 0                         
    satisfaction: int = 0                    
    score: int = 0                           
    signal: int = 0                          
    sw_depth: int = 0                        
    sw_mac: str = ''                         
    sw_port: int = 0                         
    tx_power: int = 0                        
    tx_rate: int = 0                         
    use_fixedip: bool = None                 
    usergroup_id: str = ''                   
    vlan: int = 0                            

Generated by:

 import collections                                          
 keys = collections.defaultdict(list)                        
 counter = 0                                                 
 for data in client.list_clients():                                        
     counter += 1                                            
     data = {k.replace('-', '_'): v for k, v in data.items()}
     for key, value in data.items():                         
         keys[key].append(value)                             
                                                             
 required = dict()                                           
 optional = dict()                                           
 for key, values in sorted(keys.items()):                    
     type_ = type(values[0])                                 
     if type_ is int:                                        
         default = 0                                         
     elif type_ is str:                                      
         default = ''                                        
     elif type_ is bool:                                     
         default = None                                      
     else:                                                   
         raise TypeError()                                   
                                                             
     type_str = f'{type_.__name__}'                          
                                                             
     if len(values) == counter:                              
         required[key] = type_str                            
     else:                                                   
         optional[key] = f'{type_str} = {default!r}'         
                                                             
 for key, type_ in sorted(required.items()):                 
     print(f'{key}: {type_}')                                
                                                             
 for key, type_ in sorted(optional.items()):                 
     print(f'{key}: {type_}')                                

@wolph
Copy link
Contributor

wolph commented Dec 31, 2019

Using these we can create a high-level API that could work something like this:

fixed_hosts = dict(...)

for client in api.clients:
    fixed_host = fixed_hosts.get(client.mac)
    if not fixed_host:
        continue

    client.name = fixed_hostname.name
    client.fixed_ip = fixed_hostname.ip

# Or:
for mac, fixed_host in fixed_hosts.items():
    api.clients[mac].name = fixed_host.name
    api.clients[mac].fixed_ip = fixed_host.ip

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants