Pipeline handshaking by sending protocols before hearing back

This commit is contained in:
Brian Cloutier 2019-09-08 11:55:28 -07:00
parent f38899e26e
commit 5fd4d24fe8
2 changed files with 44 additions and 17 deletions

View File

@ -2,7 +2,6 @@ import asyncio
from .raw_connection_interface import IRawConnection
class RawConnection(IRawConnection):
reader: asyncio.StreamReader
writer: asyncio.StreamWriter

View File

@ -16,7 +16,7 @@ class MultiselectClient(IMultiselectClient):
module in order to select a protocol id to communicate over
"""
async def handshake(self, communicator: IMultiselectCommunicator) -> None:
async def _handshake(self, communicator: IMultiselectCommunicator) -> None:
"""
Ensure that the client and multiselect
are both using the same multiselect protocol
@ -48,13 +48,28 @@ class MultiselectClient(IMultiselectClient):
:param stream: stream to communicate with multiselect over
:return: selected protocol
"""
# Perform handshake to ensure multiselect protocol IDs match
await self.handshake(communicator)
# Send our MULTISELECT_PROTOCOL_ID to counterparty
await communicator.write(MULTISELECT_PROTOCOL_ID)
# Try to select the given protocol
selected_protocol = await self.try_select(communicator, protocol)
# Tell counterparty we want to use protocol
await communicator.write(protocol)
return selected_protocol
# Read in the protocol ID from other party
handshake_contents = await communicator.read()
# Confirm that the protocols are the same
if not validate_handshake(handshake_contents):
raise MultiselectClientError("multiselect protocol ID mismatch")
# Get what counterparty says in response
response = await communicator.read()
# Return protocol if response is equal to protocol or raise error
if response == protocol:
return protocol
if response == PROTOCOL_NOT_FOUND_MSG:
raise MultiselectClientError("protocol not supported")
raise MultiselectClientError("unrecognized response: " + response)
async def select_one_of(
self, protocols: Sequence[TProtocol], communicator: IMultiselectCommunicator
@ -67,22 +82,35 @@ class MultiselectClient(IMultiselectClient):
:param stream: stream to communicate with multiselect over
:return: selected protocol
"""
# Perform handshake to ensure multiselect protocol IDs match
await self.handshake(communicator)
# Send our MULTISELECT_PROTOCOL_ID to counterparty
await communicator.write(MULTISELECT_PROTOCOL_ID)
# For each protocol, attempt to select that protocol
# and return the first protocol selected
for protocol in protocols:
try:
selected_protocol = await self.try_select(communicator, protocol)
return selected_protocol
except MultiselectClientError:
pass
# Tell counterparty we want to use protocol
await communicator.write(protocol)
# Read in the protocol ID from other party
handshake_contents = await communicator.read()
# Confirm that the protocols are the same
if not validate_handshake(handshake_contents):
raise MultiselectClientError("multiselect protocol ID mismatch")
for protocol in protocols:
# Get what counterparty says in response
response = await communicator.read()
if response == protocol:
# somehow ignore the other messages before returning?
return protocol
if response == PROTOCOL_NOT_FOUND_MSG:
continue
continue
# No protocols were found, so return no protocols supported error
raise MultiselectClientError("protocols not supported")
async def try_select(
async def _try_select(
self, communicator: IMultiselectCommunicator, protocol: TProtocol
) -> TProtocol:
"""