Handle connecting to rooms
This commit is contained in:
parent
04f7c9c781
commit
14bae17104
3 changed files with 131 additions and 69 deletions
|
|
@ -26,22 +26,25 @@ class SessionView():
|
||||||
self.manager = is_manager
|
self.manager = is_manager
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_data(self, data):
|
def from_data(cls, data):
|
||||||
"""
|
"""
|
||||||
Creates and returns a session created from the data.
|
Creates and returns a session created from the data.
|
||||||
|
|
||||||
data - a euphoria SessionView
|
data - a euphoria SessionView
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return self(
|
view = cls(None, None, None, None, None)
|
||||||
data.get("id"),
|
view.read_data(data)
|
||||||
data.get("name"),
|
return view
|
||||||
data.get("server_id"),
|
|
||||||
data.get("server_era"),
|
def read_data(self, data):
|
||||||
data.get("session_id"),
|
if "id" in data: self.id = data.get("id")
|
||||||
data.get("is_staff"),
|
if "name" in data: self.name = data.get("name")
|
||||||
data.get("is_manager")
|
if "server_id" in data: self.server_id = data.get("server_id")
|
||||||
)
|
if "server_era" in data: self.server_era = data.get("server_era")
|
||||||
|
if "session_id" in data: self.session_id = data.get("session_id")
|
||||||
|
if "is_staff" in data: self.is_staff = data.get("is_staff")
|
||||||
|
if "is_manager" in data: self.is_manager = data.get("is_manager")
|
||||||
|
|
||||||
def session_type(self):
|
def session_type(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,9 @@ from websocket import WebSocketException as WSException
|
||||||
|
|
||||||
from .callbacks import Callbacks
|
from .callbacks import Callbacks
|
||||||
|
|
||||||
SSLOPT_CA_CERTS = {'ca_certs': ssl.get_default_verify_paths().cafile}
|
SSLOPT = {"ca_certs": ssl.get_default_verify_paths().cafile}
|
||||||
|
#SSLOPT = {"cert_reqs": ssl.CERT_NONE}
|
||||||
|
ROOM_FORMAT = "wss://euphoria.io/room/{}/ws"
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class Connection():
|
class Connection():
|
||||||
|
|
@ -25,8 +27,6 @@ class Connection():
|
||||||
- "stop"
|
- "stop"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ROOM_FORMAT = "wss://euphoria.io/room/{}/ws"
|
|
||||||
|
|
||||||
def __init__(self, room, url_format=None):
|
def __init__(self, room, url_format=None):
|
||||||
"""
|
"""
|
||||||
room - name of the room to connect to
|
room - name of the room to connect to
|
||||||
|
|
@ -35,7 +35,7 @@ class Connection():
|
||||||
|
|
||||||
self.room = room
|
self.room = room
|
||||||
|
|
||||||
self._url_format = url_format or Connection.ROOM_FORMAT
|
self._url_format = url_format or ROOM_FORMAT
|
||||||
|
|
||||||
self._stopping = False
|
self._stopping = False
|
||||||
|
|
||||||
|
|
@ -44,7 +44,7 @@ class Connection():
|
||||||
self._send_id = 0
|
self._send_id = 0
|
||||||
self._callbacks = Callbacks()
|
self._callbacks = Callbacks()
|
||||||
self._id_callbacks = Callbacks()
|
self._id_callbacks = Callbacks()
|
||||||
self._lock = threading.Lock()
|
self._lock = threading.RLock()
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self._lock.acquire()
|
self._lock.acquire()
|
||||||
|
|
@ -77,7 +77,7 @@ class Connection():
|
||||||
self._ws = websocket.create_connection(
|
self._ws = websocket.create_connection(
|
||||||
url,
|
url,
|
||||||
enable_multithread=True,
|
enable_multithread=True,
|
||||||
sslopt=SSLOPT_CA_CERTS
|
sslopt=SSLOPT
|
||||||
)
|
)
|
||||||
|
|
||||||
except WSException:
|
except WSException:
|
||||||
|
|
@ -107,6 +107,8 @@ class Connection():
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self._ws:
|
if self._ws:
|
||||||
|
logger.debug("Closing connection!")
|
||||||
|
self._ws.abort()
|
||||||
self._ws.close()
|
self._ws.close()
|
||||||
self._ws = None
|
self._ws = None
|
||||||
|
|
||||||
|
|
@ -120,8 +122,11 @@ class Connection():
|
||||||
Connect to the room and spawn a new thread.
|
Connect to the room and spawn a new thread.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self._thread = threading.Thread(target=self._run,
|
self._stopping = False
|
||||||
name="{}-{}".format(int(time.time()), self.room))
|
self._thread = threading.Thread(
|
||||||
|
target=self._run,
|
||||||
|
name="{}-{}".format(int(time.time()), self.room)
|
||||||
|
)
|
||||||
logger.debug("Launching new thread: {}".format(self._thread.name))
|
logger.debug("Launching new thread: {}".format(self._thread.name))
|
||||||
self._thread.start()
|
self._thread.start()
|
||||||
return self._thread
|
return self._thread
|
||||||
|
|
@ -134,16 +139,20 @@ class Connection():
|
||||||
"""
|
"""
|
||||||
|
|
||||||
logger.debug("Running")
|
logger.debug("Running")
|
||||||
|
|
||||||
if not self.switch_to(self.room):
|
if not self.switch_to(self.room):
|
||||||
return
|
return
|
||||||
|
|
||||||
while not self._stopping:
|
while not self._stopping:
|
||||||
try:
|
try:
|
||||||
self._handle_json(self._ws.recv())
|
j = self._ws.recv()
|
||||||
|
self._handle_json(j)
|
||||||
except (WSException, ConnectionResetError):
|
except (WSException, ConnectionResetError):
|
||||||
if not self._stopping:
|
if not self._stopping:
|
||||||
self.disconnect()
|
self.disconnect()
|
||||||
self._connect()
|
self._connect()
|
||||||
|
|
||||||
|
logger.debug("Finished running")
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -248,15 +257,14 @@ class Connection():
|
||||||
logger.debug("Handling packet of type {}.".format(ptype))
|
logger.debug("Handling packet of type {}.".format(ptype))
|
||||||
|
|
||||||
data = packet.get("data")
|
data = packet.get("data")
|
||||||
error = packet.get("error")
|
if "error" in packet:
|
||||||
if error:
|
|
||||||
logger.debug("Error in packet: {!r}".format(error))
|
logger.debug("Error in packet: {!r}".format(error))
|
||||||
|
|
||||||
if "id" in packet:
|
if "id" in packet:
|
||||||
self._id_callbacks.call(packet["id"], data, error)
|
self._id_callbacks.call(packet["id"], data, packet)
|
||||||
self._id_callbacks.remove(packet["id"])
|
self._id_callbacks.remove(packet["id"])
|
||||||
|
|
||||||
self._callbacks.call(packet["type"], data, error)
|
self._callbacks.call(packet["type"], data, packet)
|
||||||
|
|
||||||
def _send_json(self, data):
|
def _send_json(self, data):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import logging
|
||||||
|
|
||||||
from .callbacks import Callbacks
|
from .callbacks import Callbacks
|
||||||
from .connection import Connection
|
from .connection import Connection
|
||||||
|
from .basic_types import Message, SessionView
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -13,64 +14,84 @@ class Session():
|
||||||
- seeing other clients
|
- seeing other clients
|
||||||
- sending and receiving messages
|
- sending and receiving messages
|
||||||
|
|
||||||
Things to wait for before being properly connected:
|
Events:
|
||||||
hello-event
|
enter - can view the room
|
||||||
snapshot-event
|
ready - can view the room and post messages (has a nick)
|
||||||
-> connected
|
|
||||||
|
|
||||||
Things to wait for before being ready:
|
|
||||||
hello-event
|
|
||||||
snapshot-event
|
|
||||||
nick-reply
|
|
||||||
-> ready
|
|
||||||
|
|
||||||
When connecting to a new room:
|
|
||||||
_hello_event_completed = False
|
|
||||||
_snapshot_event_completed = False
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, room, password=None):
|
def __init__(self, room, password=None, name=None):
|
||||||
self._connection = Connection(room)
|
self._connection = Connection(room)
|
||||||
self._connection.subscribe("disconnect", self._on_disconnect)
|
self._connection.subscribe("disconnect", self._reset_variables)
|
||||||
self._connection.subscribe("bounce-event", self.handle_bounce_event)
|
self._connection.subscribe("bounce-event", self.handle_bounce_event)
|
||||||
|
self._connection.subscribe("disconnect-event", self.handle_disconnect_event)
|
||||||
|
self._connection.subscribe("hello-event", self.handle_hello_event)
|
||||||
self._connection.subscribe("ping-event", self.handle_ping_event)
|
self._connection.subscribe("ping-event", self.handle_ping_event)
|
||||||
|
self._connection.subscribe("snapshot-event", self.handle_snapshot_event)
|
||||||
|
|
||||||
self._callbacks = Callbacks()
|
self._callbacks = Callbacks()
|
||||||
self._hello_event_completed = False
|
self.subscribe("enter", self._on_enter)
|
||||||
self._snapshot_event_completed = False
|
|
||||||
|
|
||||||
self.password = password
|
self.password = password
|
||||||
|
self._wish_name = name
|
||||||
|
|
||||||
self.my_session = None
|
#self._hello_event_completed = False
|
||||||
self.sessions = {} # sessions in the room
|
#self._snapshot_event_completed = False
|
||||||
|
#self._ready = False
|
||||||
|
#self.my_session = SessionView(None, None, None, None, None)
|
||||||
|
#self.sessions = {} # sessions in the room
|
||||||
|
#self.room_is_private = None
|
||||||
|
#self.server_version = None
|
||||||
|
|
||||||
|
self._reset_variables()
|
||||||
|
|
||||||
|
def _reset_variables(self):
|
||||||
|
logger.debug("Resetting room-related variables")
|
||||||
|
self.my_session = SessionView(None, None, None, None, None)
|
||||||
|
self.sessions = {}
|
||||||
|
self._hello_event_completed = False
|
||||||
|
self._snapshot_event_completed = False
|
||||||
|
self._ready = False
|
||||||
|
|
||||||
|
self.room_is_private = None
|
||||||
|
self.server_version = None
|
||||||
|
|
||||||
|
def _set_name(self, new_name):
|
||||||
|
with self._connection as conn:
|
||||||
|
logger.debug("setting name to {!r}".format(new_name))
|
||||||
|
conn.subscribe_to_next(self.handle_nick_reply)
|
||||||
|
conn.send_packet("nick", name=new_name)
|
||||||
|
|
||||||
|
def _on_enter(self):
|
||||||
|
logger.info("Connected and authenticated.")
|
||||||
|
|
||||||
|
if self._wish_name:
|
||||||
|
self._set_name(self._wish_name)
|
||||||
|
|
||||||
def launch(self):
|
def launch(self):
|
||||||
return self._connection.launch()
|
return self._connection.launch()
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
logger.info("Stopping")
|
logger.info("Stopping")
|
||||||
self._connection.stop()
|
with self._connection as conn:
|
||||||
|
conn.stop()
|
||||||
|
|
||||||
|
def subscribe(self, event, callback, *args, **kwargs):
|
||||||
|
logger.debug("Adding callback {} to {}".format(callback, event))
|
||||||
|
self._callbacks.add(event, callback, *args, **kwargs)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
if self.my_session:
|
return self.my_session.name
|
||||||
return self.my_session.name
|
|
||||||
|
|
||||||
@name.setter
|
@name.setter
|
||||||
def name(self, new_name):
|
def name(self, new_name):
|
||||||
with self._connection as conn:
|
self._wish_name = new_name
|
||||||
logger.debug("setting name to {!r}".format(new_name))
|
|
||||||
conn.subscribe_to_next(self.handle_nick_reply)
|
if not self._ready:
|
||||||
conn.send_packet("nick", name=new_name)
|
self._set_name(new_name)
|
||||||
|
|
||||||
def _on_disconnect(self):
|
def handle_bounce_event(self, data, packet):
|
||||||
logger.debug("Disconnected. Resetting related variables")
|
|
||||||
self.my_session = None
|
|
||||||
self.sessions = {}
|
|
||||||
self._hello_event_completed = False
|
|
||||||
self._snapshot_event_completed = False
|
|
||||||
|
|
||||||
def handle_bounce_event(self, data, error):
|
|
||||||
if data.get("reason") == "authentication required":
|
if data.get("reason") == "authentication required":
|
||||||
if self.password:
|
if self.password:
|
||||||
with self._connection as conn:
|
with self._connection as conn:
|
||||||
|
|
@ -80,30 +101,60 @@ class Session():
|
||||||
logger.warn("Could not access &{}: No password.".format(self._connection.room))
|
logger.warn("Could not access &{}: No password.".format(self._connection.room))
|
||||||
self.stop()
|
self.stop()
|
||||||
|
|
||||||
def handle_disconnect_event(self, data, error):
|
def handle_disconnect_event(self, data, packet):
|
||||||
self._connection.disconnect() # should reconnect
|
self._connection.disconnect() # should reconnect
|
||||||
|
|
||||||
def handle_ping_event(self, data, error):
|
def handle_hello_event(self, data, packet):
|
||||||
|
self.my_session.read_data(data.get("session"))
|
||||||
|
|
||||||
|
self.room_is_private = data.get("room_is_private")
|
||||||
|
self.server_version = data.get("version")
|
||||||
|
|
||||||
|
self._hello_event_completed = True
|
||||||
|
if self._snapshot_event_completed:
|
||||||
|
self._callbacks.call("enter")
|
||||||
|
|
||||||
|
def handle_ping_event(self, data, packet):
|
||||||
with self._connection as conn:
|
with self._connection as conn:
|
||||||
logger.debug("playing ping pong")
|
logger.debug("playing ping pong")
|
||||||
conn.send_packet("ping-reply", time=data.get("time"))
|
conn.send_packet("ping-reply", time=data.get("time"))
|
||||||
|
|
||||||
def handle_auth_reply(self, data, error):
|
def handle_snapshot_event(self, data, packet):
|
||||||
if data.get("success"):
|
# deal with connected sessions
|
||||||
logger.debug("Authetication complete, password was correct.")
|
for item in data.get("listing"):
|
||||||
else:
|
view = SessionView.from_data(item)
|
||||||
|
self.sessions[view.session_id] = view
|
||||||
|
|
||||||
|
# deal with messages
|
||||||
|
# TODO: this
|
||||||
|
|
||||||
|
# deal with other info
|
||||||
|
self.server_version = data.get("version")
|
||||||
|
if "nick" in data:
|
||||||
|
self.my_session.name = data.get("nick")
|
||||||
|
|
||||||
|
self._snapshot_event_completed = True
|
||||||
|
if self._hello_event_completed:
|
||||||
|
self._callbacks.call("enter")
|
||||||
|
|
||||||
|
|
||||||
|
def handle_auth_reply(self, data, packet):
|
||||||
|
if not data.get("success"):
|
||||||
logger.warn("Could not authenticate, reason: {!r}".format(data.get("reason")))
|
logger.warn("Could not authenticate, reason: {!r}".format(data.get("reason")))
|
||||||
self.stop()
|
self.stop()
|
||||||
|
else:
|
||||||
|
logger.debug("Authetication complete, password was correct.")
|
||||||
|
|
||||||
def handle_nick_reply(self, data, error):
|
def handle_nick_reply(self, data, packet):
|
||||||
if error:
|
|
||||||
logger.error("nick-reply error: {!r}".format(error))
|
|
||||||
return
|
|
||||||
|
|
||||||
first_name = not self.name
|
first_name = not self.name
|
||||||
|
|
||||||
logger.info("Changed name fro {!r} to {!r}.".format(data.get("from"), data.get("to")))
|
if first_name:
|
||||||
|
logger.info("Changed name to {!r}.".format(data.get("to")))
|
||||||
|
else:
|
||||||
|
logger.info("Changed name from {!r} to {!r}.".format(data.get("from"), data.get("to")))
|
||||||
|
|
||||||
self.my_session.name = data.get("to")
|
self.my_session.name = data.get("to")
|
||||||
|
|
||||||
if first_name:
|
if first_name:
|
||||||
|
self._ready = True
|
||||||
self._callbacks.call("ready")
|
self._callbacks.call("ready")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue