
    kKj                        d Z 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
 ddlmZmZmZmZ ddlmZ dd	lmZ dd
lmZ ddlmZ  ee      Z G d de      Z G d de      Z G d de      Z G d de      Zy)ay  EventStore implementation backed by AsyncKeyValue.

This module provides an EventStore implementation that enables SSE polling/resumability
for Streamable HTTP transports. Events are stored using the key_value package's
AsyncKeyValue protocol, allowing users to configure any compatible backend
(in-memory, Redis, etc.) following the same pattern as ResponseCachingMiddleware.
    )annotations)uuid4)PydanticAdapter)AsyncKeyValue)MemoryStore)EventCallbackEventIdEventMessageStreamId)
EventStore)JSONRPCMessage)
get_logger)FastMCPBaseModelc                  0    e Zd ZU dZded<   ded<   ded<   y)
EventEntryzStored event entry.strevent_id	stream_idzdict | NonemessageN__name__
__module____qualname____doc____annotations__     k/Users/ahmed/devFolder/Ultron/claude-voice/.venv/lib/python3.12/site-packages/fastmcp/server/event_store.pyr   r      s    MNr   r   c                      e Zd ZU dZded<   y)StreamEventListzList of event IDs for a stream.z	list[str]	event_idsNr   r   r   r   r    r    "   s    )r   r    c                  P    e Zd ZdZddZd	dZd
dZ	 	 	 	 	 	 ddZ	 	 	 	 	 	 ddZy)SessionScopedEventStorezEEventStore adapter that isolates stream IDs to one transport session.c                >    || _         t        |       d| d| _        y )N:)_event_storelen_stream_prefix)selfevent_store
session_ids      r   __init__z SessionScopedEventStore.__init__+   s$    '!$Z 1:,a@r   c                "    | j                    | S N)r(   r)   r   s     r   _scope_stream_idz(SessionScopedEventStore._scope_stream_id/   s    %%&yk22r   c                j    |j                  | j                        sy |t        | j                        d  S r.   )
startswithr(   r'   r/   s     r   _unscope_stream_idz*SessionScopedEventStore._unscope_stream_id2   s2    ##D$7$78T001344r   c                t   K   | j                   j                  | j                  |      |       d {   S 7 wr.   )r&   store_eventr0   )r)   r   r   s      r   r5   z#SessionScopedEventStore.store_event7   s;      &&22!!),g
 
 	
 
s   /868c                   K   g dfd}| j                   j                  ||       d {   }|y | j                  |      }|t        j	                  d|       y D ]  } ||       d {     |S 7 J7 
w)Nc                0   K   j                  |        y wr.   )append)eventreplayed_eventss    r   buffer_eventzASessionScopedEventStore.replay_events_after.<locals>.buffer_eventE   s     ""5)s   z>Event ID %s does not belong to this session-scoped event store)r9   r
   returnNone)r&   replay_events_afterr3   loggerwarning)r)   last_event_idsend_callbackr;   scoped_stream_idr   r9   r:   s          @r   r>   z+SessionScopedEventStore.replay_events_after>   s     
 /1	* "&!2!2!F!F<"
 
 #++,<=	NNP $E&&& % #
 's"   (A:A6AA:-A8.	A:8A:N)r*   SDKEventStorer+   r   )r   r   r<   r   )r   r   r<   StreamId | Noner   r   r   zJSONRPCMessage | Noner<   r	   rA   r	   rB   r   r<   rE   )	r   r   r   r   r,   r0   r3   r5   r>   r   r   r   r#   r#   (   sS    OA35

!
,A
	
 % 
	r   r#   c                  R    e Zd ZdZ	 	 	 d	 	 	 	 	 ddZ	 	 	 	 	 	 ddZ	 	 	 	 	 	 d	dZy)
r   a-  EventStore implementation backed by AsyncKeyValue.

    Enables SSE polling/resumability by storing events that can be replayed
    when clients reconnect. Works with any AsyncKeyValue backend (memory, Redis, etc.)
    following the same pattern as ResponseCachingMiddleware and OAuthProxy.

    Example:
        ```python
        from fastmcp import FastMCP
        from fastmcp.server.event_store import EventStore

        # Default in-memory storage
        event_store = EventStore()

        # Or with a custom backend
        from key_value.aio.stores.redis import RedisStore
        redis_backend = RedisStore(url="redis://localhost")
        event_store = EventStore(storage=redis_backend)

        mcp = FastMCP("MyServer")
        app = mcp.http_app(event_store=event_store, retry_interval=2000)
        ```

    Args:
        storage: AsyncKeyValue backend. Defaults to MemoryStore.
        max_events_per_stream: Maximum events to retain per stream. Default 100.
        ttl: Event TTL in seconds. Default 3600 (1 hour). Set to None for no expiration.
    Nc                    |xs
 t               | _        || _        || _        t	        t
           | j                  t
        d      | _        t	        t           | j                  t        d      | _        y )Nfastmcp_events)	key_valuepydantic_modeldefault_collectionfastmcp_streams)	r   _storage_max_events_per_stream_ttlr   r   r&   r    _stream_store)r)   storagemax_events_per_streamttls       r   r,   zEventStore.__init__z   sm     (/'?+-&;#	 :I9Tmm%/:

 @O@
 mm*0@
r   c                  K   t        t                     }t        |||r|j                  d      nd      }| j                  j                  ||| j                         d{    | j                  j                  |       d{   }|r|j                  ng }|j                  |       t        |      | j                  kD  rI|d| j                    D ]&  }| j                  j                  |       d{    ( || j                   d }| j                  j                  |t        |      | j                         d{    |S 7 7 7 V7 w)a  Store an event and return its ID.

        Args:
            stream_id: ID of the stream the event belongs to
            message: The JSON-RPC message to store, or None for priming events

        Returns:
            The generated event ID for the stored event
        json)modeN)r   r   r   )keyvaluerU   rY   )r!   )r   r   r   
model_dumpr&   putrQ   rR   getr!   r8   r'   rP   deleter    )r)   r   r   r   entrystream_datar!   old_ids           r   r5   zEventStore.store_event   sT     uw< 7>G&&F&3D

 ##499#MMM !..22y2AA-8K))b	" y>D777#$Bt'B'B&BC''..6.::: D!4#>#>">"@AI  $$!I6		 % 
 	
 	
 ' 	N B ;	
sJ   A!E#E
$#EEA/E7E8AEEEEEEc                  K   | j                   j                  |       d{   }|st        j                  d| d       y|j                  }| j
                  j                  |       d{   }|st        j                  d| d       y|j                  }	 |j                  |      dz   }||d D ]y  }| j                   j                  |       d{   }	|	s*|	j                  s7t        j                  |	j                        }
 |t        |
|	j                               d{    { |S 7 7 # t        $ r t        j                  d| d|        Y yw xY w7 7 9w)aO  Replay events that occurred after the specified event ID.

        Args:
            last_event_id: The ID of the last event the client received
            send_callback: A callback function to send events to the client

        Returns:
            The stream ID of the replayed events, or None if the event ID was not found
        r[   Nz	Event ID z not found in storezStream    z not found in stream )r&   r^   r?   r@   r   rR   r!   index
ValueErrorr   r   model_validater
   r   )r)   rA   rB   r`   r   ra   r!   	start_idxr   r9   msgs              r   r>   zEventStore.replay_events_after   sW     ''+++>>NNY}o5HIJOO	 ..22y2AANNWYK/BCD))		!6:I ")*-H++//H/==E$33EMMB#Lenn$EFFF	 . 7 ? B  	NNY}o5J9+VW	 > Gsp    E&D3AE&.D6/,E&D8 0'E&E"E&E&,>E&*E$+	E&6E&8$EE&EE&$E&)Nd   i  )rS   zAsyncKeyValue | NonerT   intrU   z
int | NonerF   rG   )r   r   r   r   r,   r5   r>   r   r   r   r   r   \   sr    > )-%(	
%
  #
 	
0'!',A'	'R** %* 
	*r   r   N)r   
__future__r   uuidr   key_value.aio.adapters.pydanticr   key_value.aio.protocolsr   key_value.aio.stores.memoryr   mcp.server.streamable_httpr   r	   r
   r   r   rD   	mcp.typesr   fastmcp.utilities.loggingr   fastmcp.utilities.typesr   r   r?   r   r    r#   r   r   r   <module>ru      sl    #  ; 1 3 U U B $ 0 4	H	! & 1m 1hI Ir   