98 lines
2.8 KiB
Python
Raw Normal View History

2024-08-01 11:07:52 +09:00
from __future__ import annotations
import abc
from typing import Generic, TypeVar
2024-08-01 11:07:52 +09:00
from framework import Framework, Queue
2024-08-07 22:36:21 +09:00
from protocol.temporalmix import TemporalMix, TemporalMixConfig
2024-08-01 11:07:52 +09:00
T = TypeVar("T")
2024-08-01 11:07:52 +09:00
class SimplexConnection(abc.ABC, Generic[T]):
2024-08-01 11:07:52 +09:00
"""
An abstract class for a simplex connection that can send and receive data in one direction
"""
@abc.abstractmethod
async def send(self, data: T) -> None:
2024-08-01 11:07:52 +09:00
pass
@abc.abstractmethod
async def recv(self) -> T:
2024-08-01 11:07:52 +09:00
pass
class LocalSimplexConnection(SimplexConnection[T]):
2024-08-01 11:07:52 +09:00
"""
A simplex connection that doesn't have any network latency.
Data sent through this connection can be immediately received from the other end.
"""
def __init__(self, framework: Framework):
self.queue: Queue[T] = framework.queue()
2024-08-01 11:07:52 +09:00
async def send(self, data: T) -> None:
2024-08-01 11:07:52 +09:00
await self.queue.put(data)
async def recv(self) -> T:
2024-08-01 11:07:52 +09:00
return await self.queue.get()
class DuplexConnection(Generic[T]):
2024-08-01 11:07:52 +09:00
"""
A duplex connection in which data can be transmitted and received simultaneously in both directions.
This is to mimic duplex communication in a real network (such as TCP or QUIC).
"""
def __init__(self, inbound: SimplexConnection[T], outbound: SimplexConnection[T]):
2024-08-01 11:07:52 +09:00
self.inbound = inbound
self.outbound = outbound
async def recv(self) -> T:
2024-08-01 11:07:52 +09:00
return await self.inbound.recv()
async def send(self, packet: T):
2024-08-01 11:07:52 +09:00
await self.outbound.send(packet)
class MixSimplexConnection(SimplexConnection[T]):
2024-08-01 11:07:52 +09:00
"""
Wraps a SimplexConnection to add a transmission rate and noise to the connection.
"""
def __init__(
self,
framework: Framework,
conn: SimplexConnection[T],
2024-08-01 11:07:52 +09:00
transmission_rate_per_sec: int,
noise_msg: T,
2024-08-01 11:07:52 +09:00
temporal_mix_config: TemporalMixConfig,
2024-07-24 15:35:41 +09:00
# OPTIMIZATION ONLY FOR EXPERIMENTS WITHOUT BANDWIDTH MEASUREMENT
# If True, skip sending a noise even if it's time to send one.
skip_sending_noise: bool,
2024-08-01 11:07:52 +09:00
):
self.framework = framework
self.queue: Queue[T] = TemporalMix.queue(
2024-08-01 11:07:52 +09:00
temporal_mix_config, framework, noise_msg
)
self.conn = conn
self.transmission_rate_per_sec = transmission_rate_per_sec
2024-07-24 15:35:41 +09:00
self.noise_msg = noise_msg
self.skip_sending_noise = skip_sending_noise
2024-08-01 11:07:52 +09:00
self.task = framework.spawn(self.__run())
async def __run(self):
while True:
await self.framework.sleep(1 / self.transmission_rate_per_sec)
msg = await self.queue.get()
2024-07-24 15:35:41 +09:00
if self.skip_sending_noise and msg == self.noise_msg:
continue
2024-08-01 11:07:52 +09:00
await self.conn.send(msg)
async def send(self, data: T) -> None:
2024-08-01 11:07:52 +09:00
await self.queue.put(data)
async def recv(self) -> T:
2024-08-01 11:07:52 +09:00
return await self.conn.recv()