o
    bqZ                     @   s  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 d dl	m
Z
mZmZ d dlmZmZ d dlmZmZ d dlmZ d dlmZ d dlmZ d d	lmZmZmZmZmZmZ d d
l m!Z!m"Z"m#Z# G dd dZ$G dd de$Z%G dd de$Z&G dd dZ'G dd dZ(dd Z)d/ddZ*dd Z+dd Z,G dd dZ-dd  Z.d!d" Z/G d#d$ d$Z0G d%d& d&ej1e0Z2d'd( Z3d)d* Z4d+d, Z5d-d. Z6dS )0    N)
attrgetter)	copyrightloggerplugin)reactorsservice)NoSuchReactorinstallReactor)defer)_ISupportsExitSignalCapturing)sob)failureloglogfileruntimeusageutil)namedAnynamedModulequalc                   @   s    e Zd ZdZdd Zdd ZdS )_BasicProfilerz
    @ivar saveStats: if C{True}, save the stats information instead of the
        human readable format
    @type saveStats: C{bool}

    @ivar profileOutput: the name of the file use to print profile data.
    @type profileOutput: C{str}
    c                 C   s   || _ || _d S N)profileOutput	saveStats)selfr   r    r   9/usr/lib/python3/dist-packages/twisted/application/app.py__init__%   s   
z_BasicProfiler.__init__c                 C   s    d| d| }|d7 }t |)z
        Helper method to report an import error with a profile module. This
        has to be explicit because some of these modules are removed by
        distributions due to them being non-free.
        zFailed to import module : z
This is most likely caused by your operating system not including
the module due to it being non-free. Either do not use the option
--profile, or install the module; your operating system vendor
may provide it in a separate package.
)
SystemExit)r   moduleesr   r   r   _reportImportError)   s   z!_BasicProfiler._reportImportErrorN)__name__
__module____qualname____doc__r   r#   r   r   r   r   r      s    	r   c                   @      e Zd ZdZdd ZdS )ProfileRunnerz1
    Runner for the standard profile module.
    c              
   C   s   zddl }W n ty } z| d| W Y d}~nd}~ww | }||j | jr4|| j dS t	j
t| jd}t	_
z|  W |t	j
t	_
}|  dS |t	j
t	_
}|  w )z:
        Run reactor under the standard profiler.
        r   Nprofilea)r*   ImportErrorr#   Profileruncallrunr   
dump_statsr   sysstdoutopenprint_statsclose)r   reactorr*   r!   ptmpr   r   r   r/   >   s"   

zProfileRunner.runNr$   r%   r&   r'   r/   r   r   r   r   r)   9       r)   c                   @   r(   )CProfileRunnerz)
    Runner for the cProfile module.
    c              
   C   s   z
ddl }ddl}W n ty" } z| d| W Y d}~nd}~ww | }||j | jr8|| j	 dS t
| j	d}|j||d}|  |d |  W d   dS 1 s^w   Y  dS )z:
        Run reactor under the cProfile profiler.
        r   NcProfilew)stream)r<   pstatsr,   r#   r-   r.   r/   r   r0   r   r3   Stats
strip_dirs
sort_statsr4   )r   r6   r<   r@   r!   r7   r>   r"   r   r   r   r/   Y   s"   

"zCProfileRunner.runNr9   r   r   r   r   r;   T   r:   r;   c                   @   s"   e Zd ZdZeedZdd ZdS )AppProfilerz
    Class which selects a specific profile runner based on configuration
    options.

    @ivar profiler: the name of the selected profiler.
    @type profiler: C{str}
    )r*   cprofilec                 C   sd   | dd}| dd }| dd | _| j| jv r*| j| j ||}|j| _d S td| j )N	savestatsFr*   profilerrE   zUnsupported profiler name: )getlowerrG   	profilersr/   r   )r   optionsr   r   rG   r   r   r   r   z   s   zAppProfiler.__init__N)r$   r%   r&   r'   r)   r;   rJ   r   r   r   r   r   rD   o   s    
rD   c                   @   s<   e Zd ZdZdZdd Zdd Zdd Zd	d
 Zdd Z	dS )	AppLoggera]  
    An L{AppLogger} attaches the configured log observer specified on the
    commandline to a L{ServerOptions} object, a custom L{logger.ILogObserver},
    or a legacy custom {log.ILogObserver}.

    @ivar _logfilename: The name of the file to which to log, if other than the
        default.
    @type _logfilename: C{str}

    @ivar _observerFactory: Callable object that will create a log observer, or
        None.

    @ivar _observer: log observer added at C{start} and removed at C{stop}.
    @type _observer: a callable that implements L{logger.ILogObserver} or
        L{log.ILogObserver}.
    Nc                 C   s"   | dd| _| dpd| _dS )zE
        Initialize an L{AppLogger} with a L{ServerOptions}.
        r    r   N)rH   _logfilename_observerFactoryr   rK   r   r   r   r      s   zAppLogger.__init__c                 C   s   | j dur
|   }n|tjd}|du r|tjd}|du r$|  }|| _tj| jr3| jg}ntj| jrBt| jg}nt	j
dtdd t| jg}tj| |   dS )a  
        Initialize the global logging system for the given application.

        If a custom logger was specified on the command line it will be used.
        If not, and an L{logger.ILogObserver} or legacy L{log.ILogObserver}
        component has been set on C{application}, then it will be used as the
        log observer. Otherwise a log observer will be created based on the
        command line options for built-in loggers (e.g. C{--logfile}).

        @param application: The application on which to check for an
            L{logger.ILogObserver} or legacy L{log.ILogObserver}.
        @type application: L{twisted.python.components.Componentized}
        NaZ  Passing a logger factory which makes log observers which do not implement twisted.logger.ILogObserver or twisted.python.log.ILogObserver to twisted.application.app.AppLogger was deprecated in Twisted 16.2. Please use a factory that produces twisted.logger.ILogObserver (or the legacy twisted.python.log.ILogObserver) implementing objects instead.   )
stacklevel)rO   getComponentr   ILogObserverr   _getLogObserver	_observer
providedByLegacyLogObserverWrapperwarningswarnDeprecationWarningglobalLogBeginnerbeginLoggingTo_initialLog)r   applicationobserver	observersr   r   r   start   s(   


	zAppLogger.startc                 C   sJ   ddl m} t| jdtjtjt	
 d t| jdt|jd dS )z1
        Print twistd start log message.
        r   r6   z1twistd {version} ({exe} {pyVersion}) starting up.)versionexe	pyVersionzreactor class: {reactor}.N)twisted.internetr6   r   
_loggerForinfor   rd   r1   
executabler   shortPythonVersionr   	__class__)r   r6   r   r   r   r^      s   



zAppLogger._initialLogc                 C   s0   | j dks| j stj}ntj| j }t|S )zr
        Create a log observer to be added to the logging system before running
        this application.
        -)rN   r1   r2   r   LogFilefromFullPathr   textFileLogObserver)r   logFiler   r   r   rU      s   
zAppLogger._getLogObserverc                 C   s6   t | d | jdurt j| j d| _dS dS )zS
        Remove all log observers previously set up by L{AppLogger.start}.
        zServer Shut Down.N)r   rh   ri   rV   globalLogPublisherremoveObserverr   r   r   r   stop   s
   

zAppLogger.stop)
r$   r%   r&   r'   rV   r   rb   r^   rU   ru   r   r   r   r   rL      s    2rL   c                  C   s4   dd } dd }dd }|t j_| t j_|t j_d S )Nc                 S   s.   |    |   ddlm} |d|j dS )Nr   rc      )clear_all_breaksset_continuerg   r6   	callLaterru   )r   argr6   r   r   r   do_stop   s
   zfixPdb.<locals>.do_stopc                 S   s   t d d S )NzEstop - Continue execution, then cleanly shutdown the twisted reactor.)printrt   r   r   r   	help_stop   s   zfixPdb.<locals>.help_stopc                 S   s   t d d S )Nr   )os_exitrt   r   r   r   set_quit  s   zfixPdb.<locals>.set_quit)pdbPdbr   r{   r}   )r{   r}   r   r   r   r   fixPdb   s   r   c                 C   s  |du r
ddl m} zG| d r|dur|| W dS W dS | d rK|t_|t_tjdkr?ttj	dd  ttj
d	d  t  t|j W dS |  W dS  ty   d
}| d ra|}ntdd}d}ztj|d |  W |r}|  Y dS Y dS |r|  w w w )aN  
    Start the reactor, using profiling if specified by the configuration, and
    log any error happening in the process.

    @param config: configuration of the twistd application.
    @type config: L{ServerOptions}

    @param oldstdout: initial value of C{sys.stdout}.
    @type oldstdout: C{file}

    @param oldstderr: initial value of C{sys.stderr}.
    @type oldstderr: C{file}

    @param profiler: object used to run the reactor with profiling.
    @type profiler: L{AppProfiler}

    @param reactor: The reactor to use.  If L{None}, the global reactor will
        be used.
    Nr   rc   r*   debugposixc                  W      t  S r   r   	set_traceargsr   r   r   <lambda>+      z'runReactorWithLogging.<locals>.<lambda>c                  W   r   r   r   r   r   r   r   r   ,  r   FnodaemonzTWISTD-CRASH.logr+   Tfile)rg   r6   r/   r1   r2   stderrr   platformTypesignalSIGUSR2SIGINTr   r   r.   BaseExceptionr3   	traceback	print_excflushr5   )config	oldstdout	oldstderrrG   r6   r5   r   r   r   r   runReactorWithLogging  s>   




r   c                 C   s   | rt  dS d S )NzPassphrase: )getpassneededr   r   r   getPassphrase@     
r   c                 C   s   | rt dS d S )NzEncryption passphrase: )r   getPasswordr   r   r   r   getSavePassphraseG  r   r   c                   @   sH   e Zd ZdZeZeZdd Zdd Z	dd Z
dd	 Zd
d Zdd ZdS )ApplicationRunnera  
    An object which helps running an application based on a config object.

    Subclass me and implement preApplication and postApplication
    methods. postApplication generally will want to run the reactor
    after starting the application.

    @ivar config: The config object, which provides a dict-like interface.

    @ivar application: Available in postApplication, but not
       preApplication. This is the application object.

    @ivar profilerFactory: Factory for creating a profiler object, able to
        profile the application if options are set accordingly.

    @ivar profiler: Instance provided by C{profilerFactory}.

    @ivar loggerFactory: Factory for creating object responsible for logging.

    @ivar logger: Instance provided by C{loggerFactory}.
    c                 C   s"   || _ | || _| || _d S r   )r   profilerFactoryrG   loggerFactoryr   )r   r   r   r   r   r   h  s   zApplicationRunner.__init__c                 C   s6   |    |  | _| j| j |   | j  dS )z&
        Run the application.
        N)preApplicationcreateOrGetApplicationr_   r   rb   postApplicationru   rt   r   r   r   r/   m  s
   
zApplicationRunner.runc                 C   sH   |du r
ddl m} t| j||| j| t|r|j| _dS d| _dS )z
        Run the reactor with the given configuration.  Subclasses should
        probably call this from C{postApplication}.

        @see: L{runReactorWithLogging}
        Nr   rc   )rg   r6   r   r   rG   r   rW   _exitSignal)r   r6   r   r   r   r   r   startReactory  s   

zApplicationRunner.startReactorc                 C      t  )z
        Override in subclass.

        This should set up any state necessary before loading and
        running the Application.
        NotImplementedErrorrt   r   r   r   r     s   z ApplicationRunner.preApplicationc                 C   r   )z
        Override in subclass.

        This will be called after the application has been loaded (so
        the C{application} attribute will be set). Generally this
        should start the application and run the reactor.
        r   rt   r   r   r   r     s   z!ApplicationRunner.postApplicationc                 C   s^   | j jr | j j| j j }|| j j}t|j}|| |S t	| j d }t
| j |}|S )a  
        Create or load an Application based on the parameters found in the
        given L{ServerOptions} instance.

        If a subcommand was used, the L{service.IServiceMaker} that it
        represents will be used to construct a service to be added to
        a newly-created Application.

        Otherwise, an application will be loaded based on parameters in
        the config.
        	encrypted)r   
subCommandloadedPluginsmakeService
subOptionsr   ApplicationtapnamesetServiceParentr   getApplication)r   plgserr_   
passphraser   r   r   r     s   
z(ApplicationRunner.createOrGetApplicationN)r$   r%   r&   r'   rD   r   rL   r   r   r/   r   r   r   r   r   r   r   r   r   N  s    	
r   c              
      s    fdddD d }|d ddi |d |d }}ztd|  t|||}td	 W |S  tyr } z4d
| }t|trN|jd dkrN|d7 }t	j
tjd t| t  td| d  W Y d }~|S d }~ww )Nc                    s    g | ]} | r | |fqS r   r   ).0tr   r   r   
<listcomp>  s     z"getApplication.<locals>.<listcomp>)pythonsourcer   r   r   picklerv   zLoading %s...zLoaded.zFailed to load application: %sr_   aN  
Could not find 'application' in the file. To use 'twistd -y', your .tac
file must create a suitable object (e.g., by calling service.Application())
and store it in a variable named 'application'. twistd loads your .tac file
and scans the global variables for one of this name.

Please read the 'Using Application' HOWTO for details.
r   
)rH   r   msgr   loadApplication	Exception
isinstanceKeyErrorr   r   r   r   deferrr1   exit)r   r   r"   filenamestyler_   r!   r   r   r   r     s$   "
r   c                   C   s   t dd t D S )Nc                 S   s   g | ]}|j qS r   )	shortName)r   rr   r   r   r     s    z"_reactorAction.<locals>.<listcomp>)r   CompleteListr   getReactorTypesr   r   r   r   _reactorAction  s   r   c                   @   sD   e Zd ZdZejdeidZej	Z
eejZdd Zdd ZeZdS )	ReactorSelectionMixinz
    Provides options for selecting a reactor to install.

    If a reactor is installed, the short name which was used to locate it is
    saved as the value for the C{"reactor"} key.
    r6   )
optActionsc                 C   s   t |  tdd}d}|D ]9}zt|j | jd|jdd|j d W q t	yG } z|d
|j|j|jd	 7 }W Y d
}~qd
}~ww |r\| jd | jd | j| td	)zE
        Display a list of possibly available reactor names.
        r   keyrM   z    z<4	r   z    !{:<4}	{} ({})
r   Nz.    reactors not available on this platform:

)sorted_getReactorTypesr   r   
moduleNamemessageOutputwriter   descriptionr,   formatr   r   )r   rctsnotWorkingReactorsr   r!   r   r   r   opt_help_reactors  s*   
$z'ReactorSelectionMixin.opt_help_reactorsc              
   C   sf   zt | W n& ty   d|f }t| ty, } z
d|f }t|d}~ww || d< dS )zX
        Which reactor to use (see --help-reactors for a list of possibilities)
        zcThe specified reactor does not exist: '%s'.
See the list of available reactors with --help-reactorsztThe specified reactor cannot be used, failed with error: %s.
See the list of available reactors with --help-reactorsNr6   )r	   r   r   
UsageErrorr   )r   r   r   r!   r   r   r   opt_reactor  s"   	

z!ReactorSelectionMixin.opt_reactorN)r$   r%   r&   r'   r   Completionsr   compDatar1   r2   r   staticmethodr   r   r   r   r   opt_rr   r   r   r   r     s    
r   c                
   @   s   e Zd ZdZg dg dg dgZg dg dg ddd	d
ddej gg dg dg dg dgZe	j
dge	de	de	de	 ddZeejZdd Zdd ZeZdd Zd#ddZdd  Zed!d" Zd	S )$ServerOptionszQtwistd reads a twisted.application.service.Application out of a file and runs it.)rF   NzBsave the Stats object rather than the text output of the profiler.)no_saveozdo not save state on shutdown)r   r!   z(The specified tap/aos file is encrypted.)r   lNz%log to a specified file, - for stdout)r   NNzA fully-qualified name to a log observer factory to use for the initial log observer.  Takes precedence over --logfile and --syslog (when available).)r*   r7   Nz7Run in profile mode, dumping results to specified file.rG   NrE   z!Name of the profiler to use (%s).z, )r   fz
twistd.tapzread the given .tap file)r   yNz:read an application from within a Python file (implies -o))r   r"   Nz2Read an application from a .tas file (AOT format).)rundird.z-Change to a supplied directory before running)r   r   r   z*.tapz
*.(tac|py)z*.tas)r   r   r   r   )mutuallyExclusiver   c                 O   s4   d| d< d|v r|d | _ ntj | _ tj|  d S )NFr   r2   )r2   r1   r   Optionsr   )r   r+   kwr   r   r   r   Y  s
   zServerOptions.__init__c                 C   s   t d t  d| d< dS )z
        Run the application in the Python Debugger (implies nodaemon),
        sending SIGUSR2 will drop into debugger
        Tr   N)r
   setDebuggingr   startDebugModert   r   r   r   	opt_debuga  s   
zServerOptions.opt_debugc                 C   s>   t tj zddl}W n
 ty   Y dS w |tj dS )z
        Print an insanely verbose log of everything that happens.
        Useful when debugging freezes or locks in complex code.
        r   N)r1   settracer   spewer	threadingr,   )r   r   r   r   r   opt_spewl  s   zServerOptions.opt_spewc                 C   s.   |d u rt jdd  pdg}tj| | d S )Nrv   z--help)r1   argvr   r   parseOptionsrP   r   r   r   r   x  s   zServerOptions.parseOptionsc              
   C   sl   | j s| d rd| d< | d d ur4zt| d | d< W d S  ty3 } ztd| d |d }~ww d S )Nr   Tr   r   z%Logger '{}' could not be imported: {})r   r   r   r   r   r   )r   r!   r   r   r   postOptions}  s   zServerOptions.postOptionsc                 c   sT    |  tj}i | _t|tddD ]}|| j|j< |jd |fdd|jfV  qd S )Nr   r   c                 S   s   |   S r   )rK   )plugr   r   r   r     r   z+ServerOptions.subCommands.<locals>.<lambda>)_getPluginsr   IServiceMakerr   r   r   r   r   )r   pluginsr   r   r   r   subCommands  s   
zServerOptions.subCommandsr   )r$   r%   r&   longdescoptFlagsjoinrD   rJ   optParametersr   r   CompleteFilesCompleteDirsr   r   r   
getPluginsr   r   r   opt_br   r   r   propertyr   r   r   r   r   r     sJ    !

	
r   c              
   C   sv   | }z|   W n+ tjy4 } zdtjdd }t| t| d|  W Y d }~d S d }~ww | | d S )N r   rQ   r   )r   r   errorr  r1   r   r|   )runAppr   r   uecommstrr   r   r   r/     s    r/   c                 C   sF   t | ||}t|| t|}|rd }t|j||d d S )N)r   r   )r   r   r   IPersistablesetStyler   save)fileintypeinr   fileouttypeoutencryptr_   r   r   r   convertStyle  s   r  c                 C   sT   ddl m} t|   |rt| }|dd|jd |ddt| j	 d S )Nr   rc   aftershutdownbefore)
rg   r6   r   IServicestartServicer   r  addSystemEventTriggerr  stopService)r_   r  r6   r7   r   r   r   startApplication  s   
r  c                 C   s"   t  | t j tt |  dS )a  
    Force the application to terminate with the specified signal by replacing
    the signal handler with the default and sending the signal to ourselves.

    @param sig:  Signal to use to terminate the process with C{os.kill}.
    @type sig:  C{int}
    N)r   SIG_DFLr~   killgetpid)sigr   r   r   _exitWithSignal  s   r$  )NN)7r   r~   r   r   r1   r   rY   operatorr   twistedr   r   r   twisted.applicationr   r   twisted.application.reactorsr   r	   rg   r
   twisted.internet.interfacesr   twisted.persistedr   twisted.pythonr   r   r   r   r   r   twisted.python.reflectr   r   r   r   r)   r;   rD   rL   r   r   r   r   r   r   r   r   r   r   r/   r  r  r$  r   r   r   r   <module>   sD    r
3kE~	