
    h78jq                         d 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
  ej        e          ZdZdZdZdZ G d	 d
          Z G d d          ZdS )z-Local cache with TTL expiration using SQLite.    N)Path)Anyi@8  i'  iP  i  c                   h    e Zd ZdZedfdededdfdZdedee         fd	Z	deddfd
Z
dedefdZdS )BloomFilterz/Simple bloom filter for negative cache lookups.   size
hash_countreturnNc                     || _         || _        t          |dz  dz             | _        t	          j                    | _        d S )N      )r   r	   	bytearray	bit_array	threadingRLock_lock)selfr   r	   s      V/home/rurouni/.hermes/hermes-agent/venv/lib/python3.11/site-packages/ddgs/dht/cache.py__init__zBloomFilter.__init__   s:    	$"419q=11_&&


    keyc                 :   g }t          | j                  D ]}| d|                                 }t          j        |                                          }t                              |dd         dd          }|                    || j	        z             |S )z@Generate hash positions for a key using SHA-256 for consistency.:Nr   bigF)	byteordersigned)
ranger	   encodehashlibsha256digestint
from_bytesappendr   )r   r   resultidatar!   hs          r   _hasheszBloomFilter._hashes   s    t'' 	) 	)A<<A<<&&((D^D))0022FvbqbzU5IIAMM!di-((((r   c                     | j         5  |                     |          D ] }| j        |dz  xx         d|dz  z  z  cc<   !	 ddd           dS # 1 swxY w Y   dS )zAdd a key to the filter.r   r   N)r   r)   r   )r   r   poss      r   addzBloomFilter.add)   s    Z 	; 	;||C(( ; ;sax(((A#'N:((((;	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	;s   7AAAc                       j         5  t           fd                     |          D                       cddd           S # 1 swxY w Y   dS )zCheck if a key may be present.c              3   J   K   | ]}j         |d z           d|d z  z  z  V  dS )r   r   N)r   ).0r+   r   s     r   	<genexpr>z+BloomFilter.__contains__.<locals>.<genexpr>2   s;      ``st~cQh/1q>B``````r   N)r   allr)   )r   r   s   ` r   __contains__zBloomFilter.__contains__/   s    Z 	a 	a````dll[^N_N_`````	a 	a 	a 	a 	a 	a 	a 	a 	a 	a 	a 	a 	a 	a 	a 	a 	a 	as   .AAA)__name__
__module____qualname____doc__NEGATIVE_CACHE_SIZEr"   r   strlistr)   r,   boolr2    r   r   r   r      s        99#6! ' 'S 'C 'PT ' ' ' '
3 
49 
 
 
 
;s ;t ; ; ; ;a a a a a a a ar   r   c                   8   e Zd ZdZddedz  ddfdZdej        ddfdZdede	e
eef                  dz  fd	Zd
ede	e
eef                  dz  fdZefd
ededede	e
eef                  deddfdZd
eddfdZdefdZdefdZdefdZdefdZd
eddfdZdS )ResultCachez0Thread-safe local SQLite cache with TTL support.Ndb_pathr
   c                    |rt          |          | _        nBt          d                                          }|                    dd           |dz  | _        t	          j                    | _        t                      | _        i | _	        t          j        | j                  5 }|                     |           d d d            d S # 1 swxY w Y   d S )Nz~/.ddgsT)parentsexist_okzcache.db)r   _db_path
expandusermkdirr   r   r   r   _negative_cache_negative_cache_timessqlite3connect_init_db)r   r>   ddgs_dirconns       r   r   zResultCache.__init__8   s     	2 MMDMMI1133HNN4$N777$z1DM_&&
*}}79" _T]++ 	 tMM$	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	 s   %CCCrK   c                     |                     d           |                     d           |                                 d S )Na>  
            CREATE TABLE IF NOT EXISTS cached_results (
                query_hash TEXT PRIMARY KEY,
                query TEXT NOT NULL,
                category TEXT NOT NULL,
                results TEXT NOT NULL,
                timestamp REAL NOT NULL,
                ttl INTEGER NOT NULL
            )
        zg
            CREATE INDEX IF NOT EXISTS idx_timestamp
            ON cached_results(timestamp)
        )executecommitr   rK   s     r   rI   zResultCache._init_dbH   sM     	 		 		 		 	  	 	 	 	r   results_jsonc                 N    	 t          j        |          S # t          $ r Y dS w xY w)zParse JSON results safely.N)jsonloads	Exception)r   rP   s     r   _parse_resultszResultCache._parse_resultsY   s9    	:l+++ 	 	 	44	s    
$$
query_hashc                 :   | j         5  t          j        | j                  5 }|                    d|f                                          }|s	 ddd           ddd           dS |\  }}}t          j                    ||z   k    rD|                    d|f           |                                 	 ddd           ddd           dS |                     |          cddd           cddd           S # 1 swxY w Y   ddd           dS # 1 swxY w Y   dS )z"Get cached results if not expired.zGSELECT results, timestamp, ttl FROM cached_results WHERE query_hash = ?N/DELETE FROM cached_results WHERE query_hash = ?)	r   rG   rH   rB   rM   fetchonetimerN   rU   )r   rV   rK   r%   rP   	timestampttls          r   getzResultCache.get`   s#   
 Z 	5 	577 	54\\Y  hjj 
  	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 ,2(L)Sy{{Y_,,EM   #	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5& &&|44'	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5sM   D-C8D'AC83DC8D8C<	<D?C<	 DDDquerycategoryresultsr\   c                 j   | j         5  t          j        | j                  5 }|                    d|||t          j        |dd          t          j                    |f           |                                 |                    d          	                                d         }|t          k    rS|t          z
  dz   }|                    d|f           |                                 t                              d|           d	d	d	           n# 1 swxY w Y   d	d	d	           d	S # 1 swxY w Y   d	S )
z,Store results with TTL and enforce max size.zvINSERT OR REPLACE INTO cached_results (query_hash, query, category, results, timestamp, ttl) VALUES (?, ?, ?, ?, ?, ?)F)ensure_ascii	allow_nan#SELECT COUNT(*) FROM cached_resultsr   r   zuDELETE FROM cached_results WHERE query_hash IN (SELECT query_hash FROM cached_results ORDER BY timestamp ASC LIMIT ?)zEvicted %d old entriesN)r   rG   rH   rB   rM   rR   dumpsrZ   rN   rY   MAX_CACHE_SIZEloggerdebug)	r   rV   r^   r_   r`   r\   rK   countexcesss	            r   setzResultCache.setz   s    Z 	? 	?77 	?4LL, JwUeLLLIKK	   KKMMM LL!FGGPPRRSTUE~%%/!36 I	   5v>>>7	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	?s5   D(C"DD(D	D(D	D((D,/D,c                     | j         5  t          j        | j                  5 }|                    d|f           |                                 ddd           n# 1 swxY w Y   ddd           dS # 1 swxY w Y   dS )zDelete a cached result.rX   N)r   rG   rH   rB   rM   rN   )r   rV   rK   s      r   deletezResultCache.delete   s    Z 	 	77 	4LLA   KKMMM	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s4   A2,AA2A	A2!A	"A22A69A6c                 F   | j         5  t          j        | j                  5 }|                    dt          j                    f          }|                                 |j        cddd           cddd           S # 1 swxY w Y   ddd           dS # 1 swxY w Y   dS )zRemove all expired entries.z4DELETE FROM cached_results WHERE timestamp + ttl < ?N)r   rG   rH   rB   rM   rZ   rN   rowcount)r   rK   cursors      r   cleanup_expiredzResultCache.cleanup_expired   s.   Z 	# 	#77 	#4\\F F KKMMM?	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	#s5   BAA>%B>B	BB	BBBc                    | j         5  t          j        | j                  5 }|                    d                                          d         cddd           cddd           S # 1 swxY w Y   ddd           dS # 1 swxY w Y   dS )#Get total number of cached entries.rd   r   N)r   rG   rH   rB   rM   rY   rO   s     r   ri   zResultCache.count   sG   Z 	U 	U77 	U4<< EFFOOQQRST	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	U 	Us4   B -A(B (A,	,B /A,	0B  BBc                 *    |                                  S )rs   )ri   r   s    r   __len__zResultCache.__len__   s    zz||r   c                 t    | j                                         r| j                                         j        ndS )zGet database size in bytes.r   )rB   existsstatst_sizeru   s    r   
size_byteszResultCache.size_bytes   s1    /3}/C/C/E/ELt}!!##++1Lr   c                    | j         5  t          | j                  t          dz  k    rEt	          j                    fd| j                                        D             }|D ]
}| j        |= | j                            |           t	          j                    | j        |<   t          	                    d|           ddd           dS # 1 swxY w Y   dS )z6Add an entry to the negative cache (no results found).g?c                 6    g | ]\  }}|z
  t           k    |S r;   )NEGATIVE_CACHE_TTL)r/   kvnows      r   
<listcomp>z,ResultCache.add_negative.<locals>.<listcomp>   s-    mmmAsUVwZlOlOl1OlOlOlr   zAdded to negative cache: %sN)
r   lenrF   r7   rZ   itemsrE   r,   rg   rh   )r   rV   expiredr   r   s       @r   add_negativezResultCache.add_negative   s.   Z 
	D 
	D4-..2E2KKKikkmmmm)C)I)I)K)Kmmm  6 6A2155 $$Z00059Y[[D&z2LL6
CCC
	D 
	D 
	D 
	D 
	D 
	D 
	D 
	D 
	D 
	D 
	D 
	D 
	D 
	D 
	D 
	D 
	D 
	Ds   B6CCC)N)r3   r4   r5   r6   r8   r   rG   
ConnectionrI   r9   dictr   rU   r]   DEFAULT_TTLr"   rk   rm   rq   ri   rv   r{   r   r;   r   r   r=   r=   5   s       ::   d
  d         W/ D    "3 4S#X3G$3N    55 
d38n		$5 5 5 5@ $? $?$? $? 	$?
 d38n%$? $? 
$? $? $? $?L     # # # # #Us U U U U
    MC M M M MDs Dt D D D D D Dr   r=   )r6   r   rR   loggingrG   r   rZ   pathlibr   typingr   	getLoggerr3   rg   r   rf   r7   r~   r   r=   r;   r   r   <module>r      s   3 3                     		8	$	$  a a a a a a a aBWD WD WD WD WD WD WD WD WD WDr   