fix help command without argument, change from default DEBUG level to individually configured, comments/docs/formatting, improved imports, remove REFRESH CLIENT LIST request

This commit is contained in:
Xevion
2021-01-22 14:35:54 -06:00
parent e862540e14
commit 0dcfa234ad
6 changed files with 50 additions and 28 deletions

View File

@@ -29,7 +29,6 @@ class Requests:
The Requests class provides a universal naming for the types of requests that can be made and received.
"""
REQUEST_NICK = 'REQUEST_NICK' # Send the server the client's nickname
REFRESH_CONNECTIONS_LIST = 'REFRESH_CLIENT_LIST' # Send the client all connections to the server and their information
GET_MESSAGE_HISTORY = 'GET_MESSAGE_HISTORY' # Send the client a detailed list of all messages sent up to a certain point.

View File

@@ -1,4 +1,3 @@
import logging
logging.basicConfig(level=logging.DEBUG,
format='[%(asctime)s] [%(levelname)s] [%(threadName)s] %(message)s')
logging.basicConfig(format='[%(asctime)s] [%(levelname)s] [%(threadName)s] %(message)s')

View File

@@ -11,6 +11,7 @@ if TYPE_CHECKING:
from server.handler import Client
logger = logging.getLogger('commands')
logger.setLevel(logging.DEBUG)
class CommandHandler:
@@ -24,10 +25,13 @@ class CommandHandler:
self.client = client
self.aliases = {}
self.commands = {}
self.__install_command(self.reroll, 'Reroll', 'reroll', 'Change your color to a random color.', aliases=['newcolor'])
self.__install_command(self.help, 'Help', 'help', 'Get info on a given commands functionality and more.', aliases=['about', 'doc'])
self.__install_command(self.reroll, 'Reroll', 'reroll', 'Change your color to a random color.',
aliases=['newcolor'])
self.__install_command(self.help, 'Help', 'help', 'Get info on a given commands functionality and more.',
aliases=['about', 'doc'])
def __install_command(self, func: Callable, name: str = None, command_name: str = None, description: str = '', aliases: List[str] = None):
def __install_command(self, func: Callable, name: str = None, command_name: str = None, description: str = '',
aliases: List[str] = None):
if aliases is None:
aliases = []
@@ -75,21 +79,24 @@ class CommandHandler:
Randomly change the client's color to a different color.
"""
i = 0
newColor = self.client.color
new_color = self.client.color
choices = constants.Colors.has_contrast(float(minimum_contrast))
while i < 50 and newColor == self.client.color:
newColor = random.choice(choices)
while i < 50 and new_color == self.client.color:
new_color = random.choice(choices)
self.client.color = newColor
contrast = round(constants.Colors.WHITE.contrast_ratio(newColor), 1)
return f'Changed your color to {newColor.name} ({newColor.hex}/{contrast})'
self.client.color = new_color
contrast = round(constants.Colors.WHITE.contrast_ratio(new_color), 1)
return f'Changed your color to {new_color.name} ({new_color.hex}/{contrast})'
def help(self, command: str) -> Optional[str]:
def help(self, command: str = None) -> Optional[str]:
"""
Print information about a given command
:return:
"""
if command is None:
return f"'help' requires 1 argument (command: str)."
if command in self.aliases.keys():
command = self.aliases[command]

View File

@@ -6,6 +6,8 @@ from typing import List
import constants
logger = logging.getLogger('database')
logger.setLevel(logging.DEBUG)
lock = threading.Lock()
@@ -20,6 +22,9 @@ class Database(object):
return self.__isClosed
def close(self) -> None:
"""
Closes the database connection and record it's connection status.
"""
if self.__isClosed:
logger.warning(f'Database connection is already closed.', exc_info=True)
else:
@@ -30,7 +35,9 @@ class Database(object):
with lock:
cur = self.conn.cursor()
try:
# check if the table exists
cur.execute('''SELECT name FROM sqlite_master WHERE type='table' AND name='?';''', 'message')
# if it doesn't exist, create the table and report it
if cur.fetchone() is None:
self.conn.execute('''CREATE TABLE message
(id INTEGER PRIMARY KEY,
@@ -55,6 +62,7 @@ class Database(object):
:return: The unique integer primary key chosen for the message, i.e. it's ID.
"""
with lock:
with self.conn:
cur = self.conn.cursor()
try:
cur.execute('''INSERT INTO message (nickname, connection_hash, color, message, timestamp)

View File

@@ -13,9 +13,9 @@ import helpers
from exceptions import DataReceptionException
from server import db
from server.commands import CommandHandler
from server.db import Database
logger = logging.getLogger('handler')
logger.setLevel(logging.DEBUG)
class BaseClient(object):
@@ -23,12 +23,12 @@ class BaseClient(object):
def __init__(self, conn: socket.socket, all_clients: List['Client'], address) -> None:
self.conn, self.all_clients, self.address = conn, all_clients, address
self.db: Optional[Database] = None
self.db: Optional[db.Database] = None
def connect_database(self):
if self.db is None:
logger.debug('Connecting client to database.')
self.db = Database()
self.db = db.Database()
def send(self, message: bytes) -> None:
"""Sends a pre-encoded message to this client."""
@@ -89,7 +89,7 @@ class Client(BaseClient):
def connect_database(self) -> None:
if self.db is None:
logger.debug(f'Connecting Client({self.id[:8]}) to the database.')
self.db = Database()
self.db = db.Database()
def request_nickname(self) -> None:
"""Send a request for the client's nickname information."""
@@ -149,13 +149,19 @@ class Client(BaseClient):
else:
logger.info(f'{self.nickname} changed their name to {nickname}')
self.nickname = nickname
# New nickname has to be sent to all clients
for client in self.all_clients:
client.send_connections_list()
def close(self) -> None:
logger.info(f'Client {self.id} closed. ({self.nickname})')
self.conn.close() # Close socket connection
self.all_clients.remove(self) # Remove the user from the global client list
self.broadcast_message(f'{self.nickname} left!') # Now we can broadcast it's exit message
self.db.conn.close() # Close database connection
# Inform all clients of the disconnected client
for client in self.all_clients:
client.send_connections_list()
self.db.close() # Close database connection
def handle(self) -> None:
self.connect_database()
@@ -164,8 +170,6 @@ class Client(BaseClient):
data = self.receive()
if data['type'] == constants.Types.REQUEST:
if data['request'] == constants.Requests.REFRESH_CONNECTIONS_LIST:
self.send_connections_list()
if data['request'] == constants.Requests.GET_MESSAGE_HISTORY:
self.send_message_history(
limit=data.get('limit', 50), time_limit=data.get('time_limit', 60 * 30)

View File

@@ -12,6 +12,7 @@ server.bind((host, port))
server.listen()
logger = logging.getLogger('server')
logger.setLevel(logging.DEBUG)
clients = []
@@ -28,6 +29,10 @@ def receive():
clients.append(client)
client.request_nickname()
# Inform all clients of new client, give new client connections list
for client in clients:
client.send_connections_list()
# Start Handling Thread For Client
thread = threading.Thread(target=client.handle, name=client.id[:8])
thread.start()