diff --git a/hw_lesson_08/client/__main__.py b/hw_lesson_08/client/__main__.py new file mode 100644 index 0000000..1ba45ed --- /dev/null +++ b/hw_lesson_08/client/__main__.py @@ -0,0 +1,74 @@ +from argparse import ArgumentParser +import socket +import datetime +import logging +import jim +import settings + + +def get_presence_msg(action, data): + time = datetime.datetime.now() + msg = { + "action": action, + "time": time.isoformat(), + "user": { + "account_name": "anonim", + "status": "Yep, I am here!" + }, + "data": data + } + + return jim.pack(msg) + + +host = getattr(settings, 'HOST', '127.0.0.1') +port = getattr(settings, 'PORT', 7777) + +parser = ArgumentParser() +parser.add_argument('-a', '--addr', type=str, help='Sets ip address') +parser.add_argument('-p', '--port', type=int, help='Sets port') +parser.add_argument('-m', '--mode', type=str, default='w') + +args = parser.parse_args() + +if args.addr: + host = args.addr +if args.port: + port = args.port + +logger = logging.getLogger('main') +handler = logging.FileHandler('client.log', encoding=settings.ENCODING) +formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') + +handler.setLevel(logging.DEBUG) +handler.setFormatter(formatter) + +logger.setLevel(logging.DEBUG) +logger.addHandler(handler) + +try: + sock = socket.socket() + sock.connect((host, port)) + logger.info(f'Client started with {host}:{port}') + print(f'Client started with {host}:{port}') + + if args.mode == 'w': + while True: + action = input('Enter action to send:') + data = input('Enter data to send:') + + msg = get_presence_msg(action, data) + sock.sendall(msg) + else: + while True: + response = sock.recv(settings.BUFFERSIZE) + response = jim.unpack(response) + logger.info(f'Got next response from server: {response}') + print(f'Got next response from server: {response}') + +except KeyboardInterrupt: + logger.info('Client closed') + print('Client closed') + + + diff --git a/hw_lesson_08/client/client.log b/hw_lesson_08/client/client.log new file mode 100644 index 0000000..b0624c8 --- /dev/null +++ b/hw_lesson_08/client/client.log @@ -0,0 +1,9 @@ +2019-04-25 20:53:53,396 - INFO - Client started with 127.0.0.1:7777 +2019-04-25 20:54:16,453 - INFO - Client started with 127.0.0.1:7777 +2019-04-25 20:55:07,847 - INFO - Client closed +2019-04-25 20:57:12,278 - INFO - Client started with 127.0.0.1:7777 +2019-04-25 20:57:15,885 - INFO - Client started with 127.0.0.1:7777 +2019-04-25 20:57:27,881 - INFO - Got next response from server: {'action': 'echo', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'time': 1556215047.880693, 'data': 'test', 'code': 200} +2019-04-25 20:57:47,815 - INFO - Got next response from server: {'action': 'now', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'time': 1556215067.814953, 'data': '2019.04.25', 'code': 200} +2019-04-25 20:57:58,583 - INFO - Got next response from server: {'action': 'bad', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'time': 1556215078.583333, 'data': 'Action is not supported', 'code': 404} +2019-04-25 20:58:30,582 - INFO - Client closed diff --git a/hw_lesson_08/client/jim.py b/hw_lesson_08/client/jim.py new file mode 100644 index 0000000..88c01a8 --- /dev/null +++ b/hw_lesson_08/client/jim.py @@ -0,0 +1,21 @@ +import json + + +def pack(dict_msg): + """ + Создание сообщения, пригодного для отправки через TCP + :param dict_msg: dict + :return: str + """ + str_msg = json.dumps(dict_msg) + return str_msg.encode('utf-8') + + +def unpack(bt_str): + """ + Распаквка полученного сообщения + :param bt_str: str + :return: dict + """ + str_decoded = bt_str.decode('utf-8') + return json.loads(str_decoded) \ No newline at end of file diff --git a/hw_lesson_08/client/settings.py b/hw_lesson_08/client/settings.py new file mode 100644 index 0000000..e4e3a8a --- /dev/null +++ b/hw_lesson_08/client/settings.py @@ -0,0 +1,4 @@ +HOST = "127.0.0.1" +PORT = 7777 +BUFFERSIZE = 1024 +ENCODING = 'utf-8' diff --git a/hw_lesson_08/server/__main__.py b/hw_lesson_08/server/__main__.py new file mode 100644 index 0000000..cb6fbca --- /dev/null +++ b/hw_lesson_08/server/__main__.py @@ -0,0 +1,109 @@ +from argparse import ArgumentParser +import socket +import datetime +import logging +import select +import threading +import jim +import settings +from routes import resolve, get_server_routes +from protocol import ( + validate_request, make_response, + make_400, make_404 +) + +from handlers import handle_request + + +def get_response_msg(): + msg = { + "response": 200, + "alert": "Необязательное сообщение/уведомление" + } + return jim.pack(msg) + + +def read_client_data(client, requests, buffersize): + b_request = client.recv(buffersize) + requests.append(b_request) + + +def write_client_data(client, response): + client.send(response) + + +host = getattr(settings, 'HOST', '127.0.0.1') +port = getattr(settings, 'PORT', 7777) + +parser = ArgumentParser() +parser.add_argument('-a', '--addr', type=str, help='Sets ip address') +parser.add_argument('-p', '--port', type=int, help='Sets port') + +args = parser.parse_args() + +if args.addr: + host = args.addr +if args.port: + port = args.port + +handler = logging.FileHandler('main.log', encoding=settings.ENCODING) +error_handler = logging.FileHandler('error.log', encoding=settings.ENCODING) + +logging.basicConfig( + level=logging.DEBUG, + format='%(asctime)s - %(levelname)s - %(message)s', + handlers=[ + handler, + error_handler, + logging.StreamHandler(), + ] +) + + +def main(): + + requests = [] + connections = [] + + try: + sock = socket.socket() + sock.bind((host, port)) + sock.settimeout(0) + sock.listen(5) + logging.info(f'Server started with {host}:{port}') + while True: + try: + client, address = sock.accept() + logging.info(f'Client detected {address}') + connections.append(client) + except Exception: + pass + + if connections != []: + rlist, wlist, xlist = select.select( + connections, connections, connections, 0 + ) + + for r_client in rlist: + thread = threading.Thread( + target=read_client_data, + args=(r_client, requests, settings.BUFFERSIZE) + ) + thread.start() + + if requests: + b_request = requests.pop() + b_response = handle_request(b_request) + + for w_client in wlist: + thread = threading.Thread( + target=write_client_data, + args=(w_client, b_response) + ) + thread.start() + + except KeyboardInterrupt: + logging.info('Server closed') + + +main() diff --git a/hw_lesson_08/server/dates/__init__.py b/hw_lesson_08/server/dates/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hw_lesson_08/server/dates/controllers.py b/hw_lesson_08/server/dates/controllers.py new file mode 100644 index 0000000..1537e16 --- /dev/null +++ b/hw_lesson_08/server/dates/controllers.py @@ -0,0 +1,11 @@ +from datetime import datetime +from protocol import make_response +from decorators import logged + + +@logged +def get_date_now(request): + date = datetime.now() + return make_response( + request, 200, date.strftime('%Y.%m.%d') + ) diff --git a/hw_lesson_08/server/dates/routes.py b/hw_lesson_08/server/dates/routes.py new file mode 100644 index 0000000..87907f8 --- /dev/null +++ b/hw_lesson_08/server/dates/routes.py @@ -0,0 +1,7 @@ +from .controllers import ( + get_date_now +) + +routes = [ + {'action': 'now', 'controller': get_date_now} +] \ No newline at end of file diff --git a/hw_lesson_08/server/dates/tests/test_dates_now.py b/hw_lesson_08/server/dates/tests/test_dates_now.py new file mode 100644 index 0000000..61498f8 --- /dev/null +++ b/hw_lesson_08/server/dates/tests/test_dates_now.py @@ -0,0 +1,17 @@ +from datetime import datetime + +from dates.controllers import get_date_now + + +def test_get_date_now(): + date = datetime.now() + s_date = date.strftime('%Y.%m.%d') + + request = { + 'time': datetime.now().timestamp(), + 'action': 'now' + } + + response = get_date_now(request) + + assert response.get('data') == s_date \ No newline at end of file diff --git a/hw_lesson_08/server/decorators.py b/hw_lesson_08/server/decorators.py new file mode 100644 index 0000000..fac222e --- /dev/null +++ b/hw_lesson_08/server/decorators.py @@ -0,0 +1,14 @@ +import logging +import sys + +logger = logging.getLogger('decorators') + + +def logged(func): + def wrapper(*args, **kwargs): + logger.debug(f'{ func.__name__ } - with args:{ args }, { kwargs }') + caller = sys._getframe(1).f_code.co_name + logger.debug(f'{func.__name__} called from function: {caller}') + return func(*args, **kwargs) + + return wrapper diff --git a/hw_lesson_08/server/echo/__init__.py b/hw_lesson_08/server/echo/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hw_lesson_08/server/echo/controllers.py b/hw_lesson_08/server/echo/controllers.py new file mode 100644 index 0000000..7f16bac --- /dev/null +++ b/hw_lesson_08/server/echo/controllers.py @@ -0,0 +1,14 @@ +from datetime import datetime +from protocol import make_response, make_400 +from decorators import logged + + +@logged +def get_echo(request): + data = request.get('data') + if data: + return make_response( + request, 200, data + ) + + return make_400(request) \ No newline at end of file diff --git a/hw_lesson_08/server/echo/routes.py b/hw_lesson_08/server/echo/routes.py new file mode 100644 index 0000000..dee9ee3 --- /dev/null +++ b/hw_lesson_08/server/echo/routes.py @@ -0,0 +1,7 @@ +from .controllers import ( + get_echo +) + +routes = [ + {'action': 'echo', 'controller': get_echo} +] \ No newline at end of file diff --git a/hw_lesson_08/server/echo/tests/test_echo.py b/hw_lesson_08/server/echo/tests/test_echo.py new file mode 100644 index 0000000..5ee2df6 --- /dev/null +++ b/hw_lesson_08/server/echo/tests/test_echo.py @@ -0,0 +1,15 @@ +from datetime import datetime + +from echo.controllers import get_echo + +def test_get_echo(): + request = { + 'time': datetime.now().timestamp(), + 'action': 'now', + 'data': 'Hello' + } + + response = get_echo(request) + + assert response.get('data') == 'Hello' + diff --git a/hw_lesson_08/server/echo/tests/test_echo_bad_request.py b/hw_lesson_08/server/echo/tests/test_echo_bad_request.py new file mode 100644 index 0000000..326c938 --- /dev/null +++ b/hw_lesson_08/server/echo/tests/test_echo_bad_request.py @@ -0,0 +1,13 @@ +from datetime import datetime + +from echo.controllers import get_echo + +def test_echo_bad_request(): + request = { + 'time': datetime.now().timestamp(), + 'action': 'now' + } + + response = get_echo(request) + + assert response.get('code') == 400 diff --git a/hw_lesson_08/server/error.log b/hw_lesson_08/server/error.log new file mode 100644 index 0000000..c0e4d5c --- /dev/null +++ b/hw_lesson_08/server/error.log @@ -0,0 +1,36 @@ +2019-04-25 20:53:31,685 - INFO - Server started with 127.0.0.1:7777 +2019-04-25 20:53:53,396 - INFO - Client detected ('127.0.0.1', 41878) +2019-04-25 20:54:16,453 - INFO - Client detected ('127.0.0.1', 41880) +2019-04-25 20:54:28,942 - DEBUG - validate_request - with args:({'action': 'now', 'time': '2019-04-25T20:54:28.942254', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'hello'},), {} +2019-04-25 20:54:28,942 - DEBUG - validate_request called from function: handle_request +2019-04-25 20:54:28,974 - DEBUG - get_date_now - with args:({'action': 'now', 'time': '2019-04-25T20:54:28.942254', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'hello'},), {} +2019-04-25 20:54:28,974 - DEBUG - get_date_now called from function: handle_request +2019-04-25 20:54:28,974 - DEBUG - make_response - with args:({'action': 'now', 'time': '2019-04-25T20:54:28.942254', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'hello'}, 200, '2019.04.25'), {} +2019-04-25 20:54:28,974 - DEBUG - make_response called from function: get_date_now +2019-04-25 20:54:28,974 - INFO - Request is valid and processed by controller +2019-04-25 20:55:01,467 - INFO - Server closed +2019-04-25 20:57:05,445 - INFO - Server started with 127.0.0.1:7777 +2019-04-25 20:57:12,278 - INFO - Client detected ('127.0.0.1', 41882) +2019-04-25 20:57:15,885 - INFO - Client detected ('127.0.0.1', 41884) +2019-04-25 20:57:27,878 - DEBUG - validate_request - with args:({'action': 'echo', 'time': '2019-04-25T20:57:27.877941', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'test'},), {} +2019-04-25 20:57:27,878 - DEBUG - validate_request called from function: handle_request +2019-04-25 20:57:27,880 - DEBUG - get_echo - with args:({'action': 'echo', 'time': '2019-04-25T20:57:27.877941', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'test'},), {} +2019-04-25 20:57:27,880 - DEBUG - get_echo called from function: handle_request +2019-04-25 20:57:27,880 - DEBUG - make_response - with args:({'action': 'echo', 'time': '2019-04-25T20:57:27.877941', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'test'}, 200, 'test'), {} +2019-04-25 20:57:27,880 - DEBUG - make_response called from function: get_echo +2019-04-25 20:57:27,880 - INFO - Request is valid and processed by controller +2019-04-25 20:57:47,814 - DEBUG - validate_request - with args:({'action': 'now', 'time': '2019-04-25T20:57:47.813459', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'test'},), {} +2019-04-25 20:57:47,814 - DEBUG - validate_request called from function: handle_request +2019-04-25 20:57:47,814 - DEBUG - get_date_now - with args:({'action': 'now', 'time': '2019-04-25T20:57:47.813459', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'test'},), {} +2019-04-25 20:57:47,814 - DEBUG - get_date_now called from function: handle_request +2019-04-25 20:57:47,814 - DEBUG - make_response - with args:({'action': 'now', 'time': '2019-04-25T20:57:47.813459', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'test'}, 200, '2019.04.25'), {} +2019-04-25 20:57:47,814 - DEBUG - make_response called from function: get_date_now +2019-04-25 20:57:47,814 - INFO - Request is valid and processed by controller +2019-04-25 20:57:58,582 - DEBUG - validate_request - with args:({'action': 'bad', 'time': '2019-04-25T20:57:58.581712', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'test'},), {} +2019-04-25 20:57:58,582 - DEBUG - validate_request called from function: handle_request +2019-04-25 20:57:58,582 - ERROR - Action bad does not exits +2019-04-25 20:57:58,582 - DEBUG - make_404 - with args:({'action': 'bad', 'time': '2019-04-25T20:57:58.581712', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'test'},), {} +2019-04-25 20:57:58,582 - DEBUG - make_404 called from function: handle_request +2019-04-25 20:57:58,583 - DEBUG - make_response - with args:({'action': 'bad', 'time': '2019-04-25T20:57:58.581712', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'test'}, 404, 'Action is not supported'), {} +2019-04-25 20:57:58,583 - DEBUG - make_response called from function: make_404 +2019-04-25 20:58:26,614 - INFO - Server closed diff --git a/hw_lesson_08/server/handlers.py b/hw_lesson_08/server/handlers.py new file mode 100644 index 0000000..1e4e298 --- /dev/null +++ b/hw_lesson_08/server/handlers.py @@ -0,0 +1,38 @@ +import logging +import jim +import settings +from routes import resolve, get_server_routes +from protocol import ( + validate_request, make_response, + make_400, make_404 +) + + +def handle_request(raw_request): + request = jim.unpack(raw_request) + + action_name = request.get('action') + + if validate_request(request): + controller = resolve(action_name) + if controller: + try: + response = controller(request) + if response.get('code') != 200: + logging.error('Wrong request format') + else: + logging.info(f'Request is valid and processed by controller') + except Exception as err: + logging.critical(err) + response = make_response( + request, 500, 'Internal server error' + ) + else: + logging.error(f'Action {action_name} does not exits') + response = make_404(request) + else: + logging.error('Request is not valid') + response = make_400(request) + + return jim.pack(response) + diff --git a/hw_lesson_08/server/jim.py b/hw_lesson_08/server/jim.py new file mode 100644 index 0000000..88c01a8 --- /dev/null +++ b/hw_lesson_08/server/jim.py @@ -0,0 +1,21 @@ +import json + + +def pack(dict_msg): + """ + Создание сообщения, пригодного для отправки через TCP + :param dict_msg: dict + :return: str + """ + str_msg = json.dumps(dict_msg) + return str_msg.encode('utf-8') + + +def unpack(bt_str): + """ + Распаквка полученного сообщения + :param bt_str: str + :return: dict + """ + str_decoded = bt_str.decode('utf-8') + return json.loads(str_decoded) \ No newline at end of file diff --git a/hw_lesson_08/server/main.log b/hw_lesson_08/server/main.log new file mode 100644 index 0000000..c0e4d5c --- /dev/null +++ b/hw_lesson_08/server/main.log @@ -0,0 +1,36 @@ +2019-04-25 20:53:31,685 - INFO - Server started with 127.0.0.1:7777 +2019-04-25 20:53:53,396 - INFO - Client detected ('127.0.0.1', 41878) +2019-04-25 20:54:16,453 - INFO - Client detected ('127.0.0.1', 41880) +2019-04-25 20:54:28,942 - DEBUG - validate_request - with args:({'action': 'now', 'time': '2019-04-25T20:54:28.942254', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'hello'},), {} +2019-04-25 20:54:28,942 - DEBUG - validate_request called from function: handle_request +2019-04-25 20:54:28,974 - DEBUG - get_date_now - with args:({'action': 'now', 'time': '2019-04-25T20:54:28.942254', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'hello'},), {} +2019-04-25 20:54:28,974 - DEBUG - get_date_now called from function: handle_request +2019-04-25 20:54:28,974 - DEBUG - make_response - with args:({'action': 'now', 'time': '2019-04-25T20:54:28.942254', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'hello'}, 200, '2019.04.25'), {} +2019-04-25 20:54:28,974 - DEBUG - make_response called from function: get_date_now +2019-04-25 20:54:28,974 - INFO - Request is valid and processed by controller +2019-04-25 20:55:01,467 - INFO - Server closed +2019-04-25 20:57:05,445 - INFO - Server started with 127.0.0.1:7777 +2019-04-25 20:57:12,278 - INFO - Client detected ('127.0.0.1', 41882) +2019-04-25 20:57:15,885 - INFO - Client detected ('127.0.0.1', 41884) +2019-04-25 20:57:27,878 - DEBUG - validate_request - with args:({'action': 'echo', 'time': '2019-04-25T20:57:27.877941', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'test'},), {} +2019-04-25 20:57:27,878 - DEBUG - validate_request called from function: handle_request +2019-04-25 20:57:27,880 - DEBUG - get_echo - with args:({'action': 'echo', 'time': '2019-04-25T20:57:27.877941', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'test'},), {} +2019-04-25 20:57:27,880 - DEBUG - get_echo called from function: handle_request +2019-04-25 20:57:27,880 - DEBUG - make_response - with args:({'action': 'echo', 'time': '2019-04-25T20:57:27.877941', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'test'}, 200, 'test'), {} +2019-04-25 20:57:27,880 - DEBUG - make_response called from function: get_echo +2019-04-25 20:57:27,880 - INFO - Request is valid and processed by controller +2019-04-25 20:57:47,814 - DEBUG - validate_request - with args:({'action': 'now', 'time': '2019-04-25T20:57:47.813459', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'test'},), {} +2019-04-25 20:57:47,814 - DEBUG - validate_request called from function: handle_request +2019-04-25 20:57:47,814 - DEBUG - get_date_now - with args:({'action': 'now', 'time': '2019-04-25T20:57:47.813459', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'test'},), {} +2019-04-25 20:57:47,814 - DEBUG - get_date_now called from function: handle_request +2019-04-25 20:57:47,814 - DEBUG - make_response - with args:({'action': 'now', 'time': '2019-04-25T20:57:47.813459', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'test'}, 200, '2019.04.25'), {} +2019-04-25 20:57:47,814 - DEBUG - make_response called from function: get_date_now +2019-04-25 20:57:47,814 - INFO - Request is valid and processed by controller +2019-04-25 20:57:58,582 - DEBUG - validate_request - with args:({'action': 'bad', 'time': '2019-04-25T20:57:58.581712', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'test'},), {} +2019-04-25 20:57:58,582 - DEBUG - validate_request called from function: handle_request +2019-04-25 20:57:58,582 - ERROR - Action bad does not exits +2019-04-25 20:57:58,582 - DEBUG - make_404 - with args:({'action': 'bad', 'time': '2019-04-25T20:57:58.581712', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'test'},), {} +2019-04-25 20:57:58,582 - DEBUG - make_404 called from function: handle_request +2019-04-25 20:57:58,583 - DEBUG - make_response - with args:({'action': 'bad', 'time': '2019-04-25T20:57:58.581712', 'user': {'account_name': 'anonim', 'status': 'Yep, I am here!'}, 'data': 'test'}, 404, 'Action is not supported'), {} +2019-04-25 20:57:58,583 - DEBUG - make_response called from function: make_404 +2019-04-25 20:58:26,614 - INFO - Server closed diff --git a/hw_lesson_08/server/protocol.py b/hw_lesson_08/server/protocol.py new file mode 100644 index 0000000..f717b34 --- /dev/null +++ b/hw_lesson_08/server/protocol.py @@ -0,0 +1,34 @@ +from datetime import datetime +from decorators import logged + + +@logged +def validate_request(raw): + request_time = raw.get('time') + request_action = raw.get('action') + + if request_action and request_time: + return True + + return False + + +@logged +def make_response(request, code, data=None): + return { + 'action': request.get('action'), + 'user': request.get('user'), + 'time': datetime.now().timestamp(), + 'data': data, + 'code': code + } + + +@logged +def make_400(request): + return make_response(request, 400, 'Wrong request format') + + +@logged +def make_404(request): + return make_response(request, 404, 'Action is not supported') diff --git a/hw_lesson_08/server/routes.py b/hw_lesson_08/server/routes.py new file mode 100644 index 0000000..ef688ad --- /dev/null +++ b/hw_lesson_08/server/routes.py @@ -0,0 +1,26 @@ +from functools import reduce +from settings import INSTALLED_MODULES + + +def get_server_routes(): + return reduce( + lambda value, item: value + [getattr(item, 'routes', None)], + reduce( + lambda value, item: value + [getattr(item, 'routes', None)], + reduce( + lambda value, item: value + [__import__(f'{ item }.routes')], + INSTALLED_MODULES, + [] + ), + [] + ), + [] + ) + + +def resolve(action, routes=None): + routes_mapping = {} + for controller_route in routes or get_server_routes(): + for route in controller_route: + routes_mapping[route['action']] = route['controller'] + return routes_mapping.get(action, None) \ No newline at end of file diff --git a/hw_lesson_08/server/settings.py b/hw_lesson_08/server/settings.py new file mode 100644 index 0000000..06d5d92 --- /dev/null +++ b/hw_lesson_08/server/settings.py @@ -0,0 +1,9 @@ +HOST = "127.0.0.1" +PORT = 7777 +BUFFERSIZE = 1024 +ENCODING = 'utf-8' + +INSTALLED_MODULES = [ + 'dates', + 'echo' +] diff --git a/hw_lesson_08/server/tests/test_get_server_routes.py b/hw_lesson_08/server/tests/test_get_server_routes.py new file mode 100644 index 0000000..b35d16b --- /dev/null +++ b/hw_lesson_08/server/tests/test_get_server_routes.py @@ -0,0 +1,12 @@ +from routes import get_server_routes + +def test_get_server_routes(): + routes = get_server_routes() + routes_mapping = {} + for controller_route in routes or get_server_routes(): + for route in controller_route: + routes_mapping[route['action']] = route['controller'] + + assert routes_mapping.get('now') is not None + assert routes_mapping.get('echo') is not None + assert routes_mapping.get('bad_action') is None diff --git a/hw_lesson_08/server/tests/test_make_400.py b/hw_lesson_08/server/tests/test_make_400.py new file mode 100644 index 0000000..39b25cd --- /dev/null +++ b/hw_lesson_08/server/tests/test_make_400.py @@ -0,0 +1,13 @@ +from datetime import datetime +from protocol import make_400 + +def test_make_400(): + request = { + 'time': datetime.now().timestamp(), + 'action': 'now', + 'data': 'Hello' + } + + response = make_400(request) + + assert response.get("code") == 400 \ No newline at end of file diff --git a/hw_lesson_08/server/tests/test_make_404.py b/hw_lesson_08/server/tests/test_make_404.py new file mode 100644 index 0000000..5c034fd --- /dev/null +++ b/hw_lesson_08/server/tests/test_make_404.py @@ -0,0 +1,13 @@ +from datetime import datetime +from protocol import make_404 + +def test_make_404(): + request = { + 'time': datetime.now().timestamp(), + 'action': 'now', + 'data': 'Hello' + } + + response = make_404(request) + + assert response.get("code") == 404 \ No newline at end of file diff --git a/hw_lesson_08/server/tests/test_make_response.py b/hw_lesson_08/server/tests/test_make_response.py new file mode 100644 index 0000000..1764639 --- /dev/null +++ b/hw_lesson_08/server/tests/test_make_response.py @@ -0,0 +1,16 @@ +from datetime import datetime +from protocol import make_response + +def test_make_400(): + request = { + 'time': datetime.now().timestamp(), + 'action': 'now', + 'user': 'User' + } + + response = make_response(request, 200, 'Hello') + + assert response.get("code") == 200 + assert response.get("data") == 'Hello' + assert response.get("user") == 'User' + assert response.get("action") == 'now' \ No newline at end of file diff --git a/hw_lesson_08/server/tests/test_pack_unpack.py b/hw_lesson_08/server/tests/test_pack_unpack.py new file mode 100644 index 0000000..91e9435 --- /dev/null +++ b/hw_lesson_08/server/tests/test_pack_unpack.py @@ -0,0 +1,15 @@ +from datetime import datetime +from jim import pack, unpack + +def test_pack_unpack(): + request = { + 'time': datetime.now().timestamp(), + 'action': 'now', + 'data': 'Hello' + } + + b_request = pack(request) + request = unpack(b_request) + + assert request.get('action') == 'now' + assert request.get('data') == 'Hello' diff --git a/hw_lesson_08/server/tests/test_resolve.py b/hw_lesson_08/server/tests/test_resolve.py new file mode 100644 index 0000000..7400366 --- /dev/null +++ b/hw_lesson_08/server/tests/test_resolve.py @@ -0,0 +1,11 @@ +from routes import resolve + +def test_resolve(): + controller = resolve('now') + assert controller is not None + + controller = resolve('echo') + assert controller is not None + + controller = resolve('bad_action') + assert controller is None diff --git a/hw_lesson_08/server/tests/test_validate_request.py b/hw_lesson_08/server/tests/test_validate_request.py new file mode 100644 index 0000000..8a09a67 --- /dev/null +++ b/hw_lesson_08/server/tests/test_validate_request.py @@ -0,0 +1,19 @@ +from datetime import datetime +from protocol import validate_request + +def test_make_400(): + request = { + 'time': datetime.now().timestamp(), + 'action': 'now', + 'user': 'User' + } + + is_valid = validate_request(request) + + assert is_valid == True + + request = {'user': 'User'} + + is_valid = validate_request(request) + + assert is_valid == False