Make room work
This commit is contained in:
parent
a971b7e064
commit
3051b15095
4 changed files with 108 additions and 46 deletions
|
|
@ -14,7 +14,7 @@ from .cookiejar import *
|
||||||
from .connection import *
|
from .connection import *
|
||||||
from .exceptions import *
|
from .exceptions import *
|
||||||
from .room import *
|
from .room import *
|
||||||
from utils import *
|
from .utils import *
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
connection.__all__ +
|
connection.__all__ +
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ class Connection:
|
||||||
|
|
||||||
self._stopped = False
|
self._stopped = False
|
||||||
self._pingtask = None
|
self._pingtask = None
|
||||||
self._runtask = asyncio.create_task(self._run())
|
self._runtask = asyncio.ensure_future(self._run())
|
||||||
# ... aaand the connection is started.
|
# ... aaand the connection is started.
|
||||||
|
|
||||||
async def send(self, ptype, data=None, await_response=True):
|
async def send(self, ptype, data=None, await_response=True):
|
||||||
|
|
@ -90,8 +90,8 @@ class Connection:
|
||||||
delay = 1 # seconds
|
delay = 1 # seconds
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
if self._cookiejar:
|
if self.cookiejar:
|
||||||
cookies = [("Cookie", cookie) for cookie in self._cookiejar.sniff()]
|
cookies = [("Cookie", cookie) for cookie in self.cookiejar.sniff()]
|
||||||
self._ws = await websockets.connect(self.url, max_size=None, extra_headers=cookies)
|
self._ws = await websockets.connect(self.url, max_size=None, extra_headers=cookies)
|
||||||
else:
|
else:
|
||||||
self._ws = await websockets.connect(self.url, max_size=None)
|
self._ws = await websockets.connect(self.url, max_size=None)
|
||||||
|
|
@ -106,11 +106,11 @@ class Connection:
|
||||||
await asyncio.sleep(delay)
|
await asyncio.sleep(delay)
|
||||||
delay *= 2
|
delay *= 2
|
||||||
else:
|
else:
|
||||||
if self._cookiejar:
|
if self.cookiejar:
|
||||||
for set_cookie in self._ws.response_headers.get_all("Set-Cookie"):
|
for set_cookie in self._ws.response_headers.get_all("Set-Cookie"):
|
||||||
self._cookiejar.bake(set_cookie)
|
self.cookiejar.bake(set_cookie)
|
||||||
|
|
||||||
self._pingtask = asyncio.create_task(self._ping())
|
self._pingtask = asyncio.ensure_future(self._ping())
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
@ -123,7 +123,7 @@ class Connection:
|
||||||
- make sure the ping task has finished
|
- make sure the ping task has finished
|
||||||
"""
|
"""
|
||||||
|
|
||||||
asyncio.create_task(self.disconnect_callback())
|
asyncio.ensure_future(self.disconnect_callback())
|
||||||
|
|
||||||
# stop ping task
|
# stop ping task
|
||||||
if self._pingtask:
|
if self._pingtask:
|
||||||
|
|
@ -149,7 +149,7 @@ class Connection:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
while not self._stopped:
|
while not self._stopped:
|
||||||
self._connect(self.reconnect_attempts)
|
await self._connect(self.reconnect_attempts)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
|
|
@ -183,13 +183,7 @@ class Connection:
|
||||||
|
|
||||||
async def _handle_next_message(self):
|
async def _handle_next_message(self):
|
||||||
response = await self._ws.recv()
|
response = await self._ws.recv()
|
||||||
packet = json.loads(text)
|
packet = json.loads(response)
|
||||||
|
|
||||||
# Deal with pending responses
|
|
||||||
pid = packet.get("id", None)
|
|
||||||
future = self._pending_responses.pop(pid, None)
|
|
||||||
if future:
|
|
||||||
future.set_result(packet)
|
|
||||||
|
|
||||||
ptype = packet.get("type")
|
ptype = packet.get("type")
|
||||||
data = packet.get("data", None)
|
data = packet.get("data", None)
|
||||||
|
|
@ -199,8 +193,14 @@ class Connection:
|
||||||
else:
|
else:
|
||||||
throttled = None
|
throttled = None
|
||||||
|
|
||||||
|
# Deal with pending responses
|
||||||
|
pid = packet.get("id", None)
|
||||||
|
future = self._pending_responses.pop(pid, None)
|
||||||
|
if future:
|
||||||
|
future.set_result((ptype, data, error, throttled))
|
||||||
|
|
||||||
# Pass packet onto room
|
# Pass packet onto room
|
||||||
asyncio.create_task(self.packet_callback(ptype, data, error, throttled))
|
asyncio.ensure_future(self.packet_callback(ptype, data, error, throttled))
|
||||||
|
|
||||||
def _wait_for_response(self, pid):
|
def _wait_for_response(self, pid):
|
||||||
future = asyncio.Future()
|
future = asyncio.Future()
|
||||||
|
|
|
||||||
118
yaboli/room.py
118
yaboli/room.py
|
|
@ -1,9 +1,14 @@
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
from .connection import *
|
from .connection import *
|
||||||
from .exceptions import *
|
from .exceptions import *
|
||||||
from .utils import *
|
from .utils import *
|
||||||
|
|
||||||
|
|
||||||
__all__ == ["Room", "Inhabitant"]
|
__all__ = ["Room", "Inhabitant"]
|
||||||
|
|
||||||
|
|
||||||
class Room:
|
class Room:
|
||||||
|
|
@ -13,7 +18,7 @@ class Room:
|
||||||
|
|
||||||
CONNECTED = 1
|
CONNECTED = 1
|
||||||
DISCONNECTED = 2
|
DISCONNECTED = 2
|
||||||
EXITED = 3
|
CLOSED = 3
|
||||||
|
|
||||||
def __init__(self, roomname, inhabitant, password=None, human=False, cookiejar=None):
|
def __init__(self, roomname, inhabitant, password=None, human=False, cookiejar=None):
|
||||||
# TODO: Connect to room etc.
|
# TODO: Connect to room etc.
|
||||||
|
|
@ -38,6 +43,7 @@ class Room:
|
||||||
|
|
||||||
self._inhabitant = inhabitant
|
self._inhabitant = inhabitant
|
||||||
self._status = Room.DISCONNECTED
|
self._status = Room.DISCONNECTED
|
||||||
|
self._connected_future = asyncio.Future()
|
||||||
|
|
||||||
# TODO: Allow for all parameters of Connection() to be specified in Room().
|
# TODO: Allow for all parameters of Connection() to be specified in Room().
|
||||||
self._connection = Connection(
|
self._connection = Connection(
|
||||||
|
|
@ -48,7 +54,7 @@ class Room:
|
||||||
)
|
)
|
||||||
|
|
||||||
async def exit(self):
|
async def exit(self):
|
||||||
self._status = Room.EXITED
|
self._status = Room.CLOSED
|
||||||
await self._connection.stop()
|
await self._connection.stop()
|
||||||
|
|
||||||
# ROOM COMMANDS
|
# ROOM COMMANDS
|
||||||
|
|
@ -57,16 +63,62 @@ class Room:
|
||||||
# the command will retry once the bot has reconnected.
|
# the command will retry once the bot has reconnected.
|
||||||
|
|
||||||
async def get_message(self, mid):
|
async def get_message(self, mid):
|
||||||
pass
|
if self._status == Room.CLOSED:
|
||||||
|
raise RoomClosed()
|
||||||
|
|
||||||
|
ptype, data, error, throttled = await self._send_while_connected(
|
||||||
|
"get-message",
|
||||||
|
id=mid
|
||||||
|
)
|
||||||
|
|
||||||
|
return Message.from_dict(data)
|
||||||
|
|
||||||
async def log(self, n, before_mid=None):
|
async def log(self, n, before_mid=None):
|
||||||
pass
|
if self._status == Room.CLOSED:
|
||||||
|
raise RoomClosed()
|
||||||
|
|
||||||
|
if before_mid:
|
||||||
|
ptype, data, error, throttled = await self._send_while_connected(
|
||||||
|
"log",
|
||||||
|
n=n,
|
||||||
|
before=before_mid
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
ptype, data, error, throttled = await self._send_while_connected(
|
||||||
|
"log",
|
||||||
|
n=n
|
||||||
|
)
|
||||||
|
|
||||||
|
return [Message.from_dict(d) for d in data.get("log")]
|
||||||
|
|
||||||
async def nick(self, nick):
|
async def nick(self, nick):
|
||||||
pass
|
if self._status == Room.CLOSED:
|
||||||
|
raise RoomClosed()
|
||||||
|
|
||||||
|
ptype, data, error, throttled = await self._send_while_connected(
|
||||||
|
"nick",
|
||||||
|
name=nick
|
||||||
|
)
|
||||||
|
|
||||||
|
sid = data.get("session_id")
|
||||||
|
uid = data.get("id")
|
||||||
|
from_nick = data.get("from")
|
||||||
|
to_nick = data.get("to")
|
||||||
|
return sid, uid, from_nick, to_nick
|
||||||
|
|
||||||
async def pm(self, uid):
|
async def pm(self, uid):
|
||||||
pass
|
if self._status == Room.CLOSED:
|
||||||
|
raise RoomClosed()
|
||||||
|
|
||||||
|
ptype, data, error, throttled = await self._send_while_connected(
|
||||||
|
"pm-initiate",
|
||||||
|
user_id=uid
|
||||||
|
)
|
||||||
|
|
||||||
|
# Just ignoring non-authenticated errors
|
||||||
|
pm_id = data.get("pm_id")
|
||||||
|
to_nick = data.get("to_nick")
|
||||||
|
return pm_id, to_nick
|
||||||
|
|
||||||
async def send(self, content, parent_mid=None):
|
async def send(self, content, parent_mid=None):
|
||||||
"""
|
"""
|
||||||
|
|
@ -75,13 +127,13 @@ class Room:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if parent_mid:
|
if parent_mid:
|
||||||
data = await self._send_while_connected(
|
ptype, data, error, throttled = await self._send_while_connected(
|
||||||
"send",
|
"send",
|
||||||
content=content,
|
content=content,
|
||||||
parent=parent_mid
|
parent=parent_mid
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
data = await self._send_while_connected(
|
ptype, data, error, throttled = await self._send_while_connected(
|
||||||
"send",
|
"send",
|
||||||
content=content
|
content=content
|
||||||
)
|
)
|
||||||
|
|
@ -103,6 +155,7 @@ class Room:
|
||||||
|
|
||||||
async def _receive_packet(self, ptype, data, error, throttled):
|
async def _receive_packet(self, ptype, data, error, throttled):
|
||||||
# Ignoring errors and throttling for now
|
# Ignoring errors and throttling for now
|
||||||
|
logger.debug(f"Received packet of type: {ptype}")
|
||||||
functions = {
|
functions = {
|
||||||
"bounce-event": self._event_bounce,
|
"bounce-event": self._event_bounce,
|
||||||
#"disconnect-event": self._event_disconnect, # Not important, can ignore
|
#"disconnect-event": self._event_disconnect, # Not important, can ignore
|
||||||
|
|
@ -127,7 +180,8 @@ class Room:
|
||||||
async def _event_bounce(self, data):
|
async def _event_bounce(self, data):
|
||||||
if self.password is not None:
|
if self.password is not None:
|
||||||
try:
|
try:
|
||||||
response = await self._connection.send("auth", type=passcode, passcode=self.password)
|
data = {"type": passcode, "passcode": self.password}
|
||||||
|
response = await self._connection.send("auth", data=data)
|
||||||
rdata = response.get("data")
|
rdata = response.get("data")
|
||||||
success = rdata.get("success")
|
success = rdata.get("success")
|
||||||
if not success:
|
if not success:
|
||||||
|
|
@ -140,7 +194,7 @@ class Room:
|
||||||
|
|
||||||
async def _event_hello(self, data):
|
async def _event_hello(self, data):
|
||||||
self.session = Session.from_dict(data.get("session"))
|
self.session = Session.from_dict(data.get("session"))
|
||||||
self.room_is_private = = data.get("room_is_private")
|
self.room_is_private = data.get("room_is_private")
|
||||||
self.version = data.get("version")
|
self.version = data.get("version")
|
||||||
self.account = data.get("account", None)
|
self.account = data.get("account", None)
|
||||||
self.account_has_access = data.get("account_has_access", None)
|
self.account_has_access = data.get("account_has_access", None)
|
||||||
|
|
@ -178,8 +232,9 @@ class Room:
|
||||||
|
|
||||||
async def _event_ping(self, data):
|
async def _event_ping(self, data):
|
||||||
try:
|
try:
|
||||||
self._connection.send()
|
new_data = {"time": data.get("time")}
|
||||||
except exceptions.ConnectionClosed:
|
await self._connection.send( "ping-reply", data=new_data, await_response=False)
|
||||||
|
except ConnectionClosed:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
async def _event_pm_initiate(self, data):
|
async def _event_pm_initiate(self, data):
|
||||||
|
|
@ -191,34 +246,41 @@ class Room:
|
||||||
await self._inhabitant.pm(self, from_uid, from_nick, from_room, pm_id)
|
await self._inhabitant.pm(self, from_uid, from_nick, from_room, pm_id)
|
||||||
|
|
||||||
async def _event_send(self, data):
|
async def _event_send(self, data):
|
||||||
pass # TODO X
|
message = Message.from_dict(data)
|
||||||
|
|
||||||
|
await self._inhabitant.send(self, message)
|
||||||
|
|
||||||
# TODO: Figure out a way to bring fast-forwarding into this
|
# TODO: Figure out a way to bring fast-forwarding into this
|
||||||
|
|
||||||
async def _event_snapshot(self, data):
|
async def _event_snapshot(self, data):
|
||||||
# update listing
|
# Update listing
|
||||||
self.listing = Listing()
|
self.listing = Listing()
|
||||||
sessions = [Session.from_dict(d) for d in data.get("listing")]
|
sessions = [Session.from_dict(d) for d in data.get("listing")]
|
||||||
for session in sessions:
|
for session in sessions:
|
||||||
self.listing.add(session)
|
self.listing.add(session)
|
||||||
|
|
||||||
# update (and possibly set) nick
|
# Update room info
|
||||||
new_nick = data.get("nick", None)
|
|
||||||
if self.session:
|
|
||||||
prev_nick = self.session.nick
|
|
||||||
if new_nick != prev_nick:
|
|
||||||
self.nick(prev_nick)
|
|
||||||
self.session.nick = new_nick
|
|
||||||
|
|
||||||
# update more room info
|
|
||||||
self.pm_with_nick = data.get("pm_with_nick", None),
|
self.pm_with_nick = data.get("pm_with_nick", None),
|
||||||
self.pm_with_user_id = data.get("pm_with_user_id", None)
|
self.pm_with_user_id = data.get("pm_with_user_id", None)
|
||||||
|
|
||||||
|
# Remember old nick, because we're going to try to get it back
|
||||||
|
old_nick = self.session.nick if self.session else None
|
||||||
|
new_nick = data.get("nick", None)
|
||||||
|
self.session.nick = new_nick
|
||||||
|
|
||||||
|
if old_nick and old_nick != new_nick:
|
||||||
|
try:
|
||||||
|
await self._connection.send("nick", data={"name": old_nick})
|
||||||
|
except ConnectionClosed:
|
||||||
|
return # Aww, we've lost connection again
|
||||||
|
|
||||||
# Now, we're finally connected again!
|
# Now, we're finally connected again!
|
||||||
self.status = Room.CONNECTED
|
self.status = Room.CONNECTED
|
||||||
if not self._connected_future.done(): # should always be True, I think
|
if not self._connected_future.done(): # Should never be done already, I think
|
||||||
self._connected_future.set_result(None)
|
self._connected_future.set_result(None)
|
||||||
|
|
||||||
# Let's let the inhabitant know.
|
# Let's let the inhabitant know.
|
||||||
|
logger.debug("Letting inhabitant know")
|
||||||
log = [Message.from_dict(m) for m in data.get("log")]
|
log = [Message.from_dict(m) for m in data.get("log")]
|
||||||
await self._inhabitant.connected(self, log)
|
await self._inhabitant.connected(self, log)
|
||||||
|
|
||||||
|
|
@ -244,14 +306,14 @@ class Room:
|
||||||
|
|
||||||
# REST OF THE IMPLEMENTATION
|
# REST OF THE IMPLEMENTATION
|
||||||
|
|
||||||
async def _send_while_connected(*args, **kwargs):
|
async def _send_while_connected(self, *args, **kwargs):
|
||||||
while True:
|
while True:
|
||||||
if self._status == Room.CLOSED:
|
if self._status == Room.CLOSED:
|
||||||
raise RoomClosed()
|
raise RoomClosed()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await self.connected()
|
await self.connected()
|
||||||
return await self._connection.send(*args, **kwargs)
|
return await self._connection.send(*args, data=kwargs)
|
||||||
except ConnectionClosed:
|
except ConnectionClosed:
|
||||||
pass # just try again
|
pass # just try again
|
||||||
|
|
||||||
|
|
@ -263,7 +325,7 @@ class Inhabitant:
|
||||||
|
|
||||||
# ROOM EVENTS
|
# ROOM EVENTS
|
||||||
# These functions are called by the room when something happens.
|
# These functions are called by the room when something happens.
|
||||||
# They're launched via asyncio.create_task(), so they don't block execution of the room.
|
# They're launched via asyncio.ensure_future(), so they don't block execution of the room.
|
||||||
# Just overwrite the events you need (make sure to keep the arguments the same though).
|
# Just overwrite the events you need (make sure to keep the arguments the same though).
|
||||||
|
|
||||||
async def disconnected(self, room):
|
async def disconnected(self, room):
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ __all__ = [
|
||||||
"mention", "mention_reduced", "similar",
|
"mention", "mention_reduced", "similar",
|
||||||
"format_time", "format_time_delta",
|
"format_time", "format_time_delta",
|
||||||
"Session", "Listing",
|
"Session", "Listing",
|
||||||
"Message", "Log",
|
"Message",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue