diff --git a/client/__main__.py b/client/__main__.py index bc7c8bc..8845a51 100644 --- a/client/__main__.py +++ b/client/__main__.py @@ -19,74 +19,98 @@ import re import sys import argparse -import socket +from socket import socket, AF_INET, SOCK_STREAM import json +import hashlib from datetime import datetime from client_log_config import logger +import select -def createParser(): +def create_parser(): parser = argparse.ArgumentParser() parser.add_argument('host', nargs='?', default='localhost') parser.add_argument('port', nargs='?', default='7777') + parser.add_argument('-m', '--mode', nargs='?', type=str, default='w') return parser +def read_response(response, mode='w'): + response = json.loads( + data.decode('utf-8') + ) + # разобрать сообщение сервера; + + if response.get('response') == 200: + if response.get('alert'): + if mode == 'w': + logger.debug(f"Response Message: {response.get('alert')}") + print( + f"Response Message: {response.get('alert')}" + ) + else: + print( + f"{response.get('user')['account_name']}: {response.get('user')['status']}\n", + f"Server: {response.get('alert')}" + ) + else: + logger.critical(f"Error request: {response.get('error')}") -parser = createParser() + +parser = create_parser() args = parser.parse_args(sys.argv[1:]) port = int(re.search('[0-9]{2,}', args.port).group(0)) -sock = socket.socket() + try: + sock = socket(AF_INET, SOCK_STREAM) sock.connect((args.host, port)) - # сформировать presence-сообщение; - # В формате JIM - - msg_presence = json.dumps( - { - "action": "presence", - "time": datetime.now().timestamp(), - "type": "status", - "user": { - "account_name": input("Enter user Name: "), - "status": input("Status message: ") - } - } - ) - """ - msg_action = json.dumps( - { - "action": input("Enter action (lower_text): "), - "data": input("Enter data: ") - } - ) - #sock.send(msg_action.encode()) - """ - - # отправить сообщение серверу; - sock.send(msg_presence.encode()) - - - # получить ответ сервера; - data = sock.recv(1024) - response = json.loads( - data.decode('utf-8') - ) - # разобрать сообщение сервера; - - if response.get('response') == 200: - if response.get('alert'): - logger.debug(f"Response Message: {response.get('alert')}") - print( - f"Response Message: {response.get('alert')}" + if args.mode == 'w': + username = input("Enter user Name: ") + while True: + # сформировать presence-сообщение; + # В формате JIM + + hash_obj = hashlib.sha1() + hash_obj.update(b'secret_key') + + msg_presence = json.dumps( + { + "action": "presence", + "time": datetime.now().timestamp(), + "type": "status", + "user": { + "account_name": username, + "status": input("Your message: ") + } + } + ) + # отправить сообщение серверу; + sock.send(msg_presence.encode()) + """ + msg_action = json.dumps( + { + "action": input("Enter action (lower_text): "), + "data": input("Enter data: ") + } ) + + sock.send(msg_action.encode()) + """ + # получить ответ сервера; + data = sock.recv(1024) + read_response(data) else: - logger.critical(f"Error request: {response.get('error')}") - + while True: # Постоянный опрос сервера + data = sock.recv(1024) + read_response(data, 'r') + #sock.close() +except KeyboardInterrupt: + logger.info(f"client closed") sock.close() + except Exception: logger.critical(f'client cant conntect to host:{args.host} port{port}') diff --git a/log/client.log b/log/client.log index 7461fbb..d8a4c53 100644 --- a/log/client.log +++ b/log/client.log @@ -1,3 +1,26 @@ 2019-03-22 23:36:02,696 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 2019-03-22 23:36:10,249 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 2019-03-22 23:36:23,476 - DEBUG - client - __main__ - Response Message: Hi Vasya +2019-03-23 11:25:04,037 - DEBUG - client - __main__ - Response Message: Hi Ggg +2019-03-23 11:25:11,259 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-23 11:25:22,627 - DEBUG - client - __main__ - Response Message: Hi gfd +2019-03-23 11:25:30,862 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-23 11:25:40,404 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-23 12:13:24,608 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-23 12:14:04,399 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-23 12:16:05,126 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-23 12:18:41,129 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-23 12:19:35,400 - DEBUG - client - __main__ - Response Message: Hi gfdgfd +2019-03-23 12:20:32,307 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-23 12:21:07,810 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-23 12:21:47,540 - CRITICAL - client - __main__ - Error request: Wrong request format +2019-03-23 12:22:47,865 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-23 12:23:13,817 - CRITICAL - client - __main__ - Error request: Wrong request format +2019-03-23 12:23:32,678 - CRITICAL - client - __main__ - Error request: Wrong request format +2019-03-23 12:24:35,061 - DEBUG - client - __main__ - Response Message: Hi gd +2019-03-23 12:48:59,584 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-23 12:49:09,084 - DEBUG - client - __main__ - Response Message: Hi fds +2019-03-23 12:49:15,536 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-23 13:23:06,491 - INFO - client - __main__ - client closed +2019-03-23 13:23:06,560 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-23 13:23:06,560 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 diff --git a/log/server.log b/log/server.log index 1ddc1a2..04af256 100644 --- a/log/server.log +++ b/log/server.log @@ -2,3 +2,40 @@ 2019-03-22 23:36:17,416 - INFO - __main__ - Client detected ('127.0.0.1', 55376) 2019-03-22 23:36:23,476 - INFO - log - function send_presence() call from __main__ 2019-03-22 23:36:23,476 - INFO - __main__ - client ('127.0.0.1', 55376) closed +2019-03-23 11:08:40,768 - INFO - __main__ - Client detected ('127.0.0.1', 60578) +2019-03-23 11:25:04,036 - INFO - log - function send_presence() call from __main__ +2019-03-23 11:25:04,037 - INFO - __main__ - client ('127.0.0.1', 60578) closed +2019-03-23 11:25:10,396 - INFO - __main__ - client ('127.0.0.1', 60578) closed +2019-03-23 11:25:21,471 - INFO - __main__ - Client detected ('127.0.0.1', 60845) +2019-03-23 11:25:22,626 - INFO - log - function send_presence() call from __main__ +2019-03-23 11:25:22,627 - INFO - __main__ - client ('127.0.0.1', 60845) closed +2019-03-23 11:25:29,652 - INFO - __main__ - client ('127.0.0.1', 60845) closed +2019-03-23 12:13:21,472 - INFO - __main__ - Client detected ('127.0.0.1', 61483) +2019-03-23 12:14:01,870 - INFO - __main__ - Client detected ('127.0.0.1', 61505) +2019-03-23 12:16:03,934 - INFO - __main__ - Client detected ('127.0.0.1', 61527) +2019-03-23 12:18:39,648 - INFO - __main__ - Client detected ('127.0.0.1', 61640) +2019-03-23 12:19:33,574 - INFO - __main__ - Client detected ('127.0.0.1', 61656) +2019-03-23 12:19:35,400 - INFO - log - function send_presence() call from __main__ +2019-03-23 12:19:35,400 - INFO - __main__ - client ('127.0.0.1', 61656) closed +2019-03-23 12:20:23,242 - INFO - __main__ - Client detected ('127.0.0.1', 61662) +2019-03-23 12:21:00,099 - INFO - __main__ - Client detected ('127.0.0.1', 61667) +2019-03-23 12:21:38,675 - INFO - __main__ - Client detected ('127.0.0.1', 61672) +2019-03-23 12:21:47,540 - CRITICAL - __main__ - error 400 bad request: {'action': 'lower_text', 'data': 'GGG'} +2019-03-23 12:21:47,540 - INFO - __main__ - client ('127.0.0.1', 61672) closed +2019-03-23 12:22:41,135 - INFO - __main__ - client ('127.0.0.1', 61672) closed +2019-03-23 12:23:07,415 - INFO - __main__ - Client detected ('127.0.0.1', 61688) +2019-03-23 12:23:13,816 - CRITICAL - __main__ - error 400 bad request: {'action': 'lowe_text', 'data': 'FFFF'} +2019-03-23 12:23:13,816 - INFO - __main__ - client ('127.0.0.1', 61688) closed +2019-03-23 12:23:26,904 - INFO - __main__ - Client detected ('127.0.0.1', 61690) +2019-03-23 12:23:32,678 - CRITICAL - __main__ - error 400 bad request: {'action': 'lower_text', 'data': 'GGGG'} +2019-03-23 12:23:32,678 - INFO - __main__ - client ('127.0.0.1', 61690) closed +2019-03-23 12:24:33,255 - INFO - __main__ - Client detected ('127.0.0.1', 61696) +2019-03-23 12:24:35,060 - INFO - log - function send_presence() call from __main__ +2019-03-23 12:24:35,061 - INFO - __main__ - client ('127.0.0.1', 61696) closed +2019-03-23 12:48:58,086 - INFO - __main__ - client ('127.0.0.1', 61696) closed +2019-03-23 12:49:07,582 - INFO - __main__ - Client detected ('127.0.0.1', 61938) +2019-03-23 12:49:09,084 - INFO - log - function send_presence() call from handlers +2019-03-23 12:49:14,361 - INFO - __main__ - client ('127.0.0.1', 61938) closed +2019-03-23 13:20:20,749 - INFO - __main__ - Client detected ('127.0.0.1', 62287) +2019-03-23 13:21:57,519 - INFO - log - function send_presence() call from handlers +2019-03-23 13:21:57,520 - INFO - __main__ - Client detected ('127.0.0.1', 62288) diff --git a/server/__main__.py b/server/__main__.py index e9b7ea7..705023f 100644 --- a/server/__main__.py +++ b/server/__main__.py @@ -2,14 +2,10 @@ __author__ = "Андрей Петров" import sys - - - import json -import socket +from socket import socket, AF_INET, SOCK_STREAM import argparse - - +import select @@ -19,6 +15,7 @@ ) from routes import resolve from server_log_config import logger +from handlers import handle_client_request def createParser(): parser = argparse.ArgumentParser() @@ -26,52 +23,90 @@ def createParser(): parser.add_argument('-p', '--port', nargs='?', default='7777') return parser +def get_client_fullname(host, port): + return f'{ host }:{ port }' + + +def read_requests(r_clients, all_clients): + """ Чтение запросов из списка клиентов + """ + responses = [] + #print('read_requests') + for sock in r_clients: + try: + print('client 1') + data = sock.recv(1024).decode('utf-8') + #responses[sock] = json.loads(data) + responses.append(json.loads(data)) + print(responses[sock]) + except: + print('Клиент {} {} отключился'.format(sock.fileno(), sock.getpeername())) + #all_clients.remove(sock) + + return responses + + +def write_responses(requests, w_clients, all_clients): + for req in requests: + #print('write_responses') + #print(req) + # Разобрать все запросы + response = handle_client_request(req) + response_string = json.dumps(response) + for sock in w_clients: + try: + # отправить всем + sock.send(response_string.encode('utf-8')) + #print('Сообщение отправлено') + except: # Сокет недоступен, клиент отключился + print('Клиент {} {} отключился'.format(sock.fileno(), sock.getpeername())) + #sock.close() + #all_clients.remove(sock) + requests.remove(req) + parser = createParser() args = parser.parse_args(sys.argv[1:]) -sock = socket.socket() +sock = socket(AF_INET, SOCK_STREAM) sock.bind((args.addr, int(args.port))) sock.listen(5) +sock.settimeout(0.2) + +requests = [] +connections = [] +clients = [] try: while True: - # принимает сообщение клиента; - client, address = sock.accept() - logger.info(f'Client detected {address}') - - data = client.recv(1024) - request = json.loads( - data.decode('utf-8') - ) - - if validate_request(request): - controller = resolve(request.get('action')) - if controller: - try: - response = controller(request) - except Exception as err: - logger.critical(err, exc_info=True) - response = make_response( - request, 500, - error='Internal server error.' - ) - else: - logger.critical(f"error 404 controller: {request.get('action')} not found") - response = make_404(request) + try: + conn, addr = sock.accept() # Проверка подключений + except OSError as e: + pass # timeout вышел else: - response = make_400(request) - logger.critical(f"error 400 bad request: {request}") + print("Получен запрос на соединение от %s" % str(addr)) + clients.append(conn) + finally: + # Проверить наличие событий ввода-вывода + wait = 0 + r = [] + w = [] + + + try: + r, w, e = select.select(clients, clients, [], wait) + + #print('r:', len(r), ' w:', len(w), ' e:', len(e)) + requests = read_requests(r, clients) # Сохраним запросы клиентов + if requests: + write_responses(requests, w, clients) # Выполним отправку ответов + except: + pass # Ничего не делать, если какой-то клиент отключился + - if response.get('code') == 400: - logger.error(f'Bad Request: { action_name } request: { request }') - response_string = json.dumps(response) - client.send(response_string.encode('utf-8')) - client.close() - logger.info(f"client {address} closed") except KeyboardInterrupt: - logger.info(f"client {address} closed") + #logger.info(f"server {address} closed") sock.close() diff --git a/server/authentication.py b/server/authentication.py new file mode 100644 index 0000000..d3ce166 --- /dev/null +++ b/server/authentication.py @@ -0,0 +1,21 @@ +from functools import wraps +from protocol import make_response + + +def login_required(func): + @wraps(func) + def wrap(request, *args, **kwrags): + if request.get('user'): + return func(request, *args, **kwrags) + return make_response(request, 403, 'Access denied.') + return wrap + + +class LoginRequired: + def __call__(self, func): + @wraps(func) + def wrap(request, *args, **kwrags): + if request.get('user'): + return func(request, *args, **kwrags) + return make_response(request, 403, 'Access denied.') + return wrap diff --git a/server/customlogging.py b/server/customlogging.py new file mode 100644 index 0000000..7f50af6 --- /dev/null +++ b/server/customlogging.py @@ -0,0 +1,49 @@ +import logging +from functools import wraps + + +logger = logging.getLogger('stack_logger') +handler = logging.StreamHandler() + +formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(module)s - %(message)s') +handler.setFormatter(formatter) +handler.setLevel(logging.DEBUG) +logger.addHandler(handler) +logger.setLevel(logging.DEBUG) + + +def stack_logging(message=''): + + def decorator(func): + @wraps(func) + def wrap(request, *args, **kwrags): + format_mapping = { + 'func_name': func.__name__, + 'request_data': request.get('data') + } + func_call = func(request, *args, **kwrags) + logger.debug( + message % format_mapping, stack_info=True + ) + return func_call + return wrap + return decorator + + +class StackLogging: + def __init__(self, message=''): + self._message = message + + def __call__(self, func): + @wraps(func) + def wrap(request, *args, **kwrags): + format_mapping = { + 'func_name': func.__name__, + 'request_data': request.get('data'), + } + func_call = func(request, *args, **kwrags) + logger.debug( + self._message % format_mapping, stack_info=True + ) + return func_call + return wrap diff --git a/server/handlers.py b/server/handlers.py new file mode 100644 index 0000000..a6d6e3c --- /dev/null +++ b/server/handlers.py @@ -0,0 +1,27 @@ +from protocol import ( + validate_request, make_response, + make_400, make_404 +) +from routes import resolve +from server_log_config import logger + + +def handle_client_request(request): + if validate_request(request): + controller = resolve(request.get('action')) + if controller: + try: + return controller(request) + except Exception as err: + logger.critical(err, exc_info=True) + return make_response( + request, 500, + error='Internal server error.' + ) + else: + logger.critical(f"error 404 controller: {request.get('action')} not found") + return make_404(request) + else: + logger.critical(f"error 400 bad request: {request}") + return make_400(request) + diff --git a/server/presence/controllers.py b/server/presence/controllers.py index aff2945..c24cadf 100644 --- a/server/presence/controllers.py +++ b/server/presence/controllers.py @@ -9,5 +9,5 @@ def send_presence(request): return make_response( request, 200, - alert=f"Hi {user['account_name']}" + alert=f"{user['account_name']} Your message is send " ) diff --git a/server/protocol.py b/server/protocol.py index 0a269fe..6886d51 100644 --- a/server/protocol.py +++ b/server/protocol.py @@ -2,6 +2,7 @@ def validate_request(raw): + #print(raw) request_time = raw.get('time') request_action = raw.get('action') if request_time and request_action: diff --git a/server/text/controllers.py b/server/text/controllers.py index c4cc8b7..0baff3d 100644 --- a/server/text/controllers.py +++ b/server/text/controllers.py @@ -1,8 +1,13 @@ from protocol import make_response, make_400 +from authentication import login_required, LoginRequired from log import log +from customlogging import stack_logging, StackLogging + +@stack_logging('Function %(func_name)s was called.') @log +@login_required def get_upper_text(request): data = request.get('data') if not data: @@ -13,7 +18,11 @@ def get_upper_text(request): data.upper() ) + + +@StackLogging('Request body: %(request_data)s') @log +@LoginRequired() def get_lower_text(request): data = request.get('data') if not data: