
    h-              	          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 	 ddl	m
Z
 dZdZ G d de      Z G d	 d
e      Zd Zd Zd Z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d,efd-efd.efd/efd0Zdd1iZd8d2Zd3 Zd4 Zd5 Z G d6 d7e      Zy# e$ r	 ddlm
Z
 Y w xY w)9a  
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 Zy)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                 h    d | _         d | _        d | _        d | _        d | _        t               | _        y N)consensus_countprioritized_relaysprioritized_relay_listsmeasurement_attemptsmeasurement_failuresRelayFailuresrelay_failuresselfs    h/var/www/betterdocs.net/sherlock_api/venv/lib/python3.12/site-packages/stem/descriptor/bandwidth_file.py__init__zRecentStats.__init__:   s4    D"D#'D  $D $D'/D    N__name__
__module____qualname____doc__r    r   r   r   r   )   s     *r   r   c                       e Zd ZdZd Zy)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                 <    d | _         d | _        d | _        d | _        y r	   )no_measurementinsuffient_periodinsufficient_measurementsstaler   s    r   r   zRelayFailures.__init__Q   s!    D!D%)D"DJr   Nr   r   r   r   r   r   C   s    r   r   c                     | S r	   r   vals    r   _strr%   [   s    	*r   c                 @    | r| j                         rt        |       S d S r	   )isdigitintr#   s    r   _intr)   _   s    ckkmS6$6r   c                 t    	 t         j                  j                  j                  |       S # t        $ r Y y w xY wr	   )stemutil	str_tools_parse_iso_timestamp
ValueErrorr#   s    r   _dater0   c   s4    9933C88	 s   (+ 	77c                 T    | %t        t        d | j                  d                  S d S )Nc                 "    | j                         S r	   )strip)vs    r   <lambda>z_csv.<locals>.<lambda>k   s    AGGI r   ,)listmapsplitr#   s    r   _csvr:   j   s'    ;>?c%syy~6	7TPTTr   versionsoftwaresoftware_versionearliest_bandwidthlatest_bandwidth
created_atfile_createdgenerated_atgenerator_startedconsensus_sizenumber_consensus_relayseligible_countnumber_eligible_relayseligible_percentpercent_eligible_relays	min_countminimum_number_eligible_relaysmin_percentminimum_percent_eligible_relaysscanner_countrydestinations_countriestime_to_report_half_networkzrecent_stats.consensus_countrecent_consensus_countz$recent_stats.prioritized_relay_listsrecent_priority_list_countrecent_priority_relay_count recent_measurement_attempt_count recent_measurement_failure_count(recent_measurements_excluded_error_count'recent_measurements_excluded_near_count&recent_measurements_excluded_few_count&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.0c              +   F   K   t        | j                         |fi | yw)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)descriptor_filevalidatekwargss      r   _parse_filera      s#       	o**,hA&AAs   !c                 &   t               }t        j                  | j                               }|j	                          d}d }	 |j	                         j                         }|snw|t        t        fv rnh|sd|v rnad|v rIt        j                  j                  j                  |      j                  dd      \  }}|||<   |dk(  r|}nt        d|z        |dz  }|| _        t               | _        t"        j%                         D ]w  \  }	\  }
}| }|	j                  d      d d D ]  }t'        ||      } t)        ||	j                  d      d    ||j+                  |
t,        j+                  |	                         y ||dk7  rt        d	      y y )
N   s   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readliner3   
HEADER_DIVHEADER_DIV_ALTr+   r,   r-   _to_unicoder9   r/   headerr   recent_statsHEADER_ATTRitemsgetattrsetattrgetHEADER_DEFAULT)
descriptorentriesro   contentindexversion_indexlinekeyvalue	full_attrkeywordclsobjattrs                 r   _parse_headerr      s   =&JJz++-.'	
%-##%D	*n-	-t+t|99&&2248>>sAFjc5fSk			LtSTT	QJE' 	* *'M*#.#4#4#6 di'3
C$Sb) Cc C%b)3vzz'>CUCUV_C`/a+bcd =A#5
J
KK $6r   c                    t        j                  | j                               j                         j	                         }|j                         r.t        j                  j                  t        |            | _	        y t        d|z        )Nz3First line should be a unix timestamp, but was '%s')rh   ri   rj   rk   r3   r'   datetimeutcfromtimestampr(   	timestampr/   )rw   rx   
first_lines      r   _parse_timestampr      se    zz*..01::<BBD*#,,==c*oNJ
JZW
XXr   c                    t        j                  | j                               }| j                  dk(  r|j	                          nX|j	                         j                         dt        t        fvr-	 |j	                         j                         dt        t        fvr-i }|j                         D ]  }t        j                  j                  j                  |j                               }t        t        d|            }|j                  dd      j!                  d      }|st#        d|z        ||v rt#        d|z        |||<    || _        y )NrZ    measurementnode_id$z+Every meaurement must include 'node_id': %szBRelay %s is listed multiple times. It should only be present once.)rh   ri   rj   r;   rk   r3   rl   rm   	readlinesr+   r,   r-   rn   dictr   ru   lstripr/   measurements)rw   rx   ry   r   r|   r   fingerprints          r   _parse_bodyr      s)    JJz++-.'7"




"
"
$R^,L
L
 



"
"
$R^,L
L ,! 
%d99**4::<8DmT23D((9b)005KDtKLL		$[^iijj $L
% )*r   c                       e Zd ZdZdZdefi efi efdZej                   e
ej                         D  cg c]  }|dt        ff c}}}              edd       Zdfd	ZxZS c c}}} w )	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)r   ro   r   c           	         |rt        d| j                  z        |t        |      n	t               }|j                  dt	        t        t        j                                           }|j                  dg       }|j                  dt        j                  d            }g }d|vr8|j                  t        j                  j                  j                  |             |dk(  r|rt        d      |dk7  rd|vrJ|j                  t        j                  j                  j                  d|j                  d      z               |j                         D ]B  \  }	}
|j                  t        j                  j                  j                  |	d|
             D |j                  t                |D ]:  }|j                  t        j                  j                  j                  |             < d	j#                  |      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 implementedr   ry   r;   rZ   z2Headers require BandwidthFile version 1.1 or laterz
version=%sre      
)NotImplementedErrorr   r   popstrr(   timeru   rv   appendr+   r,   r-   	_to_bytesr/   rr   rl   join)r   r   excludesignro   r   ry   r;   lineskr4   r   s               r   ry   zBandwidthFile.content4  s   0  ?#,, NOO"&"2[F

;C		,<(=>IjjB'GjjN$6$6y$ABGE'!ll499&&00;<'fKLL	G	 
'	!TYY((22<&**YBW3WXY,,. F$!QTYY((22a3CDEF ll: ?ll499&&00=>? ::er   c                     t         t        |   ||        |r%t        | d        t	        | d        t        | d        y y )N)	lazy_load)superr\   r   r   r   r   )r   raw_contentr_   	__class__s      r   r   zBandwidthFile.__init__k  s?    	-'X'NtT"D$$ r   )Nr   FF)r   r   r   r   TYPE_ANNOTATION_NAMEr   r   r   
ATTRIBUTESupdater   rq   keysclassmethodry   r   __classcell__).0r   r   r   s   000@r   r\   r\     s    #J * ()=!%* Dk>N>N>PQQ1t]34QRS4 4l s Rs   A(r\   r   )r   r   rh   r   stem.util.str_toolsr+   stem.descriptorr   r   collectionsr   ImportErrorstem.util.ordereddictrl   rm   objectr   r   r%   r)   r0   r:   rq   rv   ra   r   r   r   r\   r   r   r   <module>r      s$    	  
0% 
*& *4F 07U' i'
 z4 ' )40' -u5' )51' '' &.' .5'  -t4!'" 0$7#'$ 0$7%'& 3T:''. './'0 5t<1'8  "?!F9'< !#;T"B='> )+G*N?'@ 'DT%J(JD'Q(JD'Q1[]a0b4]_c3d<dfj;k(PRV'WM'T W
B&*LZY):mJ mK  0/0s   C C"!C"