Implement rewind/fast-forward system

This commit is contained in:
Joscha 2018-07-27 22:49:13 +00:00
parent 7e28c6e3dd
commit 55798a5b88

View file

@ -19,6 +19,7 @@ class Room:
CONNECTED = 1
DISCONNECTED = 2
CLOSED = 3
FORWARDING = 4
def __init__(self, inhabitant, roomname, nick, password=None, human=False, cookiejar=None):
# TODO: Connect to room etc.
@ -48,6 +49,10 @@ class Room:
self._status = Room.DISCONNECTED
self._connected_future = asyncio.Future()
self._last_known_mid = None
self._forwarding = None # task that downloads messages and fowards
self._forward_new = [] # new messages received while downloading old messages
# TODO: Allow for all parameters of Connection() to be specified in Room().
self._connection = Connection(
self.format_room_url(self.roomname, human=self.human),
@ -78,15 +83,16 @@ class Room:
return Message.from_dict(data)
async def log(self, n, before_mid=None):
# The log returned is sorted from old to new
async def log(self, n, before=None):
if self._status == Room.CLOSED:
raise RoomClosed()
if before_mid:
if before:
ptype, data, error, throttled = await self._send_while_connected(
"log",
n=n,
before=before_mid
before=before
)
else:
ptype, data, error, throttled = await self._send_while_connected(
@ -128,12 +134,12 @@ class Room:
to_nick = data.get("to_nick")
return pm_id, to_nick
async def send(self, content, parent_mid=None):
if parent_mid:
async def send(self, content, parent=None):
if parent:
ptype, data, error, throttled = await self._send_while_connected(
"send",
content=content,
parent=parent_mid
parent=parent
)
else:
ptype, data, error, throttled = await self._send_while_connected(
@ -141,7 +147,9 @@ class Room:
content=content
)
return Message.from_dict(data)
message = Message.from_dict(data)
self._last_known_mid = message.mid
return message
async def who(self):
ptype, data, error, throttled = await self._send_while_connected("who")
@ -156,6 +164,9 @@ class Room:
self.status = Room.DISCONNECTED
self._connected_future = asyncio.Future()
if self._forwarding is not None:
self._forwarding.cancel()
await self._inhabitant.disconnected(self)
async def _receive_packet(self, ptype, data, error, throttled):
@ -254,14 +265,20 @@ class Room:
async def _event_send(self, data):
message = Message.from_dict(data)
await self._inhabitant.send(self, message)
if self._status == Room.FORWARDING:
self._forward_new.append(message)
else:
self._last_known_mid = message.mid
await self._inhabitant.send(self, message)
# TODO: Figure out a way to bring fast-forwarding into this
async def _event_snapshot(self, data):
log = [Message.from_dict(m) for m in data.get("log")]
sessions = [Session.from_dict(d) for d in data.get("listing")]
# Update listing
self.listing = Listing()
sessions = [Session.from_dict(d) for d in data.get("listing")]
for session in sessions:
self.listing.add(session)
self.listing.add(self.session)
@ -280,13 +297,23 @@ class Room:
return # Aww, we've lost connection again
# Now, we're finally connected again!
self.status = Room.CONNECTED
if self._last_known_mid is None:
self._status = Room.CONNECTED
if log: # log goes from old to new
self._last_known_mid = log[-1].mid
else:
self._status = Room.FORWARDING
self._forward_new = []
if self._forwarding is not None:
self._forwarding.cancel()
self._forwarding = asyncio.ensure_future(self._forward(log))
if not self._connected_future.done(): # Should never be done already, I think
self._connected_future.set_result(None)
# Let's let the inhabitant know.
logger.debug("Letting inhabitant know")
log = [Message.from_dict(m) for m in data.get("log")]
await self._inhabitant.connected(self, log)
# TODO: Figure out a way to bring fast-forwarding into this
@ -311,6 +338,32 @@ class Room:
# REST OF THE IMPLEMENTATION
async def _forward(self, log):
old_messages = []
while True:
found_last_known = True
for message in reversed(log):
if message.mid <= self._last_known_mid:
break
old_messages.append(message)
else:
found_last_known = False
if found_last_known:
break
log = await self.log(100, before=log[0].mid)
for message in reversed(old_messages):
self._last_known_mid = message.mid
asyncio.ensure_future(self._inhabitant.forward(self, message))
for message in self._forward_new:
self._last_known_mid = message.mid
asyncio.ensure_future(self._inhabitant.forward(self, message))
self._forward_new = []
self._status = Room.CONNECTED
async def _send_while_connected(self, *args, **kwargs):
while True:
if self._status == Room.CLOSED: