
    Ki                        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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)	BaseModel)
get_loggerc                  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__     f/home/jay/workspace/scripts/.codegraph-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                  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   _event_storer    _stream_store)selfstoragemax_events_per_streamttls       r   __init__zEventStore.__init__F   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valuer1   r6   )r!   )r   r   r   
model_dumpr,   putr+   r-   getr!   appendlenr*   deleter    )r.   r   r   r   entrystream_datar!   old_ids           r   store_eventzEventStore.store_event^   sX     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.:::;!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
        r8   Nz	Event ID z not found in storezStream    z not found in stream )r,   r;   loggerwarningr   r-   r!   index
ValueErrorr   r   model_validater
   r   )r.   last_event_idsend_callbackr?   r   r@   r!   	start_idxr   eventmsgs              r   replay_events_afterzEventStore.replay_events_after   s^     ''+++>>NNY}o5HIJOO	 ..22y2AANNWYK/BCD))		!6:I ")*- 	GH++//H/==E$33EMMB#Lenn$EFFF		G 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  )r/   zAsyncKeyValue | Noner0   intr1   z
int | None)r   r   r   zJSONRPCMessage | Nonereturnr	   )rJ   r	   rK   r   rR   zStreamId | None)r   r   r   r   r2   rB   rO   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   SDKEventStore	mcp.typesr   pydanticr   fastmcp.utilities.loggingr   r   rE   r   r    r   r   r   <module>r]      s]    #  ; 1 3 U U B $  0	H	 i I Ir   