
    i1                        U d Z g dZddlZddlZddlmZ ddlZddlZddl	Z	ddl
mZmZ ej                  r ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZmZ  ej2                   eddd            Zeed<   	  e	j8                         Zej=                         d        Zej=                         dde fd       Z! G d d      Z" G d dejF                        Z$y)a  Implementations of the framework for the SearXNG engines.

- :py:obj:`searx.enginelib.EngineCache`
- :py:obj:`searx.enginelib.Engine`
- :py:obj:`searx.enginelib.traits`

There is a command line for developer purposes and for deeper analysis.  Here is
an example in which the command line is called in the development environment::

  $ ./manage pyenv.cmd bash --norc --noprofile
  (py3) python -m searx.enginelib --help

.. hint::

   The long term goal is to modularize all implementations of the engine
   framework here in this Python package.  ToDo:

   - move implementations of the :ref:`searx.engines loader` to a new module in
     the :py:obj:`searx.enginelib` namespace.

-----

)EngineCacheEngineENGINES_CACHE    N)Callable   )ExpireCacheSQLiteExpireCacheCfg)traits)EngineTraits)SXNG_Response)EngineResults)OfflineParamTypesOnlineParamTypesr   i:	 i  )nameMAXHOLD_TIMEMAINTENANCE_PERIODc                  x   d} t        |        t        dt        |       z         t        t        j                         j	                                t                dt        j
                  j                   } t        |        t        dt        |       z         t        t        t        j                               y)z)Show state for the caches of the engines.zcache tables and key/values=zproperties of N)	printlenr   statereportcfgr   str
properties)titles    )/root/searxng/searx/enginelib/__init__.pyr   r   :   s     *E	%L	#E

	-



&
&
()	G]..3345E	%L	#E

	#m&&
'(    forcec                 0    t         j                  |        y)z.Carry out maintenance on cache of the engines.r   N)r   maintenancer!   s    r   r"   r"   I   s     E*r   c            	           e Zd ZdZddededz  fdZddedej                  dedz  de	fd	Z
dded
ej                  dej                  fdZdeez  defdZy)r   ae  Persistent (SQLite) key/value cache that deletes its values again after
    ``expire`` seconds (default/max: :py:obj:`MAXHOLD_TIME
    <searx.cache.ExpireCacheCfg.MAXHOLD_TIME>`).  This class is a wrapper around
    :py:obj:`ENGINES_CACHE` (:py:obj:`ExpireCacheSQLite
    <searx.cache.ExpireCacheSQLite>`).

    In the :origin:`searx/engines/demo_offline.py` engine you can find an
    exemplary implementation of such a cache other examples are implemented
    in:

    - :origin:`searx/engines/radio_browser.py`
    - :origin:`searx/engines/soundcloud.py`
    - :origin:`searx/engines/startpage.py`

    .. code: python

       from searx.enginelib import EngineCache
       CACHE: EngineCache

       def init(engine_settings):
           global CACHE
           CACHE = EngineCache(engine_settings["name"])

       def request(query, params):
           token = CACHE.get(key="token")
           if token is None:
               token = get_token()
               # cache token of this engine for 1h
               CACHE.set(key="token", value=token, expire=3600)
           ...

    For introspection of the DB, jump into developer environment and run command to
    show cache state::

        $ ./manage pyenv.cmd bash --norc --noprofile
        (py3) python -m searx.enginelib cache state

        cache tables and key/values
        ===========================
        [demo_offline        ] 2025-04-22 11:32:50 count        --> (int) 4
        [startpage           ] 2025-04-22 12:32:30 SC_CODE      --> (str) fSOBnhEMlDfE20
        [duckduckgo          ] 2025-04-22 12:32:31 4dff493e.... --> (str) 4-128634958369380006627592672385352473325
        [duckduckgo          ] 2025-04-22 12:40:06 3e2583e2.... --> (str) 4-263126175288871260472289814259666848451
        [radio_browser       ] 2025-04-23 11:33:08 servers      --> (list) ['https://de2.api.radio-browser.info',  ...]
        [soundcloud          ] 2025-04-29 11:40:06 guest_client_id --> (str) EjkRJG0BLNEZquRiPZYdNtJdyGtTuHdp
        [wolframalpha        ] 2025-04-22 12:40:06 code         --> (str) 5aa79f86205ad26188e0e26e28fb7ae7
        number of tables: 6
        number of key/value pairs: 7

    In the "cache tables and key/values" section, the table name (engine name) is at
    first position on the second there is the calculated expire date and on the
    third and fourth position the key/value is shown.

    About duckduckgo: The *vqd coode* of ddg depends on the query term and therefore
    the key is a hash value of the query term (to not to store the raw query term).

    In the "properties of ENGINES_CACHE" section all properties of the SQLiteAppl /
    ExpireCache and their last modification date are shown::

        properties of ENGINES_CACHE
        ===========================
        [last modified: 2025-04-22 11:32:27] DB_SCHEMA           : 1
        [last modified: 2025-04-22 11:32:27] LAST_MAINTENANCE    :
        [last modified: 2025-04-22 11:32:27] crypt_hash          : ca612e3566fdfd7cf7efe...
        [last modified: 2025-04-22 11:32:30] CACHE-TABLE--demo_offline: demo_offline
        [last modified: 2025-04-22 11:32:30] CACHE-TABLE--startpage: startpage
        [last modified: 2025-04-22 11:32:31] CACHE-TABLE--duckduckgo: duckduckgo
        [last modified: 2025-04-22 11:33:08] CACHE-TABLE--radio_browser: radio_browser
        [last modified: 2025-04-22 11:40:06] CACHE-TABLE--soundcloud: soundcloud
        [last modified: 2025-04-22 11:40:06] CACHE-TABLE--wolframalpha: wolframalpha

    These properties provide information about the state of the ExpireCache and
    control the behavior.  For example, the maintenance intervals are controlled by
    the last modification date of the LAST_MAINTENANCE property and the hash value
    of the password can be used to detect whether the password has been changed (in
    this case the DB entries can no longer be decrypted and the entire cache must be
    discarded).
    Nengine_nameexpirec                     |xs t         j                  j                  | _        dt        j
                  z   t        j                  z   }dj                  |D cg c]
  }||v r|nd c}      | _        y c c}w )Nz-_. _)	r   r   r   r%   stringascii_lettersdigitsjoin
table_name)selfr$   r%   _validcs        r   __init__zEngineCache.__init__   s\    !C]%6%6%C%C---=!ww;'WaQ&[c(A'WX'Ws   A3keyvaluereturnc                 d    t         j                  |||xs | j                  | j                        S )N)r2   r3   r%   ctx)r   setr%   r-   )r.   r2   r3   r%   s       r   r7   zEngineCache.set   s3      (T[[	 ! 
 	
r   defaultc                 F    t         j                  ||| j                        S )N)r8   r6   )r   getr-   )r.   r2   r8   s      r   r:   zEngineCache.get   s      g4?? KKr   r   c                 .    t         j                  |      S )N)r   )r   secret_hash)r.   r   s     r   r<   zEngineCache.secret_hash   s    ((d(33r   )N)__name__
__module____qualname____doc__r   intr1   tAnyboolr7   r:   bytesr<    r   r   r   r   O   s    M^YC Yt Y

s 
155 
#* 
 
Ls LQUU Laee L4e 4 4r   r   c                      e Zd ZU dZej
                  ed<   eed<   	 eed<   	 dZ	e
ed<   	 eed<   	 eed<   	 eed	<   	 eed
<   	 eed<   	 ded<   	 ded<   	 ee   ed<   	 eed<   	 eed<   	 eed<   	 eed<   	 eed<   	 eed<   	 eeeeef   f   ed<   	 eed<   	 eed<   	 eeeeef   f   ed<   	 eed<   	 eed<   	 ee   ed<   	 e
ed<   	 deeej                  f   d efd!Zdeeej                  f   d ed"z  fd#Zej&                  d$ed%d&d d'fd(       Zej&                  d$ed%d)d d"fd*       Zej&                  d,d+       Zy")-r   zClass of engine instances build from YAML settings.

    Further documentation see :ref:`general engine configuration`.

    .. hint::

       This class is currently never initialized and only used for type hinting.
    loggerengine_typepagingr   max_pagetime_range_support
safesearchlanguage_supportlanguageregionz$Callable[[EngineTraits, bool], None]fetch_traitsztraits.EngineTraitsr
   
categoriesr   engineenable_httpshortcuttimeoutdisplay_error_messagesproxiesdisabledinactiveaboutusing_tor_proxysend_accept_language_headertokensweightengine_settingsr4   c                      y)a  Dynamic setup of the engine settings.

        With this method, the engine's setup is carried out.  For example, to
        check or dynamically adapt the values handed over in the parameter
        ``engine_settings``.  The return value (True/False) indicates whether
        the setup was successful and the engine can be built or rejected.

        The method is optional and is called synchronously as part of the
        initialization of the service and is therefore only suitable for simple
        (local) exams/changes at the engine setting.  The :py:obj:`Engine.init`
        method must be used for longer tasks in which values of a remote must be
        determined, for example.
        TrF   r.   r`   s     r   setupzEngine.setup8  s     r   Nc                      y)aY  Initialization of the engine.

        The method is optional and asynchronous (in a thread).  It is suitable,
        for example, for setting up a cache (for the engine) or for querying
        values (required by the engine) from a remote.

        Whether the initialization was successful can be indicated by the return
        value ``True`` or even ``False``.

        - If no return value is given from this init method (``None``), this is
          equivalent to ``True``.

        - If an exception is thrown as part of the initialization, this is
          equivalent to ``False``.
        TrF   rb   s     r   initzEngine.initH  s      r   queryparamsr   r   c                      y)z(Search method of the ``offline`` enginesNrF   r.   rf   rg   s      r   searchzEngine.searchZ      r   r   c                      y)zOMethod to build the parameters for the request of an ``online``
        engine.NrF   ri   s      r   requestzEngine.request^  rk   r   c                      y)z5Method to parse the response of an ``online`` engine.NrF   )r.   resps     r   responsezEngine.responsec  rk   r   )ro   r   r4   r   )r=   r>   r?   r@   loggingLogger__annotations__r   rD   rK   rA   listfloatdictrB   rC   rc   re   abcabstractmethodrj   rm   rp   rF   r   r   r   r      s    NN =L)HcH ,$5M K 98;!! S	Q
I K 9M7N-  /#tCH~%&& N5 NET#s(^#$$ H!%%3 I KUT#quu*%5 $  Daee$4  $ 	7C 7)< 7 7 7 	S *<    	D Dr   r   )T)%r@   __all__typingrB   rw   collections.abcr   rq   r)   typercacher   r	   TYPE_CHECKINGsearx.enginelibr
   searx.enginelib.traitsr   searx.extended_typesr   searx.result_typesr   searx.search.processorsr   r   build_cacher   rs   Typerappcommandr   rD   r"   r   ABCr   rF   r   r   <module>r      s   0 5  
 $    5??&320K#@#4#@#@%"$  - ekkm ) ) +t + +
a4 a4HrDSWW rDr   