@@ -403,3 +403,97 @@ def _send(self) -> None:
403
403
self ._send_headers ()
404
404
self ._close_connection ()
405
405
406
+
407
+ class SSEResponse (Response ): # pylint: disable=too-few-public-methods
408
+ """
409
+ Specialized version of `Response` class for sending Server-Sent Events.
410
+
411
+ Allows one way communication with the client using a persistent connection.
412
+
413
+ Keep in mind, that in order to send events, the socket must be kept open. This means that you
414
+ have to store the response object somewhere, so you can send events to it and close it later.
415
+
416
+ **It is very important to close the connection manually, it will not be done automatically.**
417
+
418
+ Example::
419
+
420
+ sse = None
421
+
422
+ @server.route(path, method)
423
+ def route_func(request: Request):
424
+
425
+ # Store the response object somewhere in global scope
426
+ global sse
427
+ sse = SSEResponse(request)
428
+
429
+ return sse
430
+
431
+ ...
432
+
433
+ # Later, when you want to send an event
434
+ sse.send_event("Simple message")
435
+ sse.send_event("Message", event="event_name", id=1, retry=5000)
436
+
437
+ # Close the connection
438
+ sse.close()
439
+ """
440
+
441
+ def __init__ ( # pylint: disable=too-many-arguments
442
+ self ,
443
+ request : Request ,
444
+ headers : Union [Headers , Dict [str , str ]] = None ,
445
+ ) -> None :
446
+ """
447
+ :param Request request: Request object
448
+ :param Headers headers: Headers to be sent with the response.
449
+ """
450
+ super ().__init__ (
451
+ request = request ,
452
+ headers = headers ,
453
+ content_type = "text/event-stream" ,
454
+ )
455
+ self ._headers .setdefault ("Cache-Control" , "no-cache" )
456
+ self ._headers .setdefault ("Connection" , "keep-alive" )
457
+
458
+ def _send (self ) -> None :
459
+ self ._send_headers ()
460
+
461
+ def send_event ( # pylint: disable=too-many-arguments
462
+ self ,
463
+ data : str ,
464
+ event : str = None ,
465
+ id : int = None , # pylint: disable=redefined-builtin,invalid-name
466
+ retry : int = None ,
467
+ custom_fields : Dict [str , str ] = None ,
468
+ ) -> None :
469
+ """
470
+ Send event to the client.
471
+
472
+ :param str data: The data to be sent.
473
+ :param str event: (Optional) The name of the event.
474
+ :param int id: (Optional) The event ID.
475
+ :param int retry: (Optional) The time (in milliseconds) to wait before retrying the event.
476
+ :param Dict[str, str] custom_fields: (Optional) Custom fields to be sent with the event.
477
+ """
478
+ message = f"data: { data } \n "
479
+ if event :
480
+ message += f"event: { event } \n "
481
+ if id :
482
+ message += f"id: { id } \n "
483
+ if retry :
484
+ message += f"retry: { retry } \n "
485
+ if custom_fields :
486
+ for field , value in custom_fields .items ():
487
+ message += f"{ field } : { value } \n "
488
+ message += "\n "
489
+
490
+ self ._send_bytes (self ._request .connection , message .encode ("utf-8" ))
491
+
492
+ def close (self ):
493
+ """
494
+ Close the connection.
495
+
496
+ **Always call this method when you are done sending events.**
497
+ """
498
+ self ._send_bytes (self ._request .connection , b"event: close\n " )
499
+ self ._close_connection ()
0 commit comments