
    h78j"                         d Z ddlZddlZddlmZ ddlZddlmZmZm	Z	 ddl
mZmZ ddlmZmZ g dZ ej        e          Zd	Zd
Z G d d          Z	 ddedz  defdZdS )a9  Distributed cache DHT module.

This module provides a P2P cache DHT for sharing search results
across multiple ddgs instances using Kademlia DHT.

Usage:
    from ddgs.dht import DhtClient

    # Direct mode (runs Trio in-process)
    client = DhtClient()
    await client.start()

    # REST API mode (connects to ddgs api service)
    client = DhtClient(api_url="http://localhost:4479")

    # Get cached results
    results = await client.get_cached("python tutorial")

    # Store results
    await client.cache("python tutorial", results)

    await client.stop()
    N)Any   )DEFAULT_TTLMAX_CACHE_SIZEResultCache)DEFAULT_MAX_HOP_CONNECTIONSLibp2pClient)compute_query_hashnormalize_query)r   r   r   	DhtClientr	   r   r
   r   zhttp://localhost:4479g      ?c                   l   e Zd ZdZddeedddededed	ed
edz  ddfdZ	defdZ
dededeeeef                  dz  fdZ	 ddededeeeef                  dz  fdZ	 ddedeeeef                  deddfdZddededdfdZddZedefd            Zedefd            Zedefd            ZdS )r   aN  Client for the distributed cache DHT.

    Provides transparent access to cached results from other peers
    while falling back to direct search engine queries when needed.

    Supports two modes:
    - Direct mode (api_url=None): Runs libp2p/Trio in-process
    - REST mode (api_url set): Connects to ddgs api service via HTTP
    Tr   N)
enable_dhtlisten_port	cache_ttlmax_hop_connectionsapi_urlr   r   r   r   r   returnc                    || _         || _        |r|	|pt          nd | _        d| _        |  |  | j        rd | _        d | _        d S t          |||          | _        t                      | _        d S )NF)r   	bootstrapr   )	r   r   DEFAULT_API_URLr   _started_dht_cacher	   r   )selfr   r   r   r   r   s         Y/home/rurouni/.hermes/hermes-agent/venv/lib/python3.11/site-packages/ddgs/dht/__init__.py__init__zDhtClient.__init__?   s     %"7AcgFY2?_c&'< 		(DIDKKK$'$$7  DI
 &--DKKK    c                 j  K   | j         rdS | j        r!t                              d| j                   ns| j        rR| j        Kt          j        | j        j                   d{V }t                              d|| j        j	                   nt                              d           d| _         | j         S )z`Start the DHT client.

        Returns:
            True if DHT connection successful.

        Tz&DHT client started (REST API mode): %sNz)DHT client started: connected=%s, port=%dz!DHT client started (DHT disabled))
r   r   loggerinfor   r   asyncio	to_threadstartport)r   	connecteds     r   r#   zDhtClient.startZ   s       = 	4< 	=KK@$,OOOO_ 		=!6%/	@@@@@@@@IKK;	    KK;<<<}r   querycategoryc                   K   t          |          }	 t          j        t                    4 d{V }|                    | j         d||d           d{V }|j        dk    r	 |                                }|                    d          x}r/t          	                    d|           |cddd          d{V  S n2# t          $ r%}t          	                    d	|           Y d}~nd}~ww xY wddd          d{V  n# 1 d{V swxY w Y   n3# t          $ r&}t          	                    d
||           Y d}~nd}~ww xY wdS )zGet cached results from API.timeoutN
/dht/cacher&   r'   params   resultszCache hit (DHT API): %sz Failed to parse API response: %rzDHT API get failed for %s: %r)r   primpAsyncClientCACHE_TIMEOUTgetr   status_codejsonr   debug	Exception)	r   r&   r'   
normalizedclientrespdatar0   exs	            r   _get_from_apizDhtClient._get_from_apit   s     $U++
	J(??? M M M M M M M6#ZZ|///%*AA (         #s**M/3yy{{&*hhy&9&997 +"LL)BJOOO#*M M M M M M M M M M M M M M+ % M M M%GLLLLLLLLMM M M M M M M M M M M M M M M M M M M M M M M M M M M  	J 	J 	JLL8*bIIIIIIII	Jtsk    D 4D(AC/D D
C2C-(D-C22D5D 
DD DD 
E	#EE	textc                 f  K   | j         s|                                  d{V  t          ||          }t          |          }| j        r|                     ||           d{V S | j        dS | j                            |          }|rt          	                    d|           |S | j
        | j
        j        rv| j
                            |          }|r@t          	                    d|           | j                            ||||| j                   |S | j                            |           dS )zGet cached results for a query.

        Checks local cache first, then DHT DHT (or REST API).

        Args:
            query: The search query.
            category: The search category.

        Returns:
            Cached results or None.

        NzCache hit (local): %szCache hit (DHT): %s)r   r#   r
   r   r   r>   r   r4   r   r7   r   
is_runningsetr   add_negative)r   r&   r'   
query_hashr9   local_resultsdht_resultss          r   
get_cachedzDhtClient.get_cached   sD     " } 	**,,'x88
$U++
< 	=++E8<<<<<<<<<;4
33 	!LL0*===  9 TY%9 )--
33K #2J???
J+t~^^^""K$$Z000tr   r0   c                 &  K   | j         s|                                  d{V  t          ||          }t          |          }| j        r	 t          j        t                    4 d{V }|                    | j         d|||d           d{V }|j	        dv rt                              d|           ddd          d{V  n# 1 d{V swxY w Y   n3# t          $ r&}t                              d||           Y d}~nd}~ww xY wdS | j        dS | j                            ||||| j                   | j        J| j        j        r@| j                            ||| j                   t                              d	|           dS dS dS )
zCache search results locally and on DHT.

        Args:
            query: The search query.
            results: The search results.
            category: The search category.

        Nr)   r+   )r&   r0   r'   )r6   )r/      zCached to DHT API: %szDHT API cache failed for %s: %rzCached to DHT: %s)r   r#   r
   r   r   r1   r2   r3   postr5   r   r7   r8   r   rB   r   r   rA   )	r   r&   r0   r'   rD   r9   r:   r;   r=   s	            r   cachezDhtClient.cache   s      } 	**,,'x88
$U++
< 		P ,]CCC J J J J J J Jv!'<333',hWW "- " "      D ':55%<jIIIJ J J J J J J J J J J J J J J J J J J J J J J J J J J  P P P>
BOOOOOOOOPF;F
J'4>RRR9 TY%9 IMM*gt~>>>LL,j99999 !   s=    C +AC9C 
CC CC 
D'DDc                   K   t          ||          }| j        r	 t          j        t                    4 d{V }|                    | j         d||d           d{V  ddd          d{V  n# 1 d{V swxY w Y   n2# t          $ r%}t                              d|           Y d}~nd}~ww xY wdS | j	        dS | j	                            |           dS )zInvalidate cached results for a query.

        Args:
            query: The search query.
            category: The search category.

        r)   Nr+   r,   r-   zDHT API invalidate failed: %r)
r
   r   r1   r2   r3   deleter8   r   r7   r   )r   r&   r'   rD   r:   r=   s         r   
invalidatezDhtClient.invalidate   s      (x88
< 		B ,]CCC       v --<333).HEE (                                   
  B B B<bAAAAAAAABF;F:&&&&&s:    B )A6$B 6
B  B B B 
B7B22B7c                 p   K   | j         r%| j         j        r| j                                          d| _        dS )zStop the DHT client.FN)r   rA   stopr   r   s    r   rP   zDhtClient.stop   s9      9 	- 	INNr   c                 H    | j         r| j        S | j        r| j        j        ndS )z%Check if the DHT client is connected.F)r   r   r   rA   rQ   s    r   is_connectedzDhtClient.is_connected  s-     < 	!= '+y;ty##e;r   c                 F    | j         r| j                                         S dS )z!Get the number of cached entries.r   )r   countrQ   s    r   cache_countzDhtClient.cache_count  s'     ; 	';$$&&&qr   c                 F    | j         r| j                                         S dS )z#Get the size of the cache in bytes.r   )r   
size_bytesrQ   s    r   
cache_sizezDhtClient.cache_size  s'     ; 	,;))+++qr   )r?   )r   N)__name__
__module____qualname____doc__r   r   boolintstrr   r#   listdictr   r>   rG   rK   rN   rP   propertyrS   rV   rY    r   r   r   r   4   s:          $#>"( ( ( ( 	(
 ( !( t( 
( ( ( (6T    4  T#s(^@TW[@[    0 + ++ + 
d38n		$	+ + + +b 	(: (:(: d38n%(: 	(:
 
(: (: (: (:T' 'c 'S 'd ' ' ' '4    <d < < < X< S    X C    X  r   r   r   r   c                 ^   K   t          |           }|                                 d{V  |S )zGet a shared DHT client instance.

    Args:
        api_url: URL of the ddgs API service. If None, uses direct mode.

    Returns:
        A started DhtClient instance.

    )r   N)r   r#   )r   r:   s     r   get_dht_clientrf     s=       w'''F
,,..Mr   )N)r]   r!   loggingtypingr   r1   rK   r   r   r   libp2p_clientr   r	   typesr
   r   __all__	getLoggerrZ   r   r   r3   r   r`   rf   rd   r   r   <module>rm      s(   0          ; ; ; ; ; ; ; ; ; ; D D D D D D D D 6 6 6 6 6 6 6 6	 	 	 
	8	$	$)` ` ` ` ` ` ` `H  4Z     r   