55import asyncio
66import json
77import logging
8+ from collections import deque
89from hashlib import sha1
910from typing import Any , Awaitable , Callable , Dict , Optional
1011
2930DEFAULT_HOST = "0.0.0.0"
3031DEFAULT_PORT = 8646
3132DEFAULT_WEBHOOK_PATH = "/msgraph/webhook"
33+ DEFAULT_MAX_SEEN_RECEIPTS = 5000
3234NotificationScheduler = Callable [[Dict [str , Any ], MessageEvent ], Awaitable [None ] | None ]
3335
3436
@@ -55,9 +57,13 @@ def __init__(self, config: PlatformConfig):
5557 if str (value ).strip ()
5658 ]
5759 self ._client_state : Optional [str ] = self ._string_or_none (extra .get ("client_state" ))
60+ self ._max_seen_receipts = max (
61+ 1 , int (extra .get ("max_seen_receipts" , DEFAULT_MAX_SEEN_RECEIPTS ))
62+ )
5863 self ._runner = None
5964 self ._notification_scheduler : Optional [NotificationScheduler ] = None
6065 self ._seen_receipts : set [str ] = set ()
66+ self ._seen_receipt_order : deque [str ] = deque ()
6167 self ._accepted_count = 0
6268 self ._duplicate_count = 0
6369
@@ -172,10 +178,10 @@ async def _handle_notification(self, request: "web.Request") -> "web.Response":
172178 continue
173179
174180 receipt_key = self ._build_receipt_key (notification )
175- if receipt_key in self ._seen_receipts :
181+ if self ._has_seen_receipt ( receipt_key ) :
176182 duplicates += 1
177183 continue
178- self ._seen_receipts . add (receipt_key )
184+ self ._remember_receipt (receipt_key )
179185
180186 accepted += 1
181187 scheduled += 1
@@ -213,6 +219,16 @@ def _verify_client_state(self, notification: Dict[str, Any]) -> bool:
213219 provided = self ._string_or_none (notification .get ("clientState" ))
214220 return provided == expected
215221
222+ def _has_seen_receipt (self , receipt_key : str ) -> bool :
223+ return receipt_key in self ._seen_receipts
224+
225+ def _remember_receipt (self , receipt_key : str ) -> None :
226+ self ._seen_receipts .add (receipt_key )
227+ self ._seen_receipt_order .append (receipt_key )
228+ while len (self ._seen_receipt_order ) > self ._max_seen_receipts :
229+ oldest = self ._seen_receipt_order .popleft ()
230+ self ._seen_receipts .discard (oldest )
231+
216232 def _build_message_event (
217233 self ,
218234 notification : Dict [str , Any ],
0 commit comments