o
    u]-                  	   @   s  d Z ddlZddlZddlZddlZddlmZmZ zddl	m
Z
 W n ey1   ddlm
Z
 Y nw dZdZG dd deZG d	d
 d
eZdd Zdd Zdd Zdd Zi ddefddefddefddefddefddefddefddefddefd d!efd"d#efd$d%efd&d&efd'd'efd(d(efd)d*efd+d,efd-efd.efd/efd0efd1efd2efd3efd4Zdd5iZdAd7d8Zd9d: Zd;d< Zd=d> ZG d?d@ d@eZdS )Ba  
Parsing for Bandwidth Authority metrics as described in Tor's
`bandwidth-file-spec <https://gitweb.torproject.org/torspec.git/tree/bandwidth-file-spec.txt>`_.

**Module Overview:**

::

  BandwidthFile - Tor bandwidth authority measurements.

.. versionadded:: 1.8.0
    N)_mappings_for
Descriptor)OrderedDicts   =====s   ====c                   @      e Zd ZdZdd ZdS )RecentStatsaE  
  Statistical information collected over the last 'data_period' (by default
  five days).

  :var int consensus_count: number of consensuses published during this period

  :var int prioritized_relays: number of relays prioritized to be measured
  :var int prioritized_relay_lists: number of times a set of relays were
    prioritized to be measured

  :var int measurement_attempts: number of relay measurements we attempted
  :var int measurement_failures: number of measurement attempts that failed

  :var RelayFailures relay_failures: number of relays we failed to measure
  c                 C   s*   d | _ d | _d | _d | _d | _t | _d S N)Zconsensus_countZprioritized_relaysZprioritized_relay_listsZmeasurement_attemptsZmeasurement_failuresRelayFailuresZrelay_failuresself r   @/usr/lib/python3/dist-packages/stem/descriptor/bandwidth_file.py__init__:   s   zRecentStats.__init__N__name__
__module____qualname____doc__r   r   r   r   r   r   )   s    r   c                   @   r   )r   a  
  Summary of the number of relays we were unable to measure.

  :var int no_measurement: number of relays that did not have any successful
    measurements
  :var int insuffient_period: number of relays whos measurements were collected
    over a period that was too small (1 day by default)
  :var int insufficient_measurements: number of relays we did not collect
    enough measurements for (2 by default)
  :var int stale: number of relays whos latest measurement is too old (5 days
    by default)
  c                 C   s   d | _ d | _d | _d | _d S r   )Zno_measurementZinsuffient_periodZinsufficient_measurementsZstaler	   r   r   r   r   Q   s   
zRelayFailures.__init__Nr   r   r   r   r   r   C   s    r   c                 C   s   | S r   r   valr   r   r   _str[   s   r   c                 C   s   | r
|   r
t| S d S r   )isdigitintr   r   r   r   _int_   s   r   c                 C   s&   zt jj| W S  ty   Y d S w r   )stemutil	str_toolsZ_parse_iso_timestamp
ValueErrorr   r   r   r   _datec   s
   r   c                 C   s$   | d urt tdd | dS d S )Nc                 S   s   |   S r   )strip)vr   r   r   <lambda>k   s    z_csv.<locals>.<lambda>,)listmapsplitr   r   r   r   _csvj   s   $r%   versionZsoftwareZsoftware_versionZearliest_bandwidthZlatest_bandwidthZ
created_atZfile_createdZgenerated_atZgenerator_startedZconsensus_sizeZnumber_consensus_relaysZeligible_countZnumber_eligible_relaysZeligible_percentZpercent_eligible_relaysZ	min_countZminimum_number_eligible_relaysZmin_percentZminimum_percent_eligible_relaysZscanner_countryZdestinations_countriesZtime_to_report_half_networkzrecent_stats.consensus_countZrecent_consensus_countz$recent_stats.prioritized_relay_listsZrecent_priority_list_countZrecent_priority_relay_countZ recent_measurement_attempt_countZ recent_measurement_failure_countZ(recent_measurements_excluded_error_countZ'recent_measurements_excluded_near_countZ&recent_measurements_excluded_few_countZ&recent_measurements_excluded_old_count)zrecent_stats.prioritized_relaysz!recent_stats.measurement_attemptsz!recent_stats.measurement_failuresz*recent_stats.relay_failures.no_measurementz-recent_stats.relay_failures.insuffient_periodz5recent_stats.relay_failures.insufficient_measurementsz!recent_stats.relay_failures.stale1.0.0Fc                 k   s    t |  |fi |V  dS )a  
  Iterates over the bandwidth authority metrics in a file.

  :param file descriptor_file: file with descriptor content
  :param bool validate: checks the validity of the descriptor's content if
    **True**, skips these checks otherwise
  :param dict kwargs: additional arguments for the descriptor constructor

  :returns: :class:`stem.descriptor.bandwidth_file.BandwidthFile` object

  :raises:
    * **ValueError** if the contents is malformed and validate is **True**
    * **IOError** if the file can't be read
  N)BandwidthFileread)Zdescriptor_filevalidatekwargsr   r   r   _parse_file   s   r,   c                 C   s4  t  }t|  }|  d}d }	 |  }|sn5|ttfv r#n.|s*d|v r*n'd|v rFtj	j
|dd\}}|||< |dkrE|}ntd| |d7 }q|| _t | _t D ]-\}	\}
}| }|	dd d	 D ]}t||}qmt||	dd	 |||
t|	 q\|d ur|dkrtd
d S d S )N   Ts   node_id=   ==r&   z3Header expected to be key=value pairs, but had '%s'.z3The 'version' header must be in the second position)r   ioBytesIO	get_bytesreadliner   
HEADER_DIVHEADER_DIV_ALTr   r   r   _to_unicoder$   r   headerr   Zrecent_statsHEADER_ATTRitemsgetattrsetattrgetHEADER_DEFAULT)
descriptorentriesr9   contentindexZversion_indexlinekeyvalueZ	full_attrkeywordclsobjattrr   r   r   _parse_header   s@   *rK   c                 C   s@   t |    }| rtjt|| _	d S t
d| )Nz3First line should be a unix timestamp, but was '%s')r2   r3   r4   r5   r   r   datetimeZutcfromtimestampr   	timestampr   )r@   rA   Z
first_liner   r   r   _parse_timestamp   s   rN   c                 C   s   t |  }| jdkr|  n|  dttfvr(	 |  dttfvsi }| D ]1}t	j
j| }ttd|}|ddd}|sQtd| ||v r[td| |||< q.|| _d S )Nr'    measurementZnode_id$z+Every meaurement must include 'node_id': %szBRelay %s is listed multiple times. It should only be present once.)r2   r3   r4   r&   r5   r   r6   r7   	readlinesr   r   r   r8   dictr   r>   lstripr   measurements)r@   rA   rB   rU   rD   rJ   Zfingerprintr   r   r   _parse_body   s"   



rV   c                       sh   e Zd ZdZdZdefi efi efdZe	e
dd e D  edd	d
Zd fdd	Z  ZS )r(   aX  
  Tor bandwidth authority measurements.

  :var dict measurements: **\*** mapping of relay fingerprints to their
    bandwidth measurement metadata

  :var dict header: **\*** header metadata
  :var datetime timestamp: **\*** time when these metrics were published
  :var str version: **\*** document format version

  :var str software: application that generated these metrics
  :var str software_version: version of the application that generated these metrics

  :var datetime earliest_bandwidth: time of the first sampling
  :var datetime latest_bandwidth: time of the last sampling
  :var datetime created_at: time when this file was created
  :var datetime generated_at: time when collection of these metrics started

  :var int consensus_size: number of relays in the consensus
  :var int eligible_count: relays with enough measurements to be included
  :var int eligible_percent: percentage of consensus with enough measurements
  :var int min_count: minimum eligible relays for results to be provided
  :var int min_percent: minimum measured percentage of the consensus

  :var str scanner_country: country code where this scan took place
  :var list destinations_countries: all country codes that were scanned

  :var int time_to_report_half_network: estimated number of seconds required to
    measure half the network, given recent measurements

  :var RecentStats recent_stats: statistical information collected over the
    last 'data_period' (by default five days)

  **\*** attribute is either required when we're parsed with validation or has
  a default value, others are left as **None** if undefined
  zbandwidth-fileN)rM   r9   rU   c                 C   s   g | ]}|d t ffqS r   )rK   ).0kr   r   r   
<listcomp>2  s    zBandwidthFile.<listcomp>r   Fc                 C   s   |r	t d| j |durt|nt }|dttt }|dg }|dtd}g }d|vr?|	t
jj| |dkrI|rItd|dkr|d|vr`|	t
jjd|d  | D ]\}	}
|	t
jjd	|	|
f  qd|	t |D ]}|	t
jj| q~d
|S )a  
    Creates descriptor content with the given attributes. This descriptor type
    differs somewhat from others and treats our attr/exclude attributes as
    follows...

      * 'timestamp' is a reserved key for our mandatory header unix timestamp.

      * 'content' is a reserved key for our bandwidth measurement lines.

      * All other keys are treated as header fields.

    For example...

    ::

      BandwidthFile.content({
        'timestamp': '12345',
        'version': '1.2.0',
        'content': [],
      })
    zSigning of %s not implementedNrM   rB   r&   r'   z2Headers require BandwidthFile version 1.1 or laterz
version=%sz%s=%s   
)NotImplementedErrorr   r   popstrr   timer>   r?   appendr   r   r   Z	_to_bytesr   r;   r6   join)rH   rJ   Zexcludesignr9   rM   rB   r&   linesrX   r   rP   r   r   r   rB   4  s(   

zBandwidthFile.contentc                    s@   t t| j|| d |rt| d  t| d  t| d  d S d S )N)Z	lazy_load)superr(   r   rN   rK   rV   )r
   Zraw_contentr*   	__class__r   r   r   k  s   

zBandwidthFile.__init__)Nr   FF)r   r   r   r   ZTYPE_ANNOTATION_NAMErN   rK   rV   Z
ATTRIBUTESupdaterS   r:   keysclassmethodrB   r   __classcell__r   r   rd   r   r(     s    %6r(   rf   )r   rL   r2   r^   Zstem.util.str_toolsr   Zstem.descriptorr   r   collectionsr   ImportErrorZstem.util.ordereddictr6   r7   objectr   r   r   r   r   r%   r:   r?   r,   rK   rN   rV   r(   r   r   r   r   <module>   s   	
 *
-	