Initial commit
This commit is contained in:
commit
a96663a5d4
7 changed files with 337 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
logs.db
|
||||||
|
logsreadable/*
|
||||||
235
bugbot/connection.py
Normal file
235
bugbot/connection.py
Normal file
|
|
@ -0,0 +1,235 @@
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
import websocket
|
||||||
|
from websocket import WebSocketException as WSException
|
||||||
|
|
||||||
|
|
||||||
|
ROOM_FORMAT = "wss://euphoria.io/room/{}/ws"
|
||||||
|
|
||||||
|
|
||||||
|
class Connection():
|
||||||
|
"""
|
||||||
|
Stays connected to a room in its own thread.
|
||||||
|
Callback functions are called when a packet is received.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, room):
|
||||||
|
"""
|
||||||
|
room - name of the room to connect to
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.room = room
|
||||||
|
|
||||||
|
self.stopping = False
|
||||||
|
|
||||||
|
self.ws = None
|
||||||
|
self.send_id = 0
|
||||||
|
self.callbacks = {}
|
||||||
|
self.id_callbacks = {}
|
||||||
|
|
||||||
|
def connect(self, tries=-1, delay=10):
|
||||||
|
"""
|
||||||
|
_connect(tries, delay) -> bool
|
||||||
|
|
||||||
|
tries - maximum number of retries
|
||||||
|
-1 -> retry indefinitely
|
||||||
|
|
||||||
|
Returns True on success, False on failure.
|
||||||
|
|
||||||
|
Connect to the room.
|
||||||
|
"""
|
||||||
|
|
||||||
|
while tries != 0:
|
||||||
|
try:
|
||||||
|
self.ws = websocket.create_connection(
|
||||||
|
ROOM_FORMAT.format(self.room),
|
||||||
|
enable_multithread=True
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
except WSException:
|
||||||
|
if tries > 0:
|
||||||
|
tries -= 1
|
||||||
|
if tries != 0:
|
||||||
|
time.sleep(delay)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def disconnect(self):
|
||||||
|
"""
|
||||||
|
disconnect() -> None
|
||||||
|
|
||||||
|
Reconnect to the room.
|
||||||
|
WARNING: To completely disconnect, use stop().
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.ws:
|
||||||
|
self.ws.close()
|
||||||
|
self.ws = None
|
||||||
|
|
||||||
|
def launch(self):
|
||||||
|
"""
|
||||||
|
launch() -> Thread
|
||||||
|
|
||||||
|
Connect to the room and spawn a new thread running run.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.connect(tries=1):
|
||||||
|
self.thread = threading.Thread(target=self.run, name=self.room)
|
||||||
|
self.thread.start()
|
||||||
|
return self.thread
|
||||||
|
else:
|
||||||
|
self.stop()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""
|
||||||
|
run() -> None
|
||||||
|
|
||||||
|
Receive messages.
|
||||||
|
"""
|
||||||
|
|
||||||
|
while not self.stopping:
|
||||||
|
try:
|
||||||
|
self.handle_json(self.ws.recv())
|
||||||
|
except (WSException, OSError, ValueError):
|
||||||
|
if not self.stopping:
|
||||||
|
self.disconnect()
|
||||||
|
self.connect()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
"""
|
||||||
|
stop() -> None
|
||||||
|
|
||||||
|
Close the connection to the room.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.stopping = True
|
||||||
|
self.disconnect()
|
||||||
|
|
||||||
|
def join(self):
|
||||||
|
"""
|
||||||
|
join() -> None
|
||||||
|
|
||||||
|
Join the thread spawned by launch.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.thread:
|
||||||
|
self.thread.join()
|
||||||
|
|
||||||
|
def add_callback(self, ptype, callback, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
add_callback(ptype, callback) -> None
|
||||||
|
|
||||||
|
Add a function to be called when a packet of type ptype is received.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not ptype in self.callbacks:
|
||||||
|
self.callbacks[ptype] = []
|
||||||
|
|
||||||
|
callback_info = {
|
||||||
|
"callback": callback,
|
||||||
|
"args": args,
|
||||||
|
"kwargs": kwargs
|
||||||
|
}
|
||||||
|
|
||||||
|
self.callbacks[ptype].append(callback_info)
|
||||||
|
|
||||||
|
def add_id_callback(self, pid, callback, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
add_id_callback(pid, callback) -> None
|
||||||
|
|
||||||
|
Add a function to be called when a packet with id pid is received.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not pid in self.id_callbacks:
|
||||||
|
self.id_callbacks[pid] = []
|
||||||
|
|
||||||
|
callback_info = {
|
||||||
|
"callback": callback,
|
||||||
|
"args": args,
|
||||||
|
"kwargs": kwargs
|
||||||
|
}
|
||||||
|
|
||||||
|
self.id_callbacks[pid].append(callback_info)
|
||||||
|
|
||||||
|
def call_callback(self, event, *args):
|
||||||
|
"""
|
||||||
|
call_callback(event) -> None
|
||||||
|
|
||||||
|
Call all callbacks subscribed to the event with *args.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if event in self.callbacks:
|
||||||
|
for c_info in self.callbacks[event]:
|
||||||
|
c = c_info["callback"]
|
||||||
|
args = c_info["args"] + args
|
||||||
|
kwargs = c_info["kwargs"]
|
||||||
|
c(*args, **kwargs)
|
||||||
|
|
||||||
|
def call_id_callback(self, pid, *args):
|
||||||
|
"""
|
||||||
|
call_callback(pid) -> None
|
||||||
|
|
||||||
|
Call all callbacks subscribed to the pid with *args.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if pid in self.id_callbacks:
|
||||||
|
for c_info in self.id_callbacks.pop(pid):
|
||||||
|
c = c_info["callback"]
|
||||||
|
args = c_info["args"] + args
|
||||||
|
kwargs = c_info["kwargs"]
|
||||||
|
c(*args, **kwargs)
|
||||||
|
|
||||||
|
def handle_json(self, data):
|
||||||
|
"""
|
||||||
|
handle_json(data) -> None
|
||||||
|
|
||||||
|
Handle incoming 'raw' data.
|
||||||
|
"""
|
||||||
|
|
||||||
|
packet = json.loads(data)
|
||||||
|
self.handle_packet(packet)
|
||||||
|
|
||||||
|
def handle_packet(self, packet):
|
||||||
|
"""
|
||||||
|
handle_packet(ptype, data) -> None
|
||||||
|
|
||||||
|
Handle incoming packets
|
||||||
|
"""
|
||||||
|
|
||||||
|
if "data" in packet:
|
||||||
|
data = packet["data"]
|
||||||
|
else:
|
||||||
|
data = None
|
||||||
|
|
||||||
|
self.call_callback(packet["type"], data)
|
||||||
|
|
||||||
|
if "id" in packet:
|
||||||
|
self.call_id_callback(packet["id"], data)
|
||||||
|
|
||||||
|
def send_json(self, data):
|
||||||
|
"""
|
||||||
|
send_json(data) -> None
|
||||||
|
|
||||||
|
Send 'raw' json.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.ws:
|
||||||
|
try:
|
||||||
|
self.ws.send(json.dumps(data))
|
||||||
|
except WSException:
|
||||||
|
self.disconnect()
|
||||||
|
|
||||||
|
def send_packet(self, ptype, **kwargs):
|
||||||
|
"""
|
||||||
|
send_packet(ptype, **kwargs) -> None
|
||||||
|
|
||||||
|
Send a formatted packet.
|
||||||
|
"""
|
||||||
|
|
||||||
|
packet = {
|
||||||
|
"type": ptype,
|
||||||
|
"data": kwargs or None,
|
||||||
|
"id": str(self.send_id)
|
||||||
|
}
|
||||||
|
self.send_id += 1
|
||||||
|
self.send_json(packet)
|
||||||
100
bugbot/download.py
Normal file
100
bugbot/download.py
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
import connection
|
||||||
|
|
||||||
|
class Downloader():
|
||||||
|
"""
|
||||||
|
Update or redownload a room's log.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, room, logfile, password=None):
|
||||||
|
"""
|
||||||
|
room - name of the room to download the logs of
|
||||||
|
logfile - path to the file to save the log in
|
||||||
|
password - password of said room, optional
|
||||||
|
"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _handle_ping_event(self, data):
|
||||||
|
"""
|
||||||
|
_handle_ping_event(data) -> None
|
||||||
|
|
||||||
|
Pong!
|
||||||
|
"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _handle_bounce_event(self, data):
|
||||||
|
"""
|
||||||
|
_handle_bounce_event(data) -> None
|
||||||
|
|
||||||
|
Authenticate if possible, otherwise give up and stop.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _handle_auth_reply(self, data):
|
||||||
|
"""
|
||||||
|
_handle_auth_reply(data) -> None
|
||||||
|
|
||||||
|
Disconnect if authentication unsucessful.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _handle_disconnect_event(self, data):
|
||||||
|
"""
|
||||||
|
_handle_disconnect_event(data) -> None
|
||||||
|
|
||||||
|
Immediately disconnect.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _handle_snapshot_event(self, data):
|
||||||
|
"""
|
||||||
|
_handle_snapshot_event(data) -> None
|
||||||
|
|
||||||
|
Save messages and request further messages
|
||||||
|
"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _handle_get_message_reply(self, data):
|
||||||
|
"""
|
||||||
|
_handle_get_message_reply(data) -> None
|
||||||
|
|
||||||
|
Append untruncated message to log file and then continue
|
||||||
|
transferring the messages from the temp file to the
|
||||||
|
log file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _handle_log_reply(self, data):
|
||||||
|
"""
|
||||||
|
_handle_log_reply(data) -> None
|
||||||
|
|
||||||
|
Save messages received to temp file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
def launch(self):
|
||||||
|
"""
|
||||||
|
launch() -> None
|
||||||
|
|
||||||
|
Start the download in a separate thread.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
def transfer(self):
|
||||||
|
"""
|
||||||
|
transfer() -> None
|
||||||
|
|
||||||
|
Transfer the messages from the temporary file to the log file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pass
|
||||||
0
bugbot/format.py
Normal file
0
bugbot/format.py
Normal file
0
bugbot/log.py
Normal file
0
bugbot/log.py
Normal file
0
config.json
Normal file
0
config.json
Normal file
0
main.py
Normal file
0
main.py
Normal file
Loading…
Add table
Add a link
Reference in a new issue