o
    
]                     @   s8  d dl Z d dlZd dlZd dlZd dlZd dlZd dlZd dlZd dlZd dlm	Z	m
Z
mZmZ edZedZedZdZej rHeneZG dd dejjZG d	d
 d
eZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZ G dd deZ!G dd deZ"G dd deZ#G dd deZ$G dd  d eZ%G d!d" d"eZ&G d#d$ d$eZ'G d%d& d&eZ(G d'd( d(eZ)G d)d* d*eZ*G d+d, d,eZ+G d-d. d.eZ,G d/d0 d0eZ-G d1d2 d2eZ.G d3d4 d4eZ/G d5d6 d6eZ0G d7d8 d8eZ1G d9d: d:eZ2G d;d< d<eZ3G d=d> d>eZ4d?d@ Z5i dAedBedCedDedEe3dFedGe2dHedIe dJe!dKe1dLe&dMe"dNe&dOe#dPe$dQe%i dRe&dSe(dTe)dUe*dVe&dWe'dXe+dYe,dZe-d[e-d\e-d]e.d^e/d_e4d`e0dae&dbe-Z6dS )c    N)
connectionlog	str_tools	tor_toolsz^(.*) ([A-Za-z0-9_]+)=(\S*)$z^(.*) ([A-Za-z0-9_]+)="(.*)"$z^[a-z0-9_]+$Tc                   @   s`   e Zd ZdZdZi ZdZdZdZe	j
dZdd Zdd Zd	d
 Zdd Zdd Zdd ZdS )EventaA  
  Base for events we receive asynchronously, as described in section 4.1 of the
  `control-spec
  <https://gitweb.torproject.org/torspec.git/tree/control-spec.txt>`_.

  :var str type: event type
  :var list positional_args: positional arguments of the event
  :var dict keyword_args: key/value arguments of the event
   Fz0.1.1.1-alphac                 C   sd   t |  stdt |  d | _g | _i | _| jtv r%t| j | _	| j
s,|   |   d S )NzFReceived a blank tor event. Events must at the very least have a type.r   )strstripstemProtocolErrorsplittypepositional_argskeyword_argsEVENT_TYPE_TO_CLASS	__class___SKIP_PARSING_parse_standard_attr_parseselfr   r   6/usr/lib/python3/dist-packages/stem/response/events.py_parse_message1   s   

zEvent._parse_messagec                 C   s   t jj| dt jjddS )NZ
arrived_atT)parentcache)r
   utilZ
_hash_attrresponseControlMessager   r   r   r   __hash__C   s   zEvent.__hash__c           
      C   sR  t | }	 t|}|st|}|r | \}}}|| j|< nnq| dd | _t| j}| j	D ]_}d}|r|| j
v sJ|| jv r|d dr|dg}|d ds`td|| f 	 |sltd|| f ||d |d dr|nqad	|dd }n|d}t| || q3| j D ]\}	}t| || j|	 qdS )
a%  
    Most events are of the form...
    650 *( positional_args ) *( key "=" value )

    This parses this standard format, populating our **positional_args** and
    **keyword_args** attributes and creating attributes if it's in our event's
    **_POSITIONAL_ARGS** and **_KEYWORD_ARGS**.
    T   Nr   "zCThe %s value should be quoted, but didn't have a starting quote: %szBThe %s value should be quoted, but didn't have an ending quote: %s )r   QUOTED_KW_ARGmatchKW_ARGgroupsr   r   r   list_POSITIONAL_ARGS_QUOTED_OPTIONALLY_QUOTED
startswithpopr
   r   appendendswithjoinsetattr_KEYWORD_ARGSitemsget)
r   contentr$   keywordvalueZ
positionalZ	attr_nameZ
attr_valueattr_valuesZcontroller_attr_namer   r   r   r   F   s@   



"	
zEvent._parse_standard_attrc              
   C   sD   |du rdS zt |W S  ty! } z	td|| f d}~ww )z
    Parses an iso timestamp (ISOTime2Frac in the control-spec).

    :param str timestamp: timestamp to parse

    :returns: **datetime** with the parsed timestamp

    :raises: :class:`stem.ProtocolError` if timestamp is malformed
    Nz"Unable to parse timestamp (%s): %s)r   Z_parse_iso_timestamp
ValueErrorr
   r   )r   Z	timestampexcr   r   r   _iso_timestamp   s   zEvent._iso_timestampc                 C   s   d S Nr   r   r   r   r   r      s   zEvent._parsec                 C   sp   t | |}|r4tj|r|g}|D ]#}||vr3d| j ||f }d| j||| f }t|tj| qdS dS )a  
    Checks if an attribute exists in a given enumeration, logging a message if
    it isn't. Attributes can either be for a string or collection of strings

    :param str attr: name of the attribute to check
    :param stem.util.enum.Enum enum: enumeration to check against
    zevent.%s.unknown_%s.%szd%s event had an unrecognized %s (%s). Maybe a new addition to the control protocol? Full Event: '%s'N)	getattrr
   r   Z_is_strr   lowerr   Zlog_onceINFO)r   attrZ	attr_enumr7   r6   Zlog_idZunrecognized_msgr   r   r   _log_if_unrecognized   s   
	zEvent._log_if_unrecognizedN)__name__
__module____qualname____doc__r(   r1   r)   r*   r   r
   versionZVersion_VERSION_ADDEDr   r   r   r:   r   r@   r   r   r   r   r      s    
=r   c                   @   s,   e Zd ZdZdZddddZdZdd	 Zd
S )AddrMapEventa  
  Event that indicates a new address mapping.

  The ADDRMAP event was one of the first Control Protocol V1 events and was
  introduced in tor version 0.1.1.1-alpha.

  .. versionchanged:: 1.1.0
     Added the cached attribute.

  :var str hostname: address being resolved
  :var str destination: destination of the resolution, this is usually an ip,
    but could be a hostname if TrackHostExits is enabled or **NONE** if the
    resolution failed
  :var datetime expiry: expiration time of the resolution in local time
  :var str error: error code if the resolution failed
  :var datetime utc_expiry: expiration time of the resolution in UTC
  :var bool cached: **True** if the resolution will be kept until it expires,
    **False** otherwise or **None** if undefined
  )Zhostnamedestinationexpiryerror
utc_expirycached)rJ   ZEXPIRESZCACHEDrI   c                 C   s   | j dkrd | _ | jd ur0| jdkrd | _nztjj| j| _W n ty/   td|  w | jd ur>tjj| j| _| j	d ur^| j	dkrMd| _	d S | j	dkrWd| _	d S td|  d S )	Nz<error>ZNEVERz)Unable to parse date in ADDRMAP event: %sZYESTZNOFz?An ADDRMAP event's CACHED mapping can only be 'YES' or 'NO': %s)
rH   rI   r
   r   r   _parse_timestampr8   r   rK   rL   r   r   r   r   r      s&   








zAddrMapEvent._parseN)rA   rB   rC   rD   r(   r1   r*   r   r   r   r   r   rG      s    rG   c                   @   &   e Zd ZdZdZejjjZ	dd Z
dS )AuthDirNewDescEventaj  
  Event specific to directory authorities, indicating that we just received new
  descriptors. The descriptor type contained within this event is unspecified
  so the descriptor contents are left unparsed.

  The AUTHDIR_NEWDESCS event was introduced in tor version 0.1.1.10-alpha and
  removed in 0.3.2.1-alpha. (:spec:`6e887ba`)

  .. deprecated:: 1.6.0
     Tor dropped this event as of version 0.3.2.1. (:spec:`6e887ba`)

  :var stem.AuthDescriptorAction action: what is being done with the descriptor
  :var str message: explanation of why we chose this action
  :var str descriptor: content of the descriptor
  Tc                 C   sf   t | d}t|dk rtd|d dkrtd|d | _|d | _d|d	d | _d S )
N
   zsAUTHDIR_NEWDESCS events must contain lines for at least the type, action, message, descriptor, and terminating 'OK'r!   ZOKz)AUTHDIR_NEWDESCS doesn't end with an 'OK'r         )	r   r   lenr
   r   actionmessager/   
descriptor)r   linesr   r   r   r      s   



zAuthDirNewDescEvent._parseN)rA   rB   rC   rD   r   r
   rE   RequirementZEVENT_AUTHDIR_NEWDESCSrF   r   r   r   r   r   rO      
    
rO   c                   @      e Zd ZdZdZdd ZdS )BandwidthEventa"  
  Event emitted every second with the bytes sent and received by tor.

  The BW event was one of the first Control Protocol V1 events and was
  introduced in tor version 0.1.1.1-alpha.

  :var int read: bytes received by tor that second
  :var int written: bytes sent by tor that second
  )readwrittenc                 C   s^   | j std| jstd| j  r| j s!td|  t| j | _ t| j| _d S )Nz"BW event is missing its read valuez%BW event is missing its written valuezUA BW event's bytes sent and received should be a positive numeric value, received: %s)r]   r
   r   r^   isdigitINT_TYPEr   r   r   r   r     s   

zBandwidthEvent._parseN)rA   rB   rC   rD   r(   r   r   r   r   r   r\   
  s    
r\   c                	   @   s<   e Zd ZdZdZddddddd	d
dZejjj	Z
dd ZdS )BuildTimeoutSetEventa  
  Event indicating that the timeout value for a circuit has changed. This was
  first added in tor version 0.2.2.7.

  The BUILDTIMEOUT_SET event was introduced in tor version 0.2.2.7-alpha.

  :var stem.TimeoutSetType set_type: way in which the timeout is changing
  :var int total_times: circuit build times tor used to determine the timeout
  :var int timeout: circuit timeout value in milliseconds
  :var int xm: Pareto parameter Xm in milliseconds
  :var float alpha: Pareto parameter alpha
  :var float quantile: CDF quantile cutoff point
  :var float timeout_rate: ratio of circuits that have time out
  :var int close_timeout: duration to keep measurement circuits in milliseconds
  :var float close_rate: ratio of measurement circuits that are closed
  )set_typetotal_timestimeoutxmalphaquantiletimeout_rateclose_timeout
close_rate)ZTOTAL_TIMESZ
TIMEOUT_MSZXMZALPHAZCUTOFF_QUANTILEZTIMEOUT_RATEZCLOSE_MSZ
CLOSE_RATEc              	   C   s   dD ]&}t | |}|d ur(z
t| |t| W q ty'   td|| f w qdD ]&}t | |}|d urQz
t| |t| W q+ tyP   td|| f w q+| dtj d S )N)rc   rd   re   ri   z5The %s of a BUILDTIMEOUT_SET should be an integer: %s)rf   rg   rh   rj   z2The %s of a BUILDTIMEOUT_SET should be a float: %srb   )	r<   r0   intr8   r
   r   floatr@   ZTimeoutSetType)r   ZparamZparam_valuer   r   r   r   B  s&   

zBuildTimeoutSetEvent._parseN)rA   rB   rC   rD   r(   r1   r
   rE   rY   ZEVENT_BUILDTIMEOUT_SETrF   r   r   r   r   r   ra   #  s    

ra   c                
   @   sL   e Zd ZdZdZddddddd	d
dd	Zdd Zdd Zdd Zdd Z	dS )CircuitEventa  
  Event that indicates that a circuit has changed.

  The fingerprint or nickname values in our 'path' may be **None** if the
  VERBOSE_NAMES feature isn't enabled. The option was first introduced in tor
  version 0.1.2.2, and on by default after 0.2.2.1.

  The CIRC event was one of the first Control Protocol V1 events and was
  introduced in tor version 0.1.1.1-alpha.

  .. versionchanged:: 1.4.0
     Added the socks_username and socks_password attributes which is used for
     `stream isolation
     <https://gitweb.torproject.org/torspec.git/tree/proposals/171-separate-streams.txt>`_.

  :var str id: circuit identifier
  :var stem.CircStatus status: reported status for the circuit
  :var tuple path: relays involved in the circuit, these are
    **(fingerprint, nickname)** tuples
  :var tuple build_flags: :data:`~stem.CircBuildFlag` attributes
    governing how the circuit is built
  :var stem.CircPurpose purpose: purpose that the circuit is intended for
  :var stem.HiddenServiceState hs_state: status if this is a hidden service circuit
  :var str rend_query: circuit's rendezvous-point if this is hidden service related
  :var datetime created: time when the circuit was created or cannibalized
  :var stem.CircClosureReason reason: reason for the circuit to be closed
  :var stem.CircClosureReason remote_reason: remote side's reason for the circuit to be closed
  :var str socks_username: username for using this circuit
  :var str socks_password: password for using this circuit
  )idstatuspathbuild_flagspurposehs_state
rend_querycreatedreasonremote_reasonZsocks_usernameZsocks_password)	BUILD_FLAGSPURPOSEHS_STATE
REND_QUERYTIME_CREATEDREASONREMOTE_REASONZSOCKS_USERNAMEZSOCKS_PASSWORDc                 C   s   t tj| j| _| | j| _| jd urt | jd| _t	
| js/td| j| f | dtj | dtj | dtj | dtj | dtj | dtj d S )	N,HCircuit IDs must be one to sixteen alphanumeric characters, got '%s': %sro   rq   rr   rs   rv   rw   )tupler
   control_parse_circ_pathrp   r:   ru   rq   r   r   is_valid_circuit_idrn   r   r@   Z
CircStatusCircBuildFlagCircPurposeHiddenServiceStateZCircClosureReasonr   r   r   r   r        
zCircuitEvent._parsec                 C   sF   t |tsdS t| d}t|d}||kr|||S |t| t|S )NFrn   )
isinstancerm   r<   hash)r   othermethodZmy_idZtheir_idr   r   r   _compare  s
   


$zCircuitEvent._comparec                 C      |  |dd S )Nc                 S   s   | |kS r;   r   sor   r   r   <lambda>      z%CircuitEvent.__gt__.<locals>.<lambda>r   r   r   r   r   r   __gt__     zCircuitEvent.__gt__c                 C   r   )Nc                 S   s   | |kS r;   r   r   r   r   r   r     r   z%CircuitEvent.__ge__.<locals>.<lambda>r   r   r   r   r   __ge__  r   zCircuitEvent.__ge__N)
rA   rB   rC   rD   r(   r1   r   r   r   r   r   r   r   r   rm   Z  s"    rm   c                   @   s:   e Zd ZdZdZddddddd	d
Zejjj	Z
dd ZdS )CircMinorEventa  
  Event providing information about minor changes in our circuits. This was
  first added in tor version 0.2.3.11.

  The CIRC_MINOR event was introduced in tor version 0.2.3.11-alpha.

  :var str id: circuit identifier
  :var stem.CircEvent event: type of change in the circuit
  :var tuple path: relays involved in the circuit, these are
    **(fingerprint, nickname)** tuples
  :var tuple build_flags: :data:`~stem.CircBuildFlag` attributes
    governing how the circuit is built
  :var stem.CircPurpose purpose: purpose that the circuit is intended for
  :var stem.HiddenServiceState hs_state: status if this is a hidden service circuit
  :var str rend_query: circuit's rendezvous-point if this is hidden service related
  :var datetime created: time when the circuit was created or cannibalized
  :var stem.CircPurpose old_purpose: prior purpose for the circuit
  :var stem.HiddenServiceState old_hs_state: prior status as a hidden service circuit
  )rn   eventrp   rq   rr   rs   rt   ru   old_purposeold_hs_state)rx   ry   rz   r{   r|   ZOLD_PURPOSEZOLD_HS_STATEc                 C   s   t tj| j| _| | j| _| jd urt | jd| _t	
| js/td| j| f | dtj | dtj | dtj | dtj | dtj | dtj d S )	Nr   r   r   rq   rr   rs   r   r   )r   r
   r   r   rp   r:   ru   rq   r   r   r   rn   r   r@   Z	CircEventr   r   r   r   r   r   r   r     r   zCircMinorEvent._parseN)rA   rB   rC   rD   r(   r1   r
   rE   rY   ZEVENT_CIRC_MINORrF   r   r   r   r   r   r     s    
	r   c                   @   s.   e Zd ZdZddddZejjjZ	dd Z
dS )	ClientsSeenEventa  
  Periodic event on bridge relays that provides a summary of our users.

  The CLIENTS_SEEN event was introduced in tor version 0.2.1.10-alpha.

  :var datetime start_time: time in UTC that we started collecting these stats
  :var dict locales: mapping of country codes to a rounded count for the number of users
  :var dict ip_versions: mapping of ip protocols to a rounded count for the number of users
  
start_timelocalesip_versions)ZTimeStartedZCountrySummaryZ
IPVersionsc                 C   s@  | j d urtjj| j | _ | jd urci }| jdD ]D}d|vr(td|  |dd\}}t|dkr?td|| f |	 sLtd|| f ||v rYtd|| f t
|||< q|| _| jd uri }| jdD ](}d|vr}td	|  |dd\}}|	 std
|| f t
|||< qp|| _d S d S )Nr   =zhThe CLIENTS_SEEN's CountrySummary should be a comma separated listing of '<locale>=<count>' mappings: %sr   rR   z4Locales should be a two character code, got '%s': %sz%Locale count was non-numeric (%s): %sz1CountrySummary had multiple mappings for '%s': %szfThe CLIENTS_SEEN's IPVersions should be a comma separated listing of '<protocol>=<count>' mappings: %sz*IP protocol count was non-numeric (%s): %s)r   r
   r   r   rM   r   r   r   rT   r_   rk   r   )r   Zlocale_to_countentrylocalecountZprotocol_to_countZprotocolr   r   r   r     s6   



zClientsSeenEvent._parseN)rA   rB   rC   rD   r1   r
   rE   rY   ZEVENT_CLIENTS_SEENrF   r   r   r   r   r   r     s    
r   c                   @   rN   )ConfChangedEventas  
  Event that indicates that our configuration changed, either in response to a
  SETCONF or RELOAD signal.

  The CONF_CHANGED event was introduced in tor version 0.2.3.3-alpha.

  .. deprecated:: 1.7.0
     Deprecated the *config* attribute. Some tor configuration options (like
     ExitPolicy) can have multiple values, so a simple 'str => str' mapping
     meant that we only provided the last.

  .. versionchanged:: 1.7.0
     Added the changed and unset attributes.

  :var dict changed: mapping of configuration options to a list of their new
    values
  :var list unset: configuration options that have been unset
  Tc                 C   s~   i | _ g | _i | _t|  dd D ])}d|v r,|dd\}}| j |g | n|d }}| j| || j|< qd S )Nr   r!   r   )ZchangedZunsetZconfigr   
splitlinesr   
setdefaultr-   )r   linekeyr6   r   r   r   r   /  s   
zConfChangedEvent._parseN)rA   rB   rC   rD   r   r
   rE   rY   ZEVENT_CONF_CHANGEDrF   r   r   r   r   r   r     s
    
r   c                   @   s   e Zd ZdZejjjZdS )DescChangedEventz
  Event that indicates that our descriptor has changed.

  The DESCCHANGED event was introduced in tor version 0.1.2.2-alpha.
  N)	rA   rB   rC   rD   r
   rE   rY   ZEVENT_DESCCHANGEDrF   r   r   r   r   r   H  s    r   c                   @   &   e Zd ZdZejjjZdZ	dd Z
dS )
GuardEventaC  
  Event that indicates that our guard relays have changed. The 'endpoint' could
  be either a...

  * fingerprint
  * 'fingerprint=nickname' pair

  The derived 'endpoint_*' attributes are generally more useful.

  The GUARD event was introduced in tor version 0.1.2.5-alpha.

  :var stem.GuardType guard_type: purpose the guard relay is for
  :var str endpoint: relay that the event concerns
  :var str endpoint_fingerprint: endpoint's finterprint
  :var str endpoint_nickname: endpoint's nickname if it was provided
  :var stem.GuardStatus status: status of the guard relay
  )
guard_typeendpointro   c                 C   sf   d | _ d | _ztj| j\| _ | _W n tjy"   td|  w | dtj | dtj	 d S )Nz/GUARD's endpoint doesn't match a ServerSpec: %sr   ro   )
endpoint_fingerprintendpoint_nicknamer
   r   _parse_circ_entryr   r   r@   Z	GuardTypeZGuardStatusr   r   r   r   r   h  s   zGuardEvent._parseN)rA   rB   rC   rD   r
   rE   rY   ZEVENT_GUARDrF   r(   r   r   r   r   r   r   R  s
    
r   c                   @   s2   e Zd ZdZejjjZdZ	ddddZ
dd Zd	S )
HSDescEventa'  
  Event triggered when we fetch a hidden service descriptor that currently isn't in our cache.

  The HS_DESC event was introduced in tor version 0.2.5.2-alpha.

  .. versionadded:: 1.2.0

  .. versionchanged:: 1.3.0
     Added the reason attribute.

  .. versionchanged:: 1.5.0
     Added the replica attribute.

  .. versionchanged:: 1.7.0
     Added the index attribute.

  :var stem.HSDescAction action: what is happening with the descriptor
  :var str address: hidden service address
  :var stem.HSAuth authentication: service's authentication method
  :var str directory: hidden service directory servicing the request
  :var str directory_fingerprint: hidden service directory's finterprint
  :var str directory_nickname: hidden service directory's nickname if it was provided
  :var str descriptor_id: descriptor identifier
  :var stem.HSDescReason reason: reason the descriptor failed to be fetched
  :var int replica: replica number the descriptor involves
  :var str index: computed index of the HSDir the descriptor was uploaded to or fetched from
  )rU   addressauthentication	directorydescriptor_idrv   replicaindex)r}   ZREPLICAZHSDIR_INDEXc                 C   s   d | _ d | _| jdkr(ztj| j\| _ | _W n tjy'   td|  w | jd urB| j s<td| j| f t	| j| _| 
dtj | 
dtj d S )NUNKNOWNz2HS_DESC's directory doesn't match a ServerSpec: %sz6HS_DESC event got a non-numeric replica count (%s): %srU   r   )directory_fingerprintdirectory_nicknamer   r
   r   r   r   r   r_   rk   r@   ZHSDescActionZHSAuthr   r   r   r   r     s   


zHSDescEvent._parseN)rA   rB   rC   rD   r
   rE   rY   ZEVENT_HS_DESCrF   r(   r1   r   r   r   r   r   r   v  s    
r   c                   @   r   )HSDescContentEventaQ  
  Provides the content of hidden service descriptors we fetch.

  The HS_DESC_CONTENT event was introduced in tor version 0.2.7.1-alpha.

  .. versionadded:: 1.4.0

  :var str address: hidden service address
  :var str descriptor_id: descriptor identifier
  :var str directory: hidden service directory servicing the request
  :var str directory_fingerprint: hidden service directory's finterprint
  :var str directory_nickname: hidden service directory's nickname if it was provided
  :var stem.descriptor.hidden_service.HiddenServiceDescriptorV2 descriptor: descriptor that was retrieved
  )r   r   r   c                 C   s   | j dkrd | _ d | _d | _ztj| j\| _| _W n tjy*   td|  w t	d
t|  dd }d | _|rQttjjt|d | _d S d S )Nr   z:HS_DESC_CONTENT's directory doesn't match a ServerSpec: %srP   r   r!   r   )r   r   r   r
   r   r   r   r   r   	_to_bytesr/   r   r   rW   r'   Zhidden_service_parse_fileioBytesIO)r   Zdesc_contentr   r   r   r     s   
 "zHSDescContentEvent._parseN)rA   rB   rC   rD   r
   rE   rY   ZEVENT_HS_DESC_CONTENTrF   r(   r   r   r   r   r   r     s
    
r   c                   @   r[   )LogEventam  
  Tor logging event. These are the most visible kind of event since, by
  default, tor logs at the NOTICE :data:`~stem.Runlevel` to stdout.

  The logging events were some of the first Control Protocol V1 events
  and were introduced in tor version 0.1.1.1-alpha.

  :var stem.Runlevel runlevel: runlevel of the logged message
  :var str message: logged message
  Tc                 C   s<   | j | _| dtj t| t| jd d  d| _d S )Nrunlevelr   
OK)	r   r   r@   r
   Runlevelr   rT   rstriprV   r   r   r   r   r     s   &zLogEvent._parseN)rA   rB   rC   rD   r   r   r   r   r   r   r     s    r   c                   @   rN   )NetworkStatusEventa  
  Event for when our copy of the consensus has changed. This was introduced in
  tor version 0.1.2.3.

  The NS event was introduced in tor version 0.1.2.3-alpha.

  :var list desc: :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV3` for the changed descriptors
  Tc                 C   sD   t | dd}ttjjjt	t
|dtjjjd| _d S )NzNS
r   FZentry_class)r   lstripr   r'   r
   rW   router_status_entryr   r   r   r   r   RouterStatusEntryV3desc)r   r4   r   r   r   r     s   
zNetworkStatusEvent._parseN)rA   rB   rC   rD   r   r
   rE   rY   ZEVENT_NSrF   r   r   r   r   r   r     s
    	
r   c                   @   s   e Zd ZdZejjjZdZ	dS )NetworkLivenessEventa  
  Event for when the network becomes reachable or unreachable.

  The NETWORK_LIVENESS event was introduced in tor version 0.2.7.2-alpha.

  .. versionadded:: 1.5.0

  :var str status: status of the network ('UP', 'DOWN', or possibly other
    statuses in the future)
  )ro   N)
rA   rB   rC   rD   r
   rE   rY   ZEVENT_NETWORK_LIVENESSrF   r(   r   r   r   r   r     s    
r   c                   @   rN   )NewConsensusEventa9  
  Event for when we have a new consensus. This is similar to
  :class:`~stem.response.events.NetworkStatusEvent`, except that it contains
  the whole consensus so anything not listed is implicitly no longer
  recommended.

  The NEWCONSENSUS event was introduced in tor version 0.2.1.13-alpha.

  .. versionchanged:: 1.6.0
     Added the consensus_content attribute.

  .. deprecated:: 1.6.0
     In Stem 2.0 we'll remove the desc attribute, so this event only provides
     the unparsed consensus. Callers can then parse it if they'd like. To drop
     parsing before then you can set...

     ::

       stem.response.events.PARSE_NEWCONSENSUS_EVENTS = False

  :var str consensus_content: consensus content
  :var list desc: :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV3` for the changed descriptors
  Tc                 C   sV   t | dd| _tr&ttjjj	t
t| jdtjjjd| _d S d | _d S )NzNEWCONSENSUS
r   Fr   )r   r   r   Zconsensus_contentPARSE_NEWCONSENSUS_EVENTSr'   r
   rW   r   r   r   r   r   r   r   r   r   r   r   r   r   3  s   

zNewConsensusEvent._parseN)rA   rB   rC   rD   r   r
   rE   rY   ZEVENT_NEWCONSENSUSrF   r   r   r   r   r   r     s
    
r   c                   @   s   e Zd ZdZdd ZdS )NewDescEventa  
  Event that indicates that a new descriptor is available.

  The fingerprint or nickname values in our 'relays' may be **None** if the
  VERBOSE_NAMES feature isn't enabled. The option was first introduced in tor
  version 0.1.2.2, and on by default after 0.2.2.1.

  The NEWDESC event was one of the first Control Protocol V1 events and was
  introduced in tor version 0.1.1.1-alpha.

  :var tuple relays: **(fingerprint, nickname)** tuples for the relays with
    new descriptors
  c                 C   s(   t dd t|  dd  D | _d S )Nc                 S   s   g | ]}t j|qS r   )r
   r   r   ).0r   r   r   r   
<listcomp>S  s    z'NewDescEvent._parse.<locals>.<listcomp>r   )r   r   r   Zrelaysr   r   r   r   r   R  s   (zNewDescEvent._parseN)rA   rB   rC   rD   r   r   r   r   r   r   C  s    r   c                   @   s(   e Zd ZdZdZddddZdd Zd	S )
ORConnEventa  
  Event that indicates a change in a relay connection. The 'endpoint' could be
  any of several things including a...

  * fingerprint
  * nickname
  * 'fingerprint=nickname' pair
  * address:port

  The derived 'endpoint_*' attributes are generally more useful.

  The ORCONN event was one of the first Control Protocol V1 events and was
  introduced in tor version 0.1.1.1-alpha. Its id attribute was added in
  version 0.2.5.2-alpha.

  .. versionchanged:: 1.2.0
     Added the id attribute.

  :var str id: connection identifier
  :var str endpoint: relay that the event concerns
  :var str endpoint_fingerprint: endpoint's finterprint if it was provided
  :var str endpoint_nickname: endpoint's nickname if it was provided
  :var str endpoint_address: endpoint's address if it was provided
  :var int endpoint_port: endpoint's port if it was provided
  :var stem.ORStatus status: state of the connection
  :var stem.ORClosureReason reason: reason for the connection to be closed
  :var int circ_count: number of established and pending circuits
  )r   ro   rv   
circ_countrn   )r}   ZNCIRCSIDc                 C   s  d | _ d | _d | _d | _ztj| j\| _ | _W n3 tjyL   d| jvr-td|  | j	dd\}}t
|sBtd|  || _t|| _Y nw | jd urg| j satd| j| f t| j| _| jrzt| jsztd| j| f | dtj | dtj d S )	N:z9ORCONN endpoint is neither a relay nor 'address:port': %sr   z0ORCONN's endpoint location's port is invalid: %sz5ORCONN event got a non-numeric circuit count (%s): %sKConnection IDs must be one to sixteen alphanumeric characters, got '%s': %sro   rv   )r   r   Zendpoint_addressZendpoint_portr
   r   r   r   r   rsplitr   is_valid_portrk   r   r_   rn   r   is_valid_connection_idr@   ZORStatusZORClosureReasonr   r   portr   r   r   r   {  s0   



zORConnEvent._parseNrA   rB   rC   rD   r(   r1   r   r   r   r   r   r   V  s    r   c                   @   rN   )SignalEventab  
  Event that indicates that tor has received and acted upon a signal being sent
  to the process. As of tor version 0.2.4.6 the only signals conveyed by this
  event are...

  * RELOAD
  * DUMP
  * DEBUG
  * NEWNYM
  * CLEARDNSCACHE

  The SIGNAL event was introduced in tor version 0.2.3.1-alpha.

  :var stem.Signal signal: signal that tor received
  )signalc                 C   s2   t jjt jjt jjt jjt jjf}| d| d S )Nr   )r
   ZSignalZRELOADZDUMPDEBUGZNEWNYMZCLEARDNSCACHEr@   )r   Zexpected_signalsr   r   r   r     s   zSignalEvent._parseN)rA   rB   rC   rD   r(   r
   rE   rY   ZEVENT_SIGNALrF   r   r   r   r   r   r     rZ   r   c                   @   rN   )StatusEventaG  
  Notification of a change in tor's state. These are generally triggered for
  the same sort of things as log messages of the NOTICE level or higher.
  However, unlike :class:`~stem.response.events.LogEvent` these contain well
  formed data.

  The STATUS_GENERAL, STATUS_CLIENT, STATUS_SERVER events were introduced
  in tor version 0.1.2.3-alpha.

  :var stem.StatusType status_type: category of the status event
  :var stem.Runlevel runlevel: runlevel of the logged message
  :var str action: activity that caused this message
  :var dict arguments: attributes about the event
  )r   rU   c                 C   sj   | j dkrtjj| _n| j dkrtjj| _n| j dkr!tjj| _ntd| j  | j| _	| 
dtj d S )NSTATUS_GENERALSTATUS_CLIENTSTATUS_SERVERzzBUG: Unrecognized status type (%s), likely an EVENT_TYPE_TO_CLASS addition without revising how 'status_type' is assigned.r   )r   r
   Z
StatusTypeZGENERALZstatus_typeZCLIENTZSERVERr8   r   Z	argumentsr@   r   r   r   r   r   r     s   


zStatusEvent._parseN)rA   rB   rC   rD   r(   r
   rE   rY   ZEVENT_STATUSrF   r   r   r   r   r   r     
    
r   c                   @   s,   e Zd ZdZdZddddddZd	d
 ZdS )StreamEventa  
  Event that indicates that a stream has changed.

  The STREAM event was one of the first Control Protocol V1 events and was
  introduced in tor version 0.1.1.1-alpha.

  :var str id: stream identifier
  :var stem.StreamStatus status: reported status for the stream
  :var str circ_id: circuit that the stream is attached to, this is **None** of
    the stream is unattached
  :var str target: destination of the stream
  :var str target_address: destination address (ip, hostname, or '(Tor_internal)')
  :var int target_port: destination port
  :var stem.StreamClosureReason reason: reason for the stream to be closed
  :var stem.StreamClosureReason remote_reason: remote side's reason for the stream to be closed
  :var stem.StreamSource source: origin of the REMAP request
  :var str source_addr: requester of the connection
  :var str source_address: requester address (ip or hostname)
  :var int source_port: requester port
  :var stem.StreamPurpose purpose: purpose for the stream
  )rn   ro   circ_idtargetrv   rw   sourcesource_addrrr   )r}   r~   ZSOURCEZSOURCE_ADDRry   c                 C   s  | j d u rtd|  d| j vrtd|  | j dd\}}tj|dds/td|  || _t|| _| j	d u rCd | _
d | _n+d| j	vrOtd|  | j	dd\}}tj|ddsftd	|  || _
t|| _| jd
krvd | _| dtj | dtj | dtj d S )Nz%STREAM event didn't have a target: %sr   z6Target location must be of the form 'address:port': %sr   T)Z
allow_zeroz%Target location's port is invalid: %sz6Source location must be of the form 'address:port': %sz%Source location's port is invalid: %s0rv   rw   rr   )r   r
   r   r   r   r   Ztarget_addressrk   Ztarget_portr   Zsource_addressZsource_portr   r@   ZStreamClosureReasonZStreamPurposer   r   r   r   r     s0   






zStreamEvent._parseNr   r   r   r   r   r     s    r   c                   @   rN   )StreamBwEventa  
  Event (emitted approximately every second) with the bytes sent and received
  by the application since the last such event on this stream.

  The STREAM_BW event was introduced in tor version 0.1.2.8-beta.

  .. versionchanged:: 1.6.0
     Added the time attribute.

  :var str id: stream identifier
  :var int written: bytes sent by the application
  :var int read: bytes received by the application
  :var datetime time: time when the measurement was recorded
  )rn   r^   r]   timec                 C   s   t | jstd| j| f | jstd| js td| j r*| j s1td|  t| j| _t| j| _| 	| j
| _
d S )NzGStream IDs must be one to sixteen alphanumeric characters, got '%s': %sz,STREAM_BW event is missing its written valuez)STREAM_BW event is missing its read valuez\A STREAM_BW event's bytes sent and received should be a positive numeric value, received: %s)r   Zis_valid_stream_idrn   r
   r   r^   r]   r_   r`   r:   r   r   r   r   r   r   @  s   

zStreamBwEvent._parseN)rA   rB   rC   rD   r(   r
   rE   rY   ZEVENT_STREAM_BWrF   r   r   r   r   r   r   -  r   r   c                   @   rN   )TransportLaunchedEventa  
  Event triggered when a pluggable transport is launched.

  The TRANSPORT_LAUNCHED event was introduced in tor version 0.2.5.0-alpha.

  .. versionadded:: 1.1.0

  :var str type: 'server' or 'client'
  :var str name: name of the pluggable transport
  :var str address: IPv4 or IPv6 address where the transport is listening for
    connections
  :var int port: port where the transport is listening for connections
  )r   namer   r   c                 C   sh   | j dvrtd|  t| jst| jstd|  t| js,td|  t	| j| _d S )N)ZserverZclientz8Transport type should either be 'server' or 'client': %sz8Transport address isn't a valid IPv4 or IPv6 address: %szTransport port is invalid: %s)
r   r
   r   r   Zis_valid_ipv4_addressr   Zis_valid_ipv6_addressr   r   rk   r   r   r   r   r   a  s   

zTransportLaunchedEvent._parseN)rA   rB   rC   rD   r(   r
   rE   rY   ZEVENT_TRANSPORT_LAUNCHEDrF   r   r   r   r   r   r   O  s
    
r   c                   @   s0   e Zd ZdZdddddZejjjZ	dd Z
d	S )
ConnectionBandwidthEventa  
  Event emitted every second with the bytes sent and received by tor on a
  per-connection basis.

  The CONN_BW event was introduced in tor version 0.2.5.2-alpha.

  .. versionadded:: 1.2.0

  .. versionchanged:: 1.6.0
     Renamed 'type' attribute to 'conn_type' so it wouldn't be override parent
     class attribute with the same name.

  :var str id: connection identifier
  :var stem.ConnectionType conn_type: connection type
  :var int read: bytes received by tor that second
  :var int written: bytes sent by tor that second
  rn   	conn_typer]   r^   )r   ZTYPEREADWRITTENc                 C   s   | j std| jstd| jstd| js td| j r*| j s1td|  t| j sAtd| j | f t	| j| _t	| j| _| 
dtj d S )NzCONN_BW event is missing its idz,CONN_BW event is missing its connection typez'CONN_BW event is missing its read valuez*CONN_BW event is missing its written valuezZA CONN_BW event's bytes sent and received should be a positive numeric value, received: %sr   r   )rn   r
   r   r   r]   r^   r_   r   r   r`   r@   ZConnectionTyper   r   r   r   r     s   



zConnectionBandwidthEvent._parseN)rA   rB   rC   rD   r1   r
   rE   rY   ZEVENT_CONN_BWrF   r   r   r   r   r   r   o  s    
r   c                	   @   s8   e Zd ZdZdddddddd	d
ZejjjZ	dd Z
dS )CircuitBandwidthEventac  
  Event emitted every second with the bytes sent and received by tor on a
  per-circuit basis.

  The CIRC_BW event was introduced in tor version 0.2.5.2-alpha.

  .. versionadded:: 1.2.0

  .. versionchanged:: 1.6.0
     Added the time attribute.

  .. versionchanged:: 1.7.0
     Added the delivered_read, delivered_written, overhead_read, and
     overhead_written attributes.

  :var str id: circuit identifier
  :var int read: bytes received by tor that second
  :var int written: bytes sent by tor that second
  :var int delivered_read: user payload received by tor that second
  :var int delivered_written: user payload sent by tor that second
  :var int overhead_read: padding so read cells will have a fixed length
  :var int overhead_written: padding so written cells will have a fixed length
  :var datetime time: time when the measurement was recorded
  rn   r]   r^   delivered_readdelivered_writtenoverhead_readoverhead_writtenr   )r   r   r   ZDELIVERED_READZDELIVERED_WRITTENZOVERHEAD_READZOVERHEAD_WRITTENZTIMEc                 C   s2  | j std| jstd| jstd| j s$td|  | j s0td|  | jr?| j s?td|  | jrN| j sNtd|  | jr]| j s]td|  | j	rl| j	 sltd	|  t
| j s|td
| j | f | | j| _dD ]}t| |}|rt| |t| qd S )NzCIRC_BW event is missing its idz'CIRC_BW event is missing its read valuez*CIRC_BW event is missing its written valuezQA CIRC_BW event's bytes received should be a positive numeric value, received: %szMA CIRC_BW event's bytes sent should be a positive numeric value, received: %sz[A CIRC_BW event's delivered bytes received should be a positive numeric value, received: %szWA CIRC_BW event's delivered bytes sent should be a positive numeric value, received: %szZA CIRC_BW event's overhead bytes received should be a positive numeric value, received: %szVA CIRC_BW event's overhead bytes sent should be a positive numeric value, received: %sr   )r]   r^   r   r   r   r   )rn   r
   r   r]   r^   r_   r   r   r   r   r   r   r:   r   r<   r0   r`   )r   r?   r6   r   r   r   r     s6   





zCircuitBandwidthEvent._parseN)rA   rB   rC   rD   r1   r
   rE   rY   ZEVENT_CIRC_BWrF   r   r   r   r   r   r     s    
r   c                   @   s>   e Zd ZdZdddddddd	d
dddZejjjZ	dd Z
dS )CellStatsEventa$  
  Event emitted every second with a count of the number of cells types broken
  down by the circuit. **These events are only emitted if TestingTorNetwork is
  set.**

  The CELL_STATS event was introduced in tor version 0.2.5.2-alpha.

  .. versionadded:: 1.2.0

  :var str id: circuit identifier
  :var str inbound_queue: inbound queue identifier
  :var str inbound_connection: inbound connection identifier
  :var dict inbound_added: mapping of added inbound cell types to their count
  :var dict inbound_removed: mapping of removed inbound cell types to their count
  :var dict inbound_time: mapping of inbound cell types to the time they took to write in milliseconds
  :var str outbound_queue: outbound queue identifier
  :var str outbound_connection: outbound connection identifier
  :var dict outbound_added: mapping of added outbound cell types to their count
  :var dict outbound_removed: mapping of removed outbound cell types to their count
  :var dict outbound_time: mapping of outbound cell types to the time they took to write in milliseconds
  rn   inbound_queueinbound_connectioninbound_addedinbound_removedinbound_timeoutbound_queueoutbound_connectionoutbound_addedoutbound_removedoutbound_time)r   ZInboundQueueZInboundConnZInboundAddedZInboundRemovedZInboundTimeZOutboundQueueZOutboundConnZOutboundAddedZOutboundRemovedZOutboundTimec                 C   s
  | j rt| j std| j | f | jr&t| js&td| j| f | jr9t| js9td| j| f | jrLt| jsLtd| j| f | j	r_t| j	s_td| j	| f t
| j| _t
| j| _t
| j| _t
| j| _t
| j| _t
| j| _d S )Nr   zFQueue IDs must be one to sixteen alphanumeric characters, got '%s': %sr   )rn   r   r   r
   r   r   r   r   r   r   _parse_cell_type_mappingr   r   r   r   r  r  r   r   r   r   r     s    zCellStatsEvent._parseN)rA   rB   rC   rD   r1   r
   rE   rY   ZEVENT_CELL_STATSrF   r   r   r   r   r   r     s     
r   c                   @   s4   e Zd ZdZdZdddddZejjj	Z
dd	 Zd
S )TokenBucketEmptyEventa/  
  Event emitted when refilling an empty token bucket. **These events are only
  emitted if TestingTorNetwork is set.**

  The TB_EMPTY event was introduced in tor version 0.2.5.2-alpha.

  .. versionadded:: 1.2.0

  :var stem.TokenBucket bucket: bucket being refilled
  :var str id: connection identifier
  :var int read: time in milliseconds since the read bucket was last refilled
  :var int written: time in milliseconds since the write bucket was last refilled
  :var int last_refill: time in milliseconds the bucket has been empty since last refilled
  )bucketrn   r]   r^   last_refill)r   r   r   ZLASTc                 C   s   | j rt| j std| j | f | j std|  | j s+td|  | j s7td|  t	| j| _t	| j| _t	| j| _| 
dtj d S )Nr   zHA TB_EMPTY's READ value should be a positive numeric value, received: %szKA TB_EMPTY's WRITTEN value should be a positive numeric value, received: %szHA TB_EMPTY's LAST value should be a positive numeric value, received: %sr  )rn   r   r   r
   r   r]   r_   r^   r  rk   r@   ZTokenBucketr   r   r   r   r   :  s   


zTokenBucketEmptyEvent._parseN)rA   rB   rC   rD   r(   r1   r
   rE   rY   ZEVENT_TB_EMPTYrF   r   r   r   r   r   r     s    
r  c                 C   s   | du rdS i }|  dD ]8}d|vrtd|| f |dd\}}t|s2td|| f | s?td|| f t|||< q|S )a  
  Parses a mapping of the form...

    key1:value1,key2:value2...

  ... in which keys are strings and values are integers.

  :param str mapping: value to be parsed

  :returns: dict of **str => int** mappings

  :rasies: **stem.ProtocolError** if unable to parse the mapping
  Nr   r   zAMappings are expected to be of the form 'key:value', got '%s': %sr   z(Key had invalid characters, got '%s': %sz,Values should just be integers, got '%s': %s)r   r
   r   r   	CELL_TYPEr$   r_   rk   )mappingresultsr   r   r6   r   r   r   r  K  s   
r  ZADDRMAPZAUTHDIR_NEWDESCSZBUILDTIMEOUT_SETZBWZ
CELL_STATSZCIRCZCIRC_BWZ
CIRC_MINORZCLIENTS_SEENZCONF_CHANGEDZCONN_BWr   ZDESCCHANGEDZERRZGUARDZHS_DESCZHS_DESC_CONTENTr>   ZNETWORK_LIVENESSZNEWCONSENSUSZNEWDESCZNOTICEZNSZORCONNZSIGNALr   r   r   ZSTREAMZ	STREAM_BWZTB_EMPTYZTRANSPORT_LAUNCHEDZWARNZSTATUS_SEVER)7r   rer
   Zstem.controlZ#stem.descriptor.router_status_entryZstem.prereqZstem.responseZ	stem.utilZstem.versionr   r   r   r   compiler%   r#   r  r   ZprereqZis_python_3rk   Zlongr`   r   r   r   rG   rO   r\   ra   rm   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r   r   r   r   r   <module>   s   


 6$7P3;0
$6),G!'H" 0F;+$	
 !$
