@@ -357,16 +357,17 @@ async def fetch_relayed_messages(
357357# soon as they arrive instead of waiting to be picked up with the pickup
358358# protocol.
359359
360- # TODO add comments to the below code segments and tidy it up
361-
360+ # Because the quickstart can be used without using websockets or connecting to
361+ # an inbound relay/mediator. If we don't have the necessary libraries, we can
362+ # just raise a warning about the lack of support.
362363try :
363364 import websockets
364365 import asyncio
365366except ImportError :
366367 import warnings
367368
368369 warnings .warn (
369- "Missing websockets or asyncio import, live-delivery will be unavailable" ,
370+ "Missing websockets or asyncio import, live-delivery support will be unavailable" ,
370371 ImportWarning ,
371372 )
372373
@@ -379,25 +380,44 @@ async def handle_websocket(
379380 callback : Callable [[Dict [str , Any ]], Awaitable [None ]] = _message_callback ,
380381):
381382 """Loop over messages received and process them."""
383+
384+ # Using async with on the websocket allows us to wait for then loop over
385+ # new messages that come in over the websocket.
382386 async with mediator_websocket as websocket :
387+ # Send our live-delivery request to the inbound relay.
383388 await websocket .send (live_delivery_message )
384- LOG .debug ("Connected to WebSocket and requested Live Delivery!" )
389+ LOG .debug ("Connected to WebSocket and requested Live Delivery." )
390+
391+ # Loop over all incoming messages
385392 while True :
386393 message = await websocket .recv ()
387394 LOG .debug ("Received message over websocket" )
388395
389396 try :
397+ # Unpack/Decrypt the message, decode it, and load the JSON into
398+ # a native python object.
390399 unpacked_message , metadata = await dmp .packaging .unpack (message )
391400 msg = unpacked_message .decode ()
392401 msg = json .loads (msg )
393402 LOG .debug ("Received websocket message %s" , msg ["type" ])
403+
404+ # If the message is not from the relay, process it via the callback
394405 if msg ["from" ] != relay_did :
395406 await callback (msg )
396407
408+ # NOTE: While out of scope for this example, when implementing
409+ # your own handler, it's advisable to handle messages that come
410+ # from the relay. For example: the relay will respond to the
411+ # live-delivery call with a pickup protocol status message. The
412+ # status message may contain a message count that is greater
413+ # than zero. If there are messages that are waiting, it is
414+ # advisable to request the messages and process them.
415+
397416 except Exception as err :
398417 LOG .error ("Error encountered while decrypting websocket message" )
399418 LOG .exception (err )
400419
420+ # Clean up the websocket
401421 await websocket .close ()
402422
403423
@@ -410,6 +430,7 @@ async def activate_websocket(
410430) -> Union [Awaitable [None ], "asyncio.Task" ]:
411431 """Connect to a websocket and request message forwarding."""
412432
433+ # Construct a message to request live-delivery and pack it
413434 message = {
414435 "type" : "https://didcomm.org/messagepickup/3.0/live-delivery-change" ,
415436 "id" : str (uuid .uuid4 ()),
@@ -424,10 +445,14 @@ async def activate_websocket(
424445 to = relay_did ,
425446 frm = my_did ,
426447 )
448+
449+ # Get the websocket endpoint from the packed message. This will pull out
450+ # the endpoint that is closest to us, the sender.
427451 endpoint = packed .get_endpoint ("ws" )
428- LOG .info ("Relay Websocket Address: %s" , endpoint )
452+ LOG .debug ("Relay Websocket Address: %s" , endpoint )
453+
429454 if endpoint :
430- LOG . info ( "Found Relay websocket, connecting" )
455+ # Connect to the websocket and prepare our handler function
431456 mediator_websocket = websockets .connect (uri = endpoint )
432457 websocket_handler = handle_websocket (
433458 dmp ,
@@ -436,6 +461,9 @@ async def activate_websocket(
436461 packed .message ,
437462 callback ,
438463 )
464+
465+ # Create an asyncio task upon request to run in another async "thread",
466+ # otherwise we'll just return the function that runs in the thread.
439467 if create_task :
440468 return asyncio .create_task (websocket_handler )
441469 else :
@@ -450,17 +478,19 @@ async def websocket_loop(
450478) -> None :
451479 """Run the websocket handler in a task and reconnect on failure."""
452480
481+ # Helper method to create the async task
453482 async def create_task ():
454483 return await activate_websocket (dmp , my_did , relay_did , callback , True )
455484
485+ # Create the initial task
456486 mediator_websocket_proc = await create_task ()
457487
488+ # Check to make sure the thread is still running every 5 seconds (to give
489+ # the OS some breathing room). Should the thread "crash" or exit for any
490+ # reason, log any exceptions and attempt to restart it.
458491 while True :
459492 await asyncio .sleep (5 )
460493 if mediator_websocket_proc .done ():
461494 LOG .exception (mediator_websocket_proc .exception ())
462- try :
463- LOG .error ("Websocket died, re-establishing connection!" )
464- except Exception :
465- pass
495+ LOG .error ("Websocket died, re-establishing connection!" )
466496 mediator_websocket_proc = await create_task ()
0 commit comments