
     i5                     L   S r SSKrSSKrSSKJr  SSKJrJrJrJ	r	J
r
JrJrJrJrJrJrJr   " S S\5      r " S S	\5      r " S
 S\5      r " S S5      r " S S5      r\R.                  " 5       rSqS rS rS rS rSS jrS rSS jr S r!S r"S r#SS jr$S r%S r&S r'g)aL  
Stash - Global Shared State for Dirty Workers

Provides simple key-value tables stored in the arbiter process.
All workers can read and write to the same tables.

Usage::

    from gunicorn.dirty import stash

    # Basic operations - table is auto-created on first access
    stash.put("sessions", "user:1", {"name": "Alice", "role": "admin"})
    user = stash.get("sessions", "user:1")
    stash.delete("sessions", "user:1")

    # Dict-like interface
    sessions = stash.table("sessions")
    sessions["user:1"] = {"name": "Alice"}
    user = sessions["user:1"]
    del sessions["user:1"]

    # Query operations
    keys = stash.keys("sessions")
    keys = stash.keys("sessions", pattern="user:*")

    # Table management
    stash.ensure("cache")           # Explicit creation (idempotent)
    stash.clear("sessions")         # Delete all entries
    stash.delete_table("sessions")  # Delete the table itself
    tables = stash.tables()         # List all tables

Declarative usage in DirtyApp::

    class MyApp(DirtyApp):
        stashes = ["sessions", "cache"]  # Auto-created on arbiter start

        def __call__(self, action, *args, **kwargs):
            # Tables are ready to use
            stash.put("sessions", "key", "value")

Note: Tables are stored in the arbiter process and are ephemeral.
If the arbiter restarts, all data is lost.
    N   )
DirtyError)DirtyProtocolSTASH_OP_PUTSTASH_OP_GETSTASH_OP_DELETESTASH_OP_KEYSSTASH_OP_CLEARSTASH_OP_INFOSTASH_OP_ENSURESTASH_OP_DELETE_TABLESTASH_OP_TABLESSTASH_OP_EXISTSmake_stash_messagec                       \ rS rSrSrSrg)
StashErrorE   z$Base exception for stash operations. N)__name__
__module____qualname____firstlineno____doc____static_attributes__r       F/var/www/ias/venv/lib/python3.13/site-packages/gunicorn/dirty/stash.pyr   r   E   s    .r   r   c                   ,   ^  \ rS rSrSrU 4S jrSrU =r$ )StashTableNotFoundErrorI   z#Raised when a table does not exist.c                 6   > Xl         [        TU ]	  SU 35        g )NzStash table not found: )
table_namesuper__init__)selfr!   	__class__s     r   r#    StashTableNotFoundError.__init__L   s    $2:,?@r   )r!   r   r   r   r   r   r#   r   __classcell__r%   s   @r   r   r   I   s    -A Ar   r   c                   ,   ^  \ rS rSrSrU 4S jrSrU =r$ )StashKeyNotFoundErrorQ   z,Raised when a key does not exist in a table.c                 H   > Xl         X l        [        TU ]  SU SU 35        g )NzKey not found in z: )r!   keyr"   r#   )r$   r!   r.   r%   s      r   r#   StashKeyNotFoundError.__init__T   s(    $,ZL3%@Ar   )r.   r!   r'   r)   s   @r   r+   r+   Q   s    6B Br   r+   c                       \ rS rSrSrSS jrS rS rS rSS jr	S	 r
SS
 jrS rSS jrS rS rS rSS jrS rS rS rS rS rS rSrg)StashClientZ   z`
Client for stash operations.

Communicates with the arbiter which stores all tables in memory.
c                 ^    Xl         X l        SU l        [        R                  " 5       U l        g)z
Initialize the stash client.

Args:
    socket_path: Path to the dirty arbiter's Unix socket
    timeout: Default timeout for operations in seconds
N)socket_pathtimeout_sock	threadingLock_lock)r$   r4   r5   s      r   r#   StashClient.__init__a   s$     '
^^%
r   c                 >    [        [        R                  " 5       5      $ )zGenerate a unique request ID.)struuiduuid4r$   s    r   _get_request_idStashClient._get_request_idn   s    4::<  r   c                 |   SSK nU R                  b  g UR                  UR                  UR                  5      U l        U R                  R	                  U R
                  5        U R                  R                  U R                  5        g! UR                  [        4 a  nSU l        [        SU 35      UeSnAff = f)z Establish connection to arbiter.r   NzFailed to connect to arbiter: )socketr6   AF_UNIXSOCK_STREAM
settimeoutr5   connectr4   errorOSErrorr   )r$   rC   es      r   _connectStashClient._connectr   s    ::!	Jv~~v7I7IJDJJJ!!$,,/JJt//0g& 	JDJ=aSABI	Js   A5B
 
B; B66B;c                     U R                   b#   U R                   R                  5         SU l         gg! [         a     Nf = f)zClose the connection.N)r6   close	Exceptionr?   s    r   _closeStashClient._close   sC    ::!

  " DJ "  s   2 
??Nc           
      J   U R                      U R                  c  U R                  5         U R                  5       n[	        XaUX4US9n [
        R                  " U R                  U5        [
        R                  " U R                  5      nUR                  S5      n	U	[
        R                  :X  a  UR                  S5      sSSS5        $ U	[
        R                  :X  ac  UR                  S0 5      n
U
R                  SS5      nU
R                  SS	5      nUS
:X  a  [        U5      eUS:X  a  [        X#5      e[        U5      e[        SU	 35      e! [         a:  nU R                  5         [!        U[        5      (       a  e [        SU 35      UeSnAff = f! , (       d  f       g= f)z
Execute a stash operation.

Args:
    op: Operation code (STASH_OP_*)
    table: Table name
    key: Optional key
    value: Optional value
    pattern: Optional pattern for keys operation

Returns:
    Result from the operation
N)r.   valuepatterntyperesultrH   
error_typer   messagezUnknown errorr   r+   zUnexpected response type: zStash operation failed: )r9   r6   rK   r@   r   r   write_messageread_messagegetMSG_TYPE_RESPONSEMSG_TYPE_ERRORr   r+   r   rO   rP   
isinstance)r$   optabler.   rS   rT   
request_idrX   responsemsg_type
error_inforW   	error_msgrJ   s                 r   _executeStashClient._execute   sk    ZZzz!--/J(gG
H++DJJ@(55djjA#<</}>>>#<<1! Z" !=!==!)gr!:J!+l!KJ *y/ JI!%>>5e<<!%<<3E??$Y//$'A(%LMM Ha,, #;A3!?@aG	H= Zs1   :FA6EBE
F5FFF
F"c                 .    U R                  [        XUS9  g)z
Store a value in a table.

The table is automatically created if it doesn't exist.

Args:
    table: Table name
    key: Key to store under
    value: Value to store (must be serializable)
)r.   rS   N)rf   r   )r$   r`   r.   rS   s       r   putStashClient.put   s     	lE%@r   c                 P     U R                  [        XS9$ ! [         a    Us $ f = f)z
Retrieve a value from a table.

Args:
    table: Table name
    key: Key to retrieve
    default: Default value if key not found

Returns:
    The stored value, or default if not found
r.   )rf   r   r+   )r$   r`   r.   defaults       r   r[   StashClient.get   s.    	==u=>>$ 	N	s    %%c                 *    U R                  [        XS9$ )z
Delete a key from a table.

Args:
    table: Table name
    key: Key to delete

Returns:
    True if key was deleted, False if it didn't exist
rl   )rf   r   r$   r`   r.   s      r   deleteStashClient.delete        }}_e}==r   c                 *    U R                  [        XS9$ )z
Get all keys in a table, optionally filtered by pattern.

Args:
    table: Table name
    pattern: Optional glob pattern (e.g., "user:*")

Returns:
    List of keys
rT   )rf   r	   )r$   r`   rT   s      r   keysStashClient.keys   s     }}]E}CCr   c                 0    U R                  [        U5        g)z=
Delete all entries in a table.

Args:
    table: Table name
N)rf   r
   r$   r`   s     r   clearStashClient.clear   s     	ne,r   c                 .    U R                  [        U5      $ )zm
Get information about a table.

Args:
    table: Table name

Returns:
    Dict with table info (size, etc.)
)rf   r   ry   s     r   infoStashClient.info   s     }}]E22r   c                 0    U R                  [        U5        g)z
Ensure a table exists (create if not exists).

This is idempotent - calling it multiple times is safe.

Args:
    table: Table name
N)rf   r   ry   s     r   ensureStashClient.ensure  s     	ou-r   c                 *    U R                  [        XS9$ )z
Check if a table or key exists.

Args:
    table: Table name
    key: Optional key to check within the table

Returns:
    True if exists, False otherwise
rl   )rf   r   rp   s      r   existsStashClient.exists  rs   r   c                 0    U R                  [        U5        g)z6
Delete an entire table.

Args:
    table: Table name
N)rf   r   ry   s     r   delete_tableStashClient.delete_table$  s     	+U3r   c                 .    U R                  [        S5      $ )z4
List all tables.

Returns:
    List of table names
 )rf   r   r?   s    r   tablesStashClient.tables-  s     }}_b11r   c                     [        X5      $ )ze
Get a dict-like interface to a table.

Args:
    name: Table name

Returns:
    StashTable instance
)
StashTable)r$   names     r   r`   StashClient.table6  s     $%%r   c                 p    U R                      U R                  5         SSS5        g! , (       d  f       g= f)zClose the client connection.N)r9   rP   r?   s    r   rN   StashClient.closeB  s    ZZKKM ZZs   '
5c                     U $ Nr   r?   s    r   	__enter__StashClient.__enter__G  s    r   c                 $    U R                  5         g r   )rN   )r$   exc_typeexc_valexc_tbs       r   __exit__StashClient.__exit__J  s    

r   )r9   r6   r4   r5   )g      >@)NNNr   )r   r   r   r   r   r#   r@   rK   rP   rf   ri   r[   rq   rv   rz   r}   r   r   r   r   r`   rN   r   r   r   r   r   r   r1   r1   Z   sk    &!J0HlA">D-
3	.>42
&
r   r1   c                   x    \ rS rSrSrS r\S 5       rS rS r	S r
S rS	 rS
 rSS jrSS jrS rS rS rSrg)r   iN  a
  
Dict-like interface to a stash table.

Example::

    sessions = stash.table("sessions")
    sessions["user:1"] = {"name": "Alice"}
    user = sessions["user:1"]
    del sessions["user:1"]

    # Iteration
    for key in sessions:
        print(key, sessions[key])
c                     Xl         X l        g r   _client_name)r$   clientr   s      r   r#   StashTable.__init__^  s    
r   c                     U R                   $ )zTable name.)r   r?   s    r   r   StashTable.nameb  s     zzr   c                     U R                   R                  U R                  U5      nUc6  U R                   R                  U R                  U5      (       d  [	        U5      eU$ r   )r   r[   r   r   KeyError)r$   r.   rV   s      r   __getitem__StashTable.__getitem__g  sK    !!$**c2><<&&tzz377sm#r   c                 P    U R                   R                  U R                  X5        g r   )r   ri   r   )r$   r.   rS   s      r   __setitem__StashTable.__setitem__o  s    S0r   c                 p    U R                   R                  U R                  U5      (       d  [        U5      eg r   )r   rq   r   r   r$   r.   s     r   __delitem__StashTable.__delitem__r  s,    ||""4::s333- 4r   c                 N    U R                   R                  U R                  U5      $ r   )r   r   r   r   s     r   __contains__StashTable.__contains__v  s    ||""4::s33r   c                 ^    [        U R                  R                  U R                  5      5      $ r   )iterr   rv   r   r?   s    r   __iter__StashTable.__iter__y  s     DLL%%djj122r   c                 p    U R                   R                  U R                  5      nUR                  SS5      $ )Nsizer   )r   r}   r   r[   )r$   r}   s     r   __len__StashTable.__len__|  s+    ||  ,xx""r   Nc                 N    U R                   R                  U R                  X5      $ )zGet value with default.)r   r[   r   )r$   r.   rm   s      r   r[   StashTable.get  s    ||

C99r   c                 J    U R                   R                  U R                  US9$ )z-Get all keys, optionally filtered by pattern.ru   )r   rv   r   )r$   rT   s     r   rv   StashTable.keys  s     ||  W ==r   c                 N    U R                   R                  U R                  5        g)zDelete all entries.N)r   rz   r   r?   s    r   rz   StashTable.clear  s    4::&r   c              #      #    U R                   R                  U R                  5       H,  nXR                   R                  U R                  U5      4v   M.     g7f)z Iterate over (key, value) pairs.Nr   rv   r   r[   r   s     r   itemsStashTable.items  s@     <<$$TZZ0C||''

C888 1s   AAc              #      #    U R                   R                  U R                  5       H+  nU R                   R                  U R                  U5      v   M-     g7f)zIterate over values.Nr   r   s     r   valuesStashTable.values  s=     <<$$TZZ0C,,""4::s33 1s   AAr   r   )r   r   r   r   r   r#   propertyr   r   r   r   r   r   r   r[   rv   rz   r   r   r   r   r   r   r   r   N  sW      1 43#:>'9
4r   r   c                     U q g)z@Set the global stash socket path (called during initialization).N)_stash_socket_path)paths    r   set_stash_socket_pathr     s
     r   c                      SSK n [        c/  U R                  R                  S5      nU(       a  U$ [	        S5      e[        $ )zGet the stash socket path.r   NGUNICORN_DIRTY_SOCKETz\Stash socket path not configured. Make sure dirty_workers > 0 and dirty_apps are configured.)osr   environr[   r   )r   r   s     r   get_stash_socket_pathr     sA    !zz~~56KI
 	
 r   c                  n    [        [        SS5      n U c   [        5       n[        U5      n U [        l        U $ )z*Get or create a thread-local stash client.stash_clientN)getattr_thread_localr   r1   r   )r   r4   s     r   _get_clientr     s4    ]ND9F~+-[)%+"Mr   c                 8    [        5       R                  XU5        g)zStore a value in a table.N)r   ri   )r`   r.   rS   s      r   ri   ri     s    Me%(r   c                 6    [        5       R                  XU5      $ )zRetrieve a value from a table.)r   r[   )r`   r.   rm   s      r   r[   r[     s    =U11r   c                 4    [        5       R                  X5      $ )zDelete a key from a table.)r   rq   r`   r.   s     r   rq   rq         =++r   c                 4    [        5       R                  X5      $ )zGet all keys in a table.)r   rv   )r`   rT   s     r   rv   rv     s    =e--r   c                 6    [        5       R                  U 5        g)zDelete all entries in a table.N)r   rz   r`   s    r   rz   rz     s    Mr   c                 4    [        5       R                  U 5      $ )zGet information about a table.)r   r}   r   s    r   r}   r}     s    =e$$r   c                 6    [        5       R                  U 5        g)zEnsure a table exists.N)r   r   r   s    r   r   r     s    Mr   c                 4    [        5       R                  X5      $ )zCheck if a table or key exists.)r   r   r   s     r   r   r     r   r   c                 6    [        5       R                  U 5        g)zDelete an entire table.N)r   r   r   s    r   r   r     s    Mu%r   c                  2    [        5       R                  5       $ )zList all tables.)r   r   r   r   r   r   r     s    =!!r   c                 4    [        5       R                  U 5      $ )z%Get a dict-like interface to a table.)r   r`   )r   s    r   r`   r`     s    =t$$r   r   )(r   r7   r=   errorsr   protocolr   r   r   r   r	   r
   r   r   r   r   r   r   r   r   r+   r1   r   localr   r   r   r   r   ri   r[   rq   rv   rz   r}   r   r   r   r   r`   r   r   r   <module>r      s   
*X       / /Aj ABJ Bq qhF4 F4\ !  )
2
,
.

%
 
,
&
"
%r   