From 72f482d8bc1593176557b8a67c382c1e9611f113 Mon Sep 17 00:00:00 2001 From: PAND-or Date: Fri, 15 Mar 2019 02:48:43 +0300 Subject: [PATCH 01/12] hw04 --- lesson04/client/__main__.py | 81 +++++++++++++++++++ lesson04/server/__init__.py | 3 + lesson04/server/__main__.py | 79 ++++++++++++++++++ lesson04/server/routes.py | 20 +++++ lesson04/server/test_module/controllers.py | 5 ++ lesson04/server/test_module/routes.py | 6 ++ lesson04/server/text/controllers.py | 6 ++ lesson04/server/text/routes.py | 9 +++ lesson04/server/text/tests/__init__.py | 0 .../server/text/tests/test_controllers.py | 9 +++ 10 files changed, 218 insertions(+) create mode 100644 lesson04/client/__main__.py create mode 100644 lesson04/server/__init__.py create mode 100644 lesson04/server/__main__.py create mode 100644 lesson04/server/routes.py create mode 100644 lesson04/server/test_module/controllers.py create mode 100644 lesson04/server/test_module/routes.py create mode 100644 lesson04/server/text/controllers.py create mode 100644 lesson04/server/text/routes.py create mode 100644 lesson04/server/text/tests/__init__.py create mode 100644 lesson04/server/text/tests/test_controllers.py diff --git a/lesson04/client/__main__.py b/lesson04/client/__main__.py new file mode 100644 index 0000000..713d571 --- /dev/null +++ b/lesson04/client/__main__.py @@ -0,0 +1,81 @@ +#!/usr/bin/python3 +__author__ = "Андрей Петров" + +""" +клиент отправляет запрос серверу; +сервер отвечает соответствующим кодом результата. Клиент и сервер должны быть реализованы в виде отдельных скриптов, +содержащих соответствующие функции. + +Функции клиента: +сформировать presence-сообщение; +отправить сообщение серверу; +получить ответ сервера; +разобрать сообщение сервера; +параметры командной строки скрипта client.py []: addr — ip-адрес сервера; +port — tcp-порт на сервере, +по умолчанию 7777. + +""" +import re +import sys +import argparse +import socket +import json +from datetime import datetime + + +def createParser(): + parser = argparse.ArgumentParser() + parser.add_argument('host', nargs='?', default='localhost') + parser.add_argument('port', nargs='?', default='7777') + return parser + + +parser = createParser() +args = parser.parse_args(sys.argv[1:]) + +port = int(re.search('[0-9]{2,}', args.port).group(0)) + +sock = socket.socket() +sock.connect((args.host, port)) + +# сформировать presence-сообщение; +# В формате JIM +msg_presence = json.dumps( + { + "action": "presence", + "time": datetime.now().timestamp(), + "type": "status", + "user": { + "account_name": "User Name", + "status": "Yep, I am here!" + } + } +) + +msg_lower = json.dumps( + { + "action": "lower_text", + "data": 'GGGGG' + } +) + +# отправить сообщение серверу; +sock.send(msg_presence.encode()) +#sock.send(msg_lower.encode()) + +# получить ответ сервера; +data = sock.recv(1024) +response = json.loads( + data.decode('utf-8') +) +# разобрать сообщение сервера; +if response.get('response') == 200: + print( + f"Response Message: {response.get('msg')}" + ) +else: + print( + f"Error: {response.get('error')}" + ) +sock.close() diff --git a/lesson04/server/__init__.py b/lesson04/server/__init__.py new file mode 100644 index 0000000..da70eca --- /dev/null +++ b/lesson04/server/__init__.py @@ -0,0 +1,3 @@ +from .controllers import * +from .routes import * + diff --git a/lesson04/server/__main__.py b/lesson04/server/__main__.py new file mode 100644 index 0000000..f7a47e6 --- /dev/null +++ b/lesson04/server/__main__.py @@ -0,0 +1,79 @@ +#!/usr/bin/python3 +__author__ = "Андрей Петров" + +""" +клиент отправляет запрос серверу; +сервер отвечает соответствующим кодом результата. Клиент и сервер должны быть реализованы в виде отдельных скриптов, +содержащих соответствующие функции. + +Функции сервера: +принимает сообщение клиента; +формирует ответ клиенту; +отправляет ответ клиенту; +имеет параметры командной строки: -p — TCP-порт для работы (по умолчанию использует 7777); +-a — IP-адрес для прослушивания (по умолчанию слушает все доступные адреса). +""" + +import sys +import os +import json +import socket +import argparse +from routes import get_server_routes + + +def createParser(): + parser = argparse.ArgumentParser() + parser.add_argument('-a', '--addr', nargs='?', default='') + parser.add_argument('-p', '--port', nargs='?', default='7777') + return parser + + +parser = createParser() +args = parser.parse_args(sys.argv[1:]) + + +sock = socket.socket() +sock.bind((args.addr, int(args.port))) +sock.listen(5) + + +## Без этого не работал код из урока +os.chdir('server') +sys.path.append(os.getcwd()) +## + +while True: + # принимает сообщение клиента; + client, address = sock.accept() + + data = client.recv(1024) + request = json.loads( + data.decode('utf-8') + ) + + # формирует ответ клиенту; + + client_action = request.get('action') + + resolved_routes = list( + filter( + lambda itm: itm.get('action') == client_action, + get_server_routes() + ) + ) + + route = resolved_routes[0] if resolved_routes else None + if route: + controller = route.get('controller') + response = controller(request.get('data'), request) + + else: + response = { + "response": 400, + "error": "Wrong action, try again" + } + + # отправляет ответ клиенту; + client.send(json.dumps(response).encode('utf-8')) + client.close() diff --git a/lesson04/server/routes.py b/lesson04/server/routes.py new file mode 100644 index 0000000..9d5b03a --- /dev/null +++ b/lesson04/server/routes.py @@ -0,0 +1,20 @@ +import os +from importlib import import_module +from functools import reduce + + +def get_server_routes(): + return reduce( + lambda routes, module: routes + getattr(module, 'routes', []), + reduce( + lambda modules, dir: modules + [import_module(f'{dir}.routes')], + filter( + lambda itm: os.path.isdir(itm) and itm != '__pycache__', + os.listdir() + ), + [] + ), + [] + ) + + diff --git a/lesson04/server/test_module/controllers.py b/lesson04/server/test_module/controllers.py new file mode 100644 index 0000000..036ec40 --- /dev/null +++ b/lesson04/server/test_module/controllers.py @@ -0,0 +1,5 @@ +def send_presence(data, request): + return { + "response": 200, + "msg": f"Hi {request.get('user')['account_name']}" + } diff --git a/lesson04/server/test_module/routes.py b/lesson04/server/test_module/routes.py new file mode 100644 index 0000000..1eb5c4c --- /dev/null +++ b/lesson04/server/test_module/routes.py @@ -0,0 +1,6 @@ +from .controllers import send_presence + + +routes = [ + {'action': 'presence', 'controller': send_presence} +] \ No newline at end of file diff --git a/lesson04/server/text/controllers.py b/lesson04/server/text/controllers.py new file mode 100644 index 0000000..f320424 --- /dev/null +++ b/lesson04/server/text/controllers.py @@ -0,0 +1,6 @@ +def get_lower_text(data): + return data.lower() + + +def get_upper_text(data): + return data.upper() diff --git a/lesson04/server/text/routes.py b/lesson04/server/text/routes.py new file mode 100644 index 0000000..290e162 --- /dev/null +++ b/lesson04/server/text/routes.py @@ -0,0 +1,9 @@ +from .controllers import get_lower_text +from .controllers import get_upper_text + + + +routes = [ + {'action': 'lower_text', 'controller': get_lower_text}, + {'action': 'upper_text', 'controller': get_upper_text} +] \ No newline at end of file diff --git a/lesson04/server/text/tests/__init__.py b/lesson04/server/text/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lesson04/server/text/tests/test_controllers.py b/lesson04/server/text/tests/test_controllers.py new file mode 100644 index 0000000..ee83895 --- /dev/null +++ b/lesson04/server/text/tests/test_controllers.py @@ -0,0 +1,9 @@ +from text.controllers import ( + get_lower_text, get_upper_text +) + +TEXT_TEST = 'SOME TEXT' +ASSERT_TEXT = 'some text' + +def test_get_lower_text_is_lower(): + assert get_lower_text(TEXT_TEST) == ASSERT_TEXT From 0f2a73a19d4bc2f2dfce86504d6e95dddd135f5c Mon Sep 17 00:00:00 2001 From: PAND-or Date: Fri, 15 Mar 2019 03:39:00 +0300 Subject: [PATCH 02/12] test --- lesson04/server/__init__.py | 3 --- lesson04/server/__main__.py | 2 +- lesson04/server/routes.py | 2 +- lesson04/server/test_module/controllers.py | 2 +- lesson04/server/text/controllers.py | 6 ----- lesson04/server/text/routes.py | 9 -------- lesson04/server/text/tests/__init__.py | 0 .../server/text/tests/test_controllers.py | 9 -------- lesson04/tests/test_server.py | 22 +++++++++++++++++++ 9 files changed, 25 insertions(+), 30 deletions(-) delete mode 100644 lesson04/server/__init__.py delete mode 100644 lesson04/server/text/controllers.py delete mode 100644 lesson04/server/text/routes.py delete mode 100644 lesson04/server/text/tests/__init__.py delete mode 100644 lesson04/server/text/tests/test_controllers.py create mode 100644 lesson04/tests/test_server.py diff --git a/lesson04/server/__init__.py b/lesson04/server/__init__.py deleted file mode 100644 index da70eca..0000000 --- a/lesson04/server/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .controllers import * -from .routes import * - diff --git a/lesson04/server/__main__.py b/lesson04/server/__main__.py index f7a47e6..c72ea45 100644 --- a/lesson04/server/__main__.py +++ b/lesson04/server/__main__.py @@ -66,7 +66,7 @@ def createParser(): route = resolved_routes[0] if resolved_routes else None if route: controller = route.get('controller') - response = controller(request.get('data'), request) + response = controller(request) else: response = { diff --git a/lesson04/server/routes.py b/lesson04/server/routes.py index 9d5b03a..3451d82 100644 --- a/lesson04/server/routes.py +++ b/lesson04/server/routes.py @@ -9,7 +9,7 @@ def get_server_routes(): reduce( lambda modules, dir: modules + [import_module(f'{dir}.routes')], filter( - lambda itm: os.path.isdir(itm) and itm != '__pycache__', + lambda itm: os.path.isdir(itm) and itm != '__pycache__' and itm != '.pytest_cache', os.listdir() ), [] diff --git a/lesson04/server/test_module/controllers.py b/lesson04/server/test_module/controllers.py index 036ec40..4b1996d 100644 --- a/lesson04/server/test_module/controllers.py +++ b/lesson04/server/test_module/controllers.py @@ -1,4 +1,4 @@ -def send_presence(data, request): +def send_presence(request): return { "response": 200, "msg": f"Hi {request.get('user')['account_name']}" diff --git a/lesson04/server/text/controllers.py b/lesson04/server/text/controllers.py deleted file mode 100644 index f320424..0000000 --- a/lesson04/server/text/controllers.py +++ /dev/null @@ -1,6 +0,0 @@ -def get_lower_text(data): - return data.lower() - - -def get_upper_text(data): - return data.upper() diff --git a/lesson04/server/text/routes.py b/lesson04/server/text/routes.py deleted file mode 100644 index 290e162..0000000 --- a/lesson04/server/text/routes.py +++ /dev/null @@ -1,9 +0,0 @@ -from .controllers import get_lower_text -from .controllers import get_upper_text - - - -routes = [ - {'action': 'lower_text', 'controller': get_lower_text}, - {'action': 'upper_text', 'controller': get_upper_text} -] \ No newline at end of file diff --git a/lesson04/server/text/tests/__init__.py b/lesson04/server/text/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/lesson04/server/text/tests/test_controllers.py b/lesson04/server/text/tests/test_controllers.py deleted file mode 100644 index ee83895..0000000 --- a/lesson04/server/text/tests/test_controllers.py +++ /dev/null @@ -1,9 +0,0 @@ -from text.controllers import ( - get_lower_text, get_upper_text -) - -TEXT_TEST = 'SOME TEXT' -ASSERT_TEXT = 'some text' - -def test_get_lower_text_is_lower(): - assert get_lower_text(TEXT_TEST) == ASSERT_TEXT diff --git a/lesson04/tests/test_server.py b/lesson04/tests/test_server.py new file mode 100644 index 0000000..46ed84b --- /dev/null +++ b/lesson04/tests/test_server.py @@ -0,0 +1,22 @@ +import sys +sys.path.append('../') + +from server.test_module.controllers import send_presence + +REQUEST = { + "action": "presence", + "type": "status", + "user": { + "account_name": "User Name", + "status": "Yep, I am here!" + } + } + +RESPONSE = { + "response": 200, + "msg": "Hi User Name" + } + + +def presence_msg_request_to_response(): + assert send_presence(REQUEST) == RESPONSE From 8968df6952b4ede3e3bc44363507a5a08984ef8b Mon Sep 17 00:00:00 2001 From: PAND-or Date: Tue, 19 Mar 2019 00:53:10 +0300 Subject: [PATCH 03/12] lesson05 init --- lesson05/__init__.py | 0 lesson05/client/__main__.py | 86 +++++++++++++++++++ lesson05/default.log | 24 ++++++ lesson05/server/__main__.py | 81 +++++++++++++++++ lesson05/server/presence/controllers.py | 12 +++ lesson05/server/presence/routes.py | 6 ++ lesson05/server/protocol.py | 29 +++++++ lesson05/server/routes.py | 29 +++++++ lesson05/server/settings.py | 9 ++ .../tests/protocol/test_make_response.py | 43 ++++++++++ .../tests/protocol/test_validate_request.py | 28 ++++++ lesson05/server/tests/routes/test_resolve.py | 19 ++++ lesson05/server/text/controllers.py | 23 +++++ lesson05/server/text/routes.py | 9 ++ .../server/text/tests/controllers/__init__.py | 0 .../text/tests/controllers/test_lower.py | 38 ++++++++ .../text/tests/controllers/test_upper.py | 38 ++++++++ 17 files changed, 474 insertions(+) create mode 100644 lesson05/__init__.py create mode 100644 lesson05/client/__main__.py create mode 100644 lesson05/default.log create mode 100644 lesson05/server/__main__.py create mode 100644 lesson05/server/presence/controllers.py create mode 100644 lesson05/server/presence/routes.py create mode 100644 lesson05/server/protocol.py create mode 100644 lesson05/server/routes.py create mode 100644 lesson05/server/settings.py create mode 100644 lesson05/server/tests/protocol/test_make_response.py create mode 100644 lesson05/server/tests/protocol/test_validate_request.py create mode 100644 lesson05/server/tests/routes/test_resolve.py create mode 100644 lesson05/server/text/controllers.py create mode 100644 lesson05/server/text/routes.py create mode 100644 lesson05/server/text/tests/controllers/__init__.py create mode 100644 lesson05/server/text/tests/controllers/test_lower.py create mode 100644 lesson05/server/text/tests/controllers/test_upper.py diff --git a/lesson05/__init__.py b/lesson05/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lesson05/client/__main__.py b/lesson05/client/__main__.py new file mode 100644 index 0000000..27d384e --- /dev/null +++ b/lesson05/client/__main__.py @@ -0,0 +1,86 @@ +#!/usr/bin/python3 +__author__ = "Андрей Петров" + +""" +клиент отправляет запрос серверу; +сервер отвечает соответствующим кодом результата. Клиент и сервер должны быть реализованы в виде отдельных скриптов, +содержащих соответствующие функции. + +Функции клиента: +сформировать presence-сообщение; +отправить сообщение серверу; +получить ответ сервера; +разобрать сообщение сервера; +параметры командной строки скрипта client.py []: addr — ip-адрес сервера; +port — tcp-порт на сервере, +по умолчанию 7777. + +""" +import re +import sys +import argparse +import socket +import json +from datetime import datetime + + +def createParser(): + parser = argparse.ArgumentParser() + parser.add_argument('host', nargs='?', default='localhost') + parser.add_argument('port', nargs='?', default='7777') + return parser + + +parser = createParser() +args = parser.parse_args(sys.argv[1:]) + +port = int(re.search('[0-9]{2,}', args.port).group(0)) + +sock = socket.socket() +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'): + print( + f"Response Message: {response.get('alert')}" + ) +else: + print( + f"Error: {response.get('error')}" + ) +sock.close() diff --git a/lesson05/default.log b/lesson05/default.log new file mode 100644 index 0000000..40914a5 --- /dev/null +++ b/lesson05/default.log @@ -0,0 +1,24 @@ +2019-03-18 21:38:58,556 - DEBUG - Client detected ('127.0.0.1', 57458) +2019-03-18 21:40:01,858 - DEBUG - Client detected ('127.0.0.1', 57464) +2019-03-18 21:40:10,016 - DEBUG - Client detected ('127.0.0.1', 57465) +2019-03-18 23:41:19,099 - DEBUG - Client detected ('127.0.0.1', 60493) +2019-03-18 23:42:06,300 - DEBUG - Client detected ('127.0.0.1', 60496) +2019-03-18 23:42:54,092 - DEBUG - Client detected ('127.0.0.1', 60501) +2019-03-18 23:51:58,722 - DEBUG - Client detected ('127.0.0.1', 60631) +2019-03-18 23:52:27,013 - DEBUG - Client detected ('127.0.0.1', 60633) +2019-03-18 23:53:55,819 - DEBUG - Client detected ('127.0.0.1', 60638) +2019-03-19 00:06:15,021 - DEBUG - Client detected ('127.0.0.1', 61013) +2019-03-19 00:09:42,991 - DEBUG - Client detected ('127.0.0.1', 61045) +2019-03-19 00:17:01,016 - DEBUG - Client detected ('127.0.0.1', 61226) +2019-03-19 00:21:39,446 - DEBUG - Client detected ('127.0.0.1', 61272) +2019-03-19 00:21:50,358 - DEBUG - Client detected ('127.0.0.1', 61274) +2019-03-19 00:24:33,940 - DEBUG - Client detected ('127.0.0.1', 61300) +2019-03-19 00:29:55,684 - DEBUG - Client detected ('127.0.0.1', 61404) +2019-03-19 00:30:43,120 - DEBUG - Client detected ('127.0.0.1', 61410) +2019-03-19 00:32:23,369 - DEBUG - Client detected ('127.0.0.1', 61421) +2019-03-19 00:47:00,622 - DEBUG - Client detected ('127.0.0.1', 61804) +2019-03-19 00:47:47,436 - DEBUG - Client detected ('127.0.0.1', 61807) +2019-03-19 00:48:18,901 - DEBUG - Client detected ('127.0.0.1', 61817) +2019-03-19 00:48:30,243 - DEBUG - Client detected ('127.0.0.1', 61822) +2019-03-19 00:48:41,896 - DEBUG - Client detected ('127.0.0.1', 61825) +2019-03-19 00:48:47,608 - DEBUG - Client detected ('127.0.0.1', 61827) diff --git a/lesson05/server/__main__.py b/lesson05/server/__main__.py new file mode 100644 index 0000000..6d67885 --- /dev/null +++ b/lesson05/server/__main__.py @@ -0,0 +1,81 @@ +#!/usr/bin/python3 +__author__ = "Андрей Петров" + + +import sys +import os +import json +import socket +import argparse +import logging +from datetime import datetime + +from protocol import ( + validate_request, make_response, + make_400, make_404 +) +from routes import resolve + +logger = logging.getLogger('default') +formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') +handler = logging.FileHandler('default.log') + +handler.setFormatter(formatter) +handler.setLevel(logging.DEBUG) + +logger.addHandler(handler) +logger.setLevel(logging.DEBUG) + + +def createParser(): + parser = argparse.ArgumentParser() + parser.add_argument('-a', '--addr', nargs='?', default='') + parser.add_argument('-p', '--port', nargs='?', default='7777') + return parser + + +parser = createParser() +args = parser.parse_args(sys.argv[1:]) + + +sock = socket.socket() +sock.bind((args.addr, int(args.port))) +sock.listen(5) + + +## Без этого не работал код из урока +#os.chdir('server') +#sys.path.append(os.getcwd()) +## + +try: + while True: + # принимает сообщение клиента; + client, address = sock.accept() + logger.debug(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: + response = make_response( + request, 500, + error='Internal server error.' + ) + else: + response = make_404(request) + else: + response = make_400(request) + + response_string = json.dumps(response) + client.send(response_string.encode('utf-8')) + client.close() +except KeyboardInterrupt: + sock.close() diff --git a/lesson05/server/presence/controllers.py b/lesson05/server/presence/controllers.py new file mode 100644 index 0000000..bf56412 --- /dev/null +++ b/lesson05/server/presence/controllers.py @@ -0,0 +1,12 @@ +from protocol import make_response, make_400 + + +def send_presence(request): + user = request.get('user') + if not user: + return make_400(request) + return make_response( + request, + 200, + alert=f"Hi {user['account_name']}" + ) diff --git a/lesson05/server/presence/routes.py b/lesson05/server/presence/routes.py new file mode 100644 index 0000000..6679a46 --- /dev/null +++ b/lesson05/server/presence/routes.py @@ -0,0 +1,6 @@ +from .controllers import send_presence + + +routes = [ + {'action': 'presence', 'controller': send_presence} +] diff --git a/lesson05/server/protocol.py b/lesson05/server/protocol.py new file mode 100644 index 0000000..0a269fe --- /dev/null +++ b/lesson05/server/protocol.py @@ -0,0 +1,29 @@ +from datetime import datetime + + +def validate_request(raw): + request_time = raw.get('time') + request_action = raw.get('action') + if request_time and request_action: + return True + return False + + +def make_response(request, code, data=None, error=None, alert=None): + return { + 'action': request.get('action'), + 'user': request.get('user'), + 'time': datetime.now().timestamp(), + 'data': data, + 'response': code, + 'error': error, + 'alert': alert, + } + + +def make_400(request): + return make_response(request, 400, error='Wrong request format') + + +def make_404(request): + return make_response(request, 404, error='Action is not supported.') diff --git a/lesson05/server/routes.py b/lesson05/server/routes.py new file mode 100644 index 0000000..6458acb --- /dev/null +++ b/lesson05/server/routes.py @@ -0,0 +1,29 @@ +import os +from functools import reduce +from importlib import __import__ + +from settings import INSTALLED_MODULES + + +def get_server_routes(): + return reduce( + lambda routes, module: routes + getattr(module, 'routes', []), + reduce( + lambda submodules, module: submodules + [getattr(module, 'routes', [])], + reduce ( + lambda modules, module: modules + [__import__(f'{module}.routes')], + INSTALLED_MODULES, + [] + ), + [] + ), + [] + ) + + +def resolve(action, routes=None): + routes_mapping = { + route['action']:route['controller'] + for route in routes or get_server_routes() + } + return routes_mapping.get(action, None) diff --git a/lesson05/server/settings.py b/lesson05/server/settings.py new file mode 100644 index 0000000..fe7eb4c --- /dev/null +++ b/lesson05/server/settings.py @@ -0,0 +1,9 @@ +import os + +BASE_DIR = os.path.dirname( + os.path.abspath(__file__) +) + +INSTALLED_MODULES = [ + 'text', 'presence' +] \ No newline at end of file diff --git a/lesson05/server/tests/protocol/test_make_response.py b/lesson05/server/tests/protocol/test_make_response.py new file mode 100644 index 0000000..d9d34eb --- /dev/null +++ b/lesson05/server/tests/protocol/test_make_response.py @@ -0,0 +1,43 @@ +import pytest +from datetime import datetime +from protocol import make_response + + +@pytest.fixture +def success_status(): + return 200 + + +@pytest.fixture +def valid_request(): + return { + 'action': 'upper_text', + 'time': datetime.now().timestamp() + } + + +@pytest.fixture +def assert_response(success_status): + return { + 'action': 'upper_text', + 'user': None, + 'time': datetime.now().timestamp(), + 'data': None, + 'response': success_status, + } + + +def test_make_response( + valid_request, + assert_response, + success_status +): + response = make_response( + valid_request, + success_status, + ) + + assert response.get('action') == assert_response.get('action') + assert response.get('user') == assert_response.get('user') + assert response.get('data') == assert_response.get('data') + assert response.get('code') == assert_response.get('code') diff --git a/lesson05/server/tests/protocol/test_validate_request.py b/lesson05/server/tests/protocol/test_validate_request.py new file mode 100644 index 0000000..33f13a4 --- /dev/null +++ b/lesson05/server/tests/protocol/test_validate_request.py @@ -0,0 +1,28 @@ +import pytest +from datetime import datetime +from protocol import validate_request + + +@pytest.fixture +def valid_request(): + return { + 'action': 'upper_text', + 'time': datetime.now().timestamp() + } + + +@pytest.fixture +def invalid_request(): + return {} + + +def test_validate_request_success( + valid_request +): + assert validate_request(valid_request) == True + + +def test_validate_request_fail( + invalid_request +): + assert validate_request(invalid_request) == False diff --git a/lesson05/server/tests/routes/test_resolve.py b/lesson05/server/tests/routes/test_resolve.py new file mode 100644 index 0000000..7efe1d5 --- /dev/null +++ b/lesson05/server/tests/routes/test_resolve.py @@ -0,0 +1,19 @@ +import pytest +from routes import resolve + + +@pytest.fixture +def controller(): + return lambda arg: arg + + +@pytest.fixture +def routes(controller): + return [ + {'action': 'upper_text', 'controller': controller}, + ] + + +def test_resolve(routes, controller): + resolved = resolve('upper_text', routes) + assert resolved == controller diff --git a/lesson05/server/text/controllers.py b/lesson05/server/text/controllers.py new file mode 100644 index 0000000..f2ae160 --- /dev/null +++ b/lesson05/server/text/controllers.py @@ -0,0 +1,23 @@ +from protocol import make_response, make_400 + + +def get_upper_text(request): + data = request.get('data') + if not data: + return make_400(request) + return make_response( + request, + 200, + data.upper() + ) + + +def get_lower_text(request): + data = request.get('data') + if not data: + return make_400(request) + return make_response( + request, + 200, + data.lower() + ) diff --git a/lesson05/server/text/routes.py b/lesson05/server/text/routes.py new file mode 100644 index 0000000..57b929d --- /dev/null +++ b/lesson05/server/text/routes.py @@ -0,0 +1,9 @@ +from .controllers import ( + get_upper_text, get_lower_text +) + + +routes = [ + {'action': 'upper_text', 'controller': get_upper_text}, + {'action': 'lower_text', 'controller': get_lower_text}, +] \ No newline at end of file diff --git a/lesson05/server/text/tests/controllers/__init__.py b/lesson05/server/text/tests/controllers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lesson05/server/text/tests/controllers/test_lower.py b/lesson05/server/text/tests/controllers/test_lower.py new file mode 100644 index 0000000..1650704 --- /dev/null +++ b/lesson05/server/text/tests/controllers/test_lower.py @@ -0,0 +1,38 @@ +import pytest +from datetime import datetime +from text.controllers import get_lower_text + + +@pytest.fixture +def lower_text_request(): + return { + 'action': 'lower_text', + 'time': datetime.now().timestamp(), + 'data': 'LOWER TEXT', + } + + +@pytest.fixture +def lower_text_response_data(): + return 'lower text' + + +@pytest.fixture +def empty_request(): + return { + 'action': 'upper_text', + 'time': datetime.now().timestamp() + } + + +def test_get_lower_text_is_lower( + lower_text_request, + lower_text_response_data +): + response = get_lower_text(lower_text_request) + assert response.get('data') == lower_text_response_data + + +def test_get_lower_text_empty(empty_request): + response = get_lower_text(empty_request) + assert response.get('response') == 400 diff --git a/lesson05/server/text/tests/controllers/test_upper.py b/lesson05/server/text/tests/controllers/test_upper.py new file mode 100644 index 0000000..1dd16cd --- /dev/null +++ b/lesson05/server/text/tests/controllers/test_upper.py @@ -0,0 +1,38 @@ +import pytest +from datetime import datetime +from text.controllers import get_upper_text + + +@pytest.fixture +def valid_request(): + return { + 'action': 'upper_text', + 'time': datetime.now().timestamp(), + 'data': 'upper text', + } + + +@pytest.fixture +def empty_request(): + return { + 'action': 'upper_text', + 'time': datetime.now().timestamp() + } + + +@pytest.fixture +def upper_text_response_data(): + return 'UPPER TEXT' + + +def test_get_upper_text_is_upper( + valid_request, + upper_text_response_data +): + response = get_upper_text(valid_request) + assert response.get('data') == upper_text_response_data + + +def test_get_upper_text_empty(empty_request): + response = get_upper_text(empty_request) + assert response.get('response') == 400 From 3259911c94d4cc5add92b8427176ec490fda8f5c Mon Sep 17 00:00:00 2001 From: PAND-or Date: Tue, 19 Mar 2019 03:13:05 +0300 Subject: [PATCH 04/12] hw05 --- lesson05/__init__.py | 0 lesson05/client/__main__.py | 94 +++++++++++++++------------- lesson05/client/client_log_config.py | 18 ++++++ lesson05/log/client.log | 7 +++ lesson05/log/server.log | 5 ++ lesson05/server/__main__.py | 32 ++++------ lesson05/server/server_log_config.py | 18 ++++++ 7 files changed, 110 insertions(+), 64 deletions(-) delete mode 100644 lesson05/__init__.py create mode 100644 lesson05/client/client_log_config.py create mode 100644 lesson05/log/client.log create mode 100644 lesson05/log/server.log create mode 100644 lesson05/server/server_log_config.py diff --git a/lesson05/__init__.py b/lesson05/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/lesson05/client/__main__.py b/lesson05/client/__main__.py index 27d384e..bc7c8bc 100644 --- a/lesson05/client/__main__.py +++ b/lesson05/client/__main__.py @@ -22,6 +22,7 @@ import socket import json from datetime import datetime +from client_log_config import logger def createParser(): @@ -31,56 +32,61 @@ def createParser(): return parser + parser = createParser() args = parser.parse_args(sys.argv[1:]) port = int(re.search('[0-9]{2,}', args.port).group(0)) + sock = socket.socket() -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: ") +try: + 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()) -""" + ) + """ + msg_action = json.dumps( + { + "action": input("Enter action (lower_text): "), + "data": input("Enter data: ") + } + ) + #sock.send(msg_action.encode()) + """ + + # отправить сообщение серверу; + sock.send(msg_presence.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'): - print( - f"Response Message: {response.get('alert')}" - ) -else: - print( - f"Error: {response.get('error')}" + + # получить ответ сервера; + data = sock.recv(1024) + response = json.loads( + data.decode('utf-8') ) -sock.close() + # разобрать сообщение сервера; + + if response.get('response') == 200: + if response.get('alert'): + logger.debug(f"Response Message: {response.get('alert')}") + print( + f"Response Message: {response.get('alert')}" + ) + else: + logger.critical(f"Error request: {response.get('error')}") + + sock.close() +except Exception: + logger.critical(f'client cant conntect to host:{args.host} port{port}') diff --git a/lesson05/client/client_log_config.py b/lesson05/client/client_log_config.py new file mode 100644 index 0000000..9c31693 --- /dev/null +++ b/lesson05/client/client_log_config.py @@ -0,0 +1,18 @@ +""" +Создание именованного логгера; +Сообщения лога должны иметь следующий формат: "<дата-время> <уровеньважности> <имямодуля> <сообщение>"; +Журналирование должно производиться в лог-файл; +На стороне сервера необходимо настроить ежедневную ротацию лог-файлов. +""" + +import logging.handlers + +logger = logging.getLogger('client') +formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(module)s - %(message)s') +handler = logging.handlers.TimedRotatingFileHandler('log/client.log', when='d', interval=1, backupCount=4) + +handler.setFormatter(formatter) +handler.setLevel(logging.DEBUG) + +logger.addHandler(handler) +logger.setLevel(logging.DEBUG) \ No newline at end of file diff --git a/lesson05/log/client.log b/lesson05/log/client.log new file mode 100644 index 0000000..4f3b8ea --- /dev/null +++ b/lesson05/log/client.log @@ -0,0 +1,7 @@ + +2019-03-19 03:05:05,291 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-19 03:10:20,565 - DEBUG - client - __main__ - Response Message: Hi vASYA +2019-03-19 03:10:29,685 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-19 03:11:09,124 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-19 03:11:14,589 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-19 03:11:57,166 - DEBUG - client - __main__ - Response Message: Hi gfd diff --git a/lesson05/log/server.log b/lesson05/log/server.log new file mode 100644 index 0000000..934ad27 --- /dev/null +++ b/lesson05/log/server.log @@ -0,0 +1,5 @@ +2019-03-19 03:10:13,134 - DEBUG - __main__ - Client detected ('127.0.0.1', 64775) +2019-03-19 03:10:20,565 - DEBUG - __main__ - client ('127.0.0.1', 64775) closed +2019-03-19 03:10:56,456 - DEBUG - __main__ - Client detected ('127.0.0.1', 64819) +2019-03-19 03:11:50,998 - DEBUG - __main__ - Client detected ('127.0.0.1', 64851) +2019-03-19 03:11:57,166 - DEBUG - __main__ - client ('127.0.0.1', 64851) closed diff --git a/lesson05/server/__main__.py b/lesson05/server/__main__.py index 6d67885..c63036f 100644 --- a/lesson05/server/__main__.py +++ b/lesson05/server/__main__.py @@ -1,31 +1,24 @@ #!/usr/bin/python3 __author__ = "Андрей Петров" - import sys -import os + + + import json import socket import argparse -import logging -from datetime import datetime + + + + from protocol import ( validate_request, make_response, make_400, make_404 ) from routes import resolve - -logger = logging.getLogger('default') -formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') -handler = logging.FileHandler('default.log') - -handler.setFormatter(formatter) -handler.setLevel(logging.DEBUG) - -logger.addHandler(handler) -logger.setLevel(logging.DEBUG) - +from server_log_config import logger def createParser(): parser = argparse.ArgumentParser() @@ -43,11 +36,6 @@ def createParser(): sock.listen(5) -## Без этого не работал код из урока -#os.chdir('server') -#sys.path.append(os.getcwd()) -## - try: while True: # принимает сообщение клиента; @@ -65,17 +53,21 @@ def createParser(): try: response = controller(request) except Exception: + logger.critical(f'error 500 controller: {controller}') 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) else: response = make_400(request) + logger.critical(f"error 400 bad request: {request}") response_string = json.dumps(response) client.send(response_string.encode('utf-8')) client.close() + logger.debug(f"client {address} closed") except KeyboardInterrupt: sock.close() diff --git a/lesson05/server/server_log_config.py b/lesson05/server/server_log_config.py new file mode 100644 index 0000000..7410b14 --- /dev/null +++ b/lesson05/server/server_log_config.py @@ -0,0 +1,18 @@ +""" +Создание именованного логгера; +Сообщения лога должны иметь следующий формат: "<дата-время> <уровеньважности> <имямодуля> <сообщение>"; +Журналирование должно производиться в лог-файл; +На стороне сервера необходимо настроить ежедневную ротацию лог-файлов. +""" + +import logging.handlers + +logger = logging.getLogger('server') +formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(module)s - %(message)s') +handler = logging.handlers.TimedRotatingFileHandler('log/server.log', when='d', interval=1, backupCount=4) + +handler.setFormatter(formatter) +handler.setLevel(logging.DEBUG) + +logger.addHandler(handler) +logger.setLevel(logging.DEBUG) \ No newline at end of file From 01f350f5910288f8c04c0c430bae8700dd306754 Mon Sep 17 00:00:00 2001 From: PAND-or Date: Tue, 19 Mar 2019 03:14:45 +0300 Subject: [PATCH 05/12] delete old log --- lesson05/default.log | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 lesson05/default.log diff --git a/lesson05/default.log b/lesson05/default.log deleted file mode 100644 index 40914a5..0000000 --- a/lesson05/default.log +++ /dev/null @@ -1,24 +0,0 @@ -2019-03-18 21:38:58,556 - DEBUG - Client detected ('127.0.0.1', 57458) -2019-03-18 21:40:01,858 - DEBUG - Client detected ('127.0.0.1', 57464) -2019-03-18 21:40:10,016 - DEBUG - Client detected ('127.0.0.1', 57465) -2019-03-18 23:41:19,099 - DEBUG - Client detected ('127.0.0.1', 60493) -2019-03-18 23:42:06,300 - DEBUG - Client detected ('127.0.0.1', 60496) -2019-03-18 23:42:54,092 - DEBUG - Client detected ('127.0.0.1', 60501) -2019-03-18 23:51:58,722 - DEBUG - Client detected ('127.0.0.1', 60631) -2019-03-18 23:52:27,013 - DEBUG - Client detected ('127.0.0.1', 60633) -2019-03-18 23:53:55,819 - DEBUG - Client detected ('127.0.0.1', 60638) -2019-03-19 00:06:15,021 - DEBUG - Client detected ('127.0.0.1', 61013) -2019-03-19 00:09:42,991 - DEBUG - Client detected ('127.0.0.1', 61045) -2019-03-19 00:17:01,016 - DEBUG - Client detected ('127.0.0.1', 61226) -2019-03-19 00:21:39,446 - DEBUG - Client detected ('127.0.0.1', 61272) -2019-03-19 00:21:50,358 - DEBUG - Client detected ('127.0.0.1', 61274) -2019-03-19 00:24:33,940 - DEBUG - Client detected ('127.0.0.1', 61300) -2019-03-19 00:29:55,684 - DEBUG - Client detected ('127.0.0.1', 61404) -2019-03-19 00:30:43,120 - DEBUG - Client detected ('127.0.0.1', 61410) -2019-03-19 00:32:23,369 - DEBUG - Client detected ('127.0.0.1', 61421) -2019-03-19 00:47:00,622 - DEBUG - Client detected ('127.0.0.1', 61804) -2019-03-19 00:47:47,436 - DEBUG - Client detected ('127.0.0.1', 61807) -2019-03-19 00:48:18,901 - DEBUG - Client detected ('127.0.0.1', 61817) -2019-03-19 00:48:30,243 - DEBUG - Client detected ('127.0.0.1', 61822) -2019-03-19 00:48:41,896 - DEBUG - Client detected ('127.0.0.1', 61825) -2019-03-19 00:48:47,608 - DEBUG - Client detected ('127.0.0.1', 61827) From c6a250879bc1ba4541bfa8b136a9bde995c2cc6d Mon Sep 17 00:00:00 2001 From: PAND-or Date: Tue, 19 Mar 2019 03:17:36 +0300 Subject: [PATCH 06/12] to root directry --- .gitignore | 3 + {lesson05/client => client}/__main__.py | 0 .../client => client}/client_log_config.py | 0 lesson01/hw01.py | 187 ------------------ lesson01/test_file.txt | 3 - lesson02/file.yaml | 13 -- lesson02/info_1.txt | 42 ---- lesson02/info_2.txt | 42 ---- lesson02/info_3.txt | 42 ---- lesson02/new_file.csv | 4 - lesson02/orders.json | 32 --- lesson02/task01.py | 65 ------ lesson02/task02.py | 35 ---- lesson02/task03.py | 36 ---- lesson03/client/__main__.py | 73 ------- lesson03/server/__main__.py | 61 ------ lesson04/client/__main__.py | 81 -------- lesson04/server/__main__.py | 79 -------- lesson04/server/routes.py | 20 -- lesson04/server/test_module/controllers.py | 5 - lesson04/server/test_module/routes.py | 6 - lesson04/tests/test_server.py | 22 --- {lesson05/log => log}/client.log | 0 {lesson05/log => log}/server.log | 0 {lesson05/server => server}/__main__.py | 0 .../server => server}/presence/controllers.py | 0 .../server => server}/presence/routes.py | 0 {lesson05/server => server}/protocol.py | 0 {lesson05/server => server}/routes.py | 0 .../server => server}/server_log_config.py | 0 {lesson05/server => server}/settings.py | 0 .../tests/protocol/test_make_response.py | 0 .../tests/protocol/test_validate_request.py | 0 .../tests/routes/test_resolve.py | 0 .../server => server}/text/controllers.py | 0 {lesson05/server => server}/text/routes.py | 0 .../text/tests/controllers/__init__.py | 0 .../text/tests/controllers/test_lower.py | 0 .../text/tests/controllers/test_upper.py | 0 39 files changed, 3 insertions(+), 848 deletions(-) create mode 100644 .gitignore rename {lesson05/client => client}/__main__.py (100%) rename {lesson05/client => client}/client_log_config.py (100%) delete mode 100644 lesson01/hw01.py delete mode 100644 lesson01/test_file.txt delete mode 100644 lesson02/file.yaml delete mode 100644 lesson02/info_1.txt delete mode 100644 lesson02/info_2.txt delete mode 100644 lesson02/info_3.txt delete mode 100644 lesson02/new_file.csv delete mode 100644 lesson02/orders.json delete mode 100644 lesson02/task01.py delete mode 100644 lesson02/task02.py delete mode 100644 lesson02/task03.py delete mode 100644 lesson03/client/__main__.py delete mode 100644 lesson03/server/__main__.py delete mode 100644 lesson04/client/__main__.py delete mode 100644 lesson04/server/__main__.py delete mode 100644 lesson04/server/routes.py delete mode 100644 lesson04/server/test_module/controllers.py delete mode 100644 lesson04/server/test_module/routes.py delete mode 100644 lesson04/tests/test_server.py rename {lesson05/log => log}/client.log (100%) rename {lesson05/log => log}/server.log (100%) rename {lesson05/server => server}/__main__.py (100%) rename {lesson05/server => server}/presence/controllers.py (100%) rename {lesson05/server => server}/presence/routes.py (100%) rename {lesson05/server => server}/protocol.py (100%) rename {lesson05/server => server}/routes.py (100%) rename {lesson05/server => server}/server_log_config.py (100%) rename {lesson05/server => server}/settings.py (100%) rename {lesson05/server => server}/tests/protocol/test_make_response.py (100%) rename {lesson05/server => server}/tests/protocol/test_validate_request.py (100%) rename {lesson05/server => server}/tests/routes/test_resolve.py (100%) rename {lesson05/server => server}/text/controllers.py (100%) rename {lesson05/server => server}/text/routes.py (100%) rename {lesson05/server => server}/text/tests/controllers/__init__.py (100%) rename {lesson05/server => server}/text/tests/controllers/test_lower.py (100%) rename {lesson05/server => server}/text/tests/controllers/test_upper.py (100%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..853aa9c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.coverage +__pycache__ +.pytest_cache diff --git a/lesson05/client/__main__.py b/client/__main__.py similarity index 100% rename from lesson05/client/__main__.py rename to client/__main__.py diff --git a/lesson05/client/client_log_config.py b/client/client_log_config.py similarity index 100% rename from lesson05/client/client_log_config.py rename to client/client_log_config.py diff --git a/lesson01/hw01.py b/lesson01/hw01.py deleted file mode 100644 index ad092a1..0000000 --- a/lesson01/hw01.py +++ /dev/null @@ -1,187 +0,0 @@ -#!/usr/bin/python3 -__author__ = "Андрей Петров" - - -""" -1. Каждое из слов «разработка», «сокет», «декоратор» представить в строковом формате и проверить тип и содержание -соответствующих переменных. Затем с помощью онлайн-конвертера преобразовать строковые представление в формат Unicode -и также проверить тип и содержимое переменных. - ->>> a = 'разработка' ->>> print(f'development: {a}, type {type(a)}') -development: разработка, type - ->>> b = 'сокет' ->>> print(f'socket: {b}, type {type(b)}') -socket: сокет, type - ->>> c = 'декоратор' ->>> print(f'decorator: {c}, type {type(c)}') -decorator: декоратор, type - ->>> a = a.encode('utf-8') ->>> print(f'development: {a}, type {type(a)}') -development: b'\xd1\x80\xd0\xb0\xd0\xb7\xd1\x80\xd0\xb0\xd0\xb1\xd0\xbe\xd1\x82\xd0\xba\xd0\xb0', type - ->>> b = b.encode('utf-8') ->>> print(f'socket: {b}, type {type(b)}') -socket: b'\xd1\x81\xd0\xbe\xd0\xba\xd0\xb5\xd1\x82', type - ->>> c = c.encode('utf-8') ->>> print(f'decorator: {c}, type {type(c)}') -decorator: b'\xd0\xb4\xd0\xb5\xd0\xba\xd0\xbe\xd1\x80\xd0\xb0\xd1\x82\xd0\xbe\xd1\x80', type - -""" - - -""" -2. Каждое из слов «class», «function», «method» записать в байтовом типе без преобразования в последовательность кодов -(не используя методы encode и decode) и определить тип, содержимое и длину соответствующих переменных. - ->>> a = b'class' ->>> print(f'class: {a}, type: {type(a)}, len:{len(a)}') -class: b'class', type: , len:5 - ->>> b = b'function' ->>> print(f'function: {b}, type: {type(b)}, len:{len(b)}') -function: b'function', type: , len:8 - ->>> c = b'method' ->>> print(f'method: {c}, type: {type(c)}, len:{len(c)}') -method: b'method', type: , len:6 -""" - - -""" -3. Определить, какие из слов «attribute», «класс», «функция», «type» невозможно записать в байтовом типе. - ->>> b'attribute' -b'attribute' - ->>> b'класс' - File "", line 1 -SyntaxError: bytes can only contain ASCII literal characters. - ->>> b'функция' - File "", line 1 -SyntaxError: bytes can only contain ASCII literal characters. - ->>> b'type' -b'type' - -Нельзя записать в байтовый тип без преобразования кириллические символы, т.к. на хранение одного -кириллическоно символа требуется больше 1 байта - -""" - - -""" -4. Преобразовать слова «разработка», «администрирование», «protocol», «standard» из строкового представления в байтовое - и выполнить обратное преобразование (используя методы encode и decode). - ->>> a = 'разработка' ->>> a -'разработка' ->>> a = a.encode() ->>> a -b'\xd1\x80\xd0\xb0\xd0\xb7\xd1\x80\xd0\xb0\xd0\xb1\xd0\xbe\xd1\x82\xd0\xba\xd0\xb0' ->>> a = a.decode() ->>> a -'разработка' - ->>> b = 'администрирование' ->>> b -'администрирование' ->>> b = b.encode() ->>> b -b'\xd0\xb0\xd0\xb4\xd0\xbc\xd0\xb8\xd0\xbd\xd0\xb8\xd1\x81\xd1\x82\xd1\x80\xd0\xb8\xd1\x80\xd0\xbe\xd0\xb2\xd0\xb0\xd0\xbd\xd0\xb8\xd0\xb5' ->>> b = b.decode() ->>> b -'администрирование' - ->>> c = 'protocol' ->>> c -'protocol' ->>> c = c.encode() ->>> c -b'protocol' ->>> c = c.decode() ->>> c -'protocol' - ->>> d = 'standard' ->>> d -'standard' ->>> d = d.encode() ->>> d -b'standard' ->>> d = d.decode() ->>> d -'standard' - -""" - -""" -5. Выполнить пинг веб-ресурсов yandex.ru, youtube.com и преобразовать результаты из байтовового -в строковый тип на кириллице. - ->>> import subprocess ->>> args = ['ping', 'yandex.ru'] ->>> subproc_ping = subprocess.Popen(args, stdout=subprocess.PIPE) ->>> for line in subproc_ping.stdout: -... line = line.decode('cp866').encode('utf-8') -... print(line.decode('utf-8')) -... -Ответ от 5.255.255.70: число байт=32 время=24мс TTL=57 -Ответ от 5.255.255.70: число байт=32 время=26мс TTL=57 -Ответ от 5.255.255.70: число байт=32 время=27мс TTL=57 - -Статистика Ping для 5.255.255.70: - Пакетов: отправлено = 4, получено = 4, потеряно = 0 - (0% потерь) -Приблизительное время приема-передачи в мс: - Минимальное = 24мсек, Максимальное = 27 мсек, Среднее = 25 мсек - - ->>> args = ['ping', 'youtube.com'] ->>> subproc_ping = subprocess.Popen(args, stdout=subprocess.PIPE) ->>> for line in subproc_ping.stdout: -... line = line.decode('cp866').encode('utf-8') -... print(line.decode('utf-8')) -... -Обмен пакетами с youtube.com [173.194.44.39] с 32 байтами данных: -Ответ от 173.194.44.39: число байт=32 время=23мс TTL=120 -Ответ от 173.194.44.39: число байт=32 время=22мс TTL=120 -Ответ от 173.194.44.39: число байт=32 время=21мс TTL=120 -Ответ от 173.194.44.39: число байт=32 время=23мс TTL=120 - -Статистика Ping для 173.194.44.39: - Пакетов: отправлено = 4, получено = 4, потеряно = 0 - (0% потерь) -Приблизительное время приема-передачи в мс: - Минимальное = 21мсек, Максимальное = 23 мсек, Среднее = 22 мсек - -""" - -""" -6. Создать текстовый файл test_file.txt, заполнить его тремя строками: «сетевое программирование», «сокет», -«декоратор». Проверить кодировку файла по умолчанию. Принудительно открыть файл в формате Unicode и -вывести его содержимое. - ->>> with open('E:/PythonScripts/Repo/python_advanced/lesson01/test_file.txt') as file: -... for f_str in file: -... print(f_str) -... -сетевое программирование -сокет -декоратор - ->>> with open('E:/PythonScripts/Repo/python_advanced/lesson01/test_file.txt', encoding='utf-8') as file: -... for f_str in file: -... print(f_str) -... -сетевое программирование -сокет -декоратор - -""" diff --git a/lesson01/test_file.txt b/lesson01/test_file.txt deleted file mode 100644 index d9c8af1..0000000 --- a/lesson01/test_file.txt +++ /dev/null @@ -1,3 +0,0 @@ -сетевое программирование -сокет -декоратор \ No newline at end of file diff --git a/lesson02/file.yaml b/lesson02/file.yaml deleted file mode 100644 index 4f0efa3..0000000 --- a/lesson02/file.yaml +++ /dev/null @@ -1,13 +0,0 @@ -100: -- 1 -- 2 -- 3 -- 4 -200: 8000 -300: - first: - - 1 - - 2 - - 3 - - 4 - second: 800 diff --git a/lesson02/info_1.txt b/lesson02/info_1.txt deleted file mode 100644 index 845390d..0000000 --- a/lesson02/info_1.txt +++ /dev/null @@ -1,42 +0,0 @@ - : Comp1 - : Microsoft Windows 7 - : 6.1.7601 Service Pack 1 7601 - : Microsoft Corporation - : - : Multiprocessor Free - : User - : - : 00971-OEM-1982661-00231 - : 11.10.2013, 10:18:05 - : 0 ., 4 ., 41 , 0 . - : LENOVO - : 3538F2G - : x64-based PC -(): - 1. - [01]: Intel64 Family 6 Model 42 Stepping 7 GenuineIntel ~3400 - BIOS: LENOVO - 1390 - Windows: C:\Windows - : C:\Windows\system32 - : \Device\HarddiskVolume1 - : ru; - : en-us; () - : (UTC+04:00) , , - - : 3 914 - : 2 299 - : . : 7 826 - : : 6 139 - : : 1 687 - : / -: net - : / -(): - 74. - [01]: KB982861 - [02]: 982861 -. . . - [74]: KB982018 - : - 1. - [01]: Realtek PCIe GBE Family Controller - : - DHCP : - IP- - [01]: 192.168.0.4 \ No newline at end of file diff --git a/lesson02/info_2.txt b/lesson02/info_2.txt deleted file mode 100644 index 0f96fb2..0000000 --- a/lesson02/info_2.txt +++ /dev/null @@ -1,42 +0,0 @@ - : Comp1 - : Microsoft Windows 10 Professional - : 16299 - : Microsoft Corporation - : - : Multiprocessor Free - : User - : - : 00971-OEM-1982661-00231 - : 11.10.2013, 10:18:05 - : 0 ., 4 ., 41 , 0 . - : ACER - : 3538F2G - : x64-based PC -(): - 1. - [01]: Intel64 Family 6 Model 42 Stepping 7 GenuineIntel ~3400 - BIOS: LENOVO - 1390 - Windows: C:\Windows - : C:\Windows\system32 - : \Device\HarddiskVolume1 - : ru; - : en-us; () - : (UTC+04:00) , , - - : 3 914 - : 2 299 - : . : 7 826 - : : 6 139 - : : 1 687 - : / -: net - : / -(): - 74. - [01]: KB982861 - [02]: 982861 -. . . - [74]: KB982018 - : - 1. - [01]: Realtek PCIe GBE Family Controller - : - DHCP : - IP- - [01]: 192.168.0.4 \ No newline at end of file diff --git a/lesson02/info_3.txt b/lesson02/info_3.txt deleted file mode 100644 index c2a964a..0000000 --- a/lesson02/info_3.txt +++ /dev/null @@ -1,42 +0,0 @@ - : Comp1 - : Microsoft Windows 8.1 Professional - : 10001 - : Microsoft Corporation - : - : Multiprocessor Free - : User - : - : 00971-OEM-1982661-00231 - : 11.10.2013, 10:18:05 - : 0 ., 4 ., 41 , 0 . - : DELL - : 3538F2G - : x86-based PC -(): - 1. - [01]: Intel64 Family 6 Model 42 Stepping 7 GenuineIntel ~3400 - BIOS: LENOVO - 1390 - Windows: C:\Windows - : C:\Windows\system32 - : \Device\HarddiskVolume1 - : ru; - : en-us; () - : (UTC+04:00) , , - - : 3 914 - : 2 299 - : . : 7 826 - : : 6 139 - : : 1 687 - : / -: net - : / -(): - 74. - [01]: KB982861 - [02]: 982861 -. . . - [74]: KB982018 - : - 1. - [01]: Realtek PCIe GBE Family Controller - : - DHCP : - IP- - [01]: 192.168.0.4 \ No newline at end of file diff --git a/lesson02/new_file.csv b/lesson02/new_file.csv deleted file mode 100644 index 0f481d5..0000000 --- a/lesson02/new_file.csv +++ /dev/null @@ -1,4 +0,0 @@ - , , , -LENOVO,Microsoft Windows 7 ,00971-OEM-1982661-00231,x64-based PC -ACER,Microsoft Windows 10 Professional,00971-OEM-1982661-00231,x64-based PC -DELL,Microsoft Windows 8.1 Professional,00971-OEM-1982661-00231,x86-based PC diff --git a/lesson02/orders.json b/lesson02/orders.json deleted file mode 100644 index 4a60f00..0000000 --- a/lesson02/orders.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "orders": [ - { - "item": "\u0411\u0430\u043d\u0430\u043d", - "quantity": 3, - "price": 300, - "buyer": "Pupkin", - "date": "08.03.2019" - }, - { - "item": "\u042f\u0431\u043b\u043e\u043a\u043e", - "quantity": 2, - "price": 700, - "buyer": "Pupkin", - "date": "08.03.2019" - }, - { - "item": "\u0410\u043f\u0435\u043b\u044c\u0441\u0438\u043d", - "quantity": 3, - "price": 1200, - "buyer": "Pupkin", - "date": "08.03.2019" - }, - { - "item": "\u0413\u0440\u0443\u0448\u0430", - "quantity": 4, - "price": 500, - "buyer": "Pupkin", - "date": "08.03.2019" - } - ] -} \ No newline at end of file diff --git a/lesson02/task01.py b/lesson02/task01.py deleted file mode 100644 index fa4e888..0000000 --- a/lesson02/task01.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/python3 -__author__ = "Андрей Петров" - -import csv -import re - - -""" -1. Задание на закрепление знаний по модулю CSV. Написать скрипт, осуществляющий выборку определенных данных из файлов -info_1.txt, info_2.txt, info_3.txt и формирующий новый «отчетный» файл в формате CSV. Для этого: -Создать функцию get_data(), в которой в цикле осуществляется перебор файлов с данными, их открытие и считывание данных. -В этой функции из считанных данных необходимо с помощью регулярных выражений извлечь значения параметров «Изготовитель -системы», «Название ОС», «Код продукта», «Тип системы». Значения каждого параметра поместить в соответствующий список. -Должно получиться четыре списка — например, os_prod_list, os_name_list, os_code_list, os_type_list. В этой же функции -создать главный список для хранения данных отчета — например, main_data — и поместить в него названия столбцов отчета -в виде списка: «Изготовитель системы», «Название ОС», «Код продукта», «Тип системы». Значения для этих столбцов также -оформить в виде списка и поместить в файл main_data (также для каждого файла); -Создать функцию write_to_csv(), в которую передавать ссылку на CSV-файл. В этой функции реализовать получение данных -через вызов функции get_data(), а также сохранение подготовленных данных в соответствующий CSV-файл; -Проверить работу программы через вызов функции write_to_csv(). ### -""" - - -def write_to_csv(file, data): - with open(file, 'w') as f_n: - f_n_writer = csv.writer(f_n) - for nrow in data: - f_n_writer.writerow(nrow) - - -def get_data(lst): - os_prod_list = [] - os_name_list = [] - os_code_list = [] - os_type_list = [] - main_data = [['Изготовитель системы', 'Название ОС', 'Код продукта', 'Тип системы']] - for file in lst: - datafile = open(file) - for row in datafile: - row = row.rstrip() - if re.match('Изготовитель системы', row): - os_prod_list.append(re.search(r'(Изготовитель системы).\s*(.*)', row).group(2)) - elif re.match('Название ОС', row): - os_name_list.append(re.search(r'(Название ОС).\s*(.*)', row).group(2)) - elif re.match('Код продукта', row): - os_code_list.append(re.search(r'(Код продукта).\s*(.*)', row).group(2)) - elif re.match('Тип системы', row): - os_type_list.append(re.search(r'(Тип системы).\s*(.*)', row).group(2)) - - for k in range(len(lst)): - main_data.append([ - os_prod_list[k], - os_name_list[k], - os_code_list[k], - os_type_list[k] - ]) - return main_data - - -if __name__ == "__main__": - res = get_data(['info_1.txt', 'info_2.txt', 'info_3.txt']) - write_to_csv('new_file.csv', res) - - with open('new_file.csv') as f_n: - print(f_n.read()) diff --git a/lesson02/task02.py b/lesson02/task02.py deleted file mode 100644 index 65b1628..0000000 --- a/lesson02/task02.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/python3 -__author__ = "Андрей Петров" - -import json - -""" -2. Задание на закрепление знаний по модулю json. Есть файл orders в формате JSON с информацией о заказах. Написать -скрипт, автоматизирующий его заполнение данными. Для этого: -Создать функцию write_order_to_json(), в которую передается 5 параметров — товар (item), количество (quantity), -цена (price), покупатель (buyer), дата (date). Функция должна предусматривать запись данных в виде словаря -в файл orders.json. При записи данных указать величину отступа в 4 пробельных символа; -Проверить работу программы через вызов функции write_order_to_json() с передачей в нее значений каждого параметра. -""" - - -def write_order_to_json(item, quantity, price, buyer, date): - with open('orders.json') as f_n: - dict_to_json = json.load(f_n) - print(dict_to_json) - dict_to_json['orders'].append({ - 'item': item, - 'quantity': quantity, - 'price': price, - 'buyer': buyer, - 'date': date, - }) - with open('orders.json', 'w') as f_w: - json.dump(dict_to_json, f_w, indent=4) - - -if __name__ == "__main__": - write_order_to_json('Банан', 3, 300, 'Pupkin', '08.03.2019') - write_order_to_json('Яблоко', 2, 700, 'Pupkin', '08.03.2019') - write_order_to_json('Апельсин', 3, 1200, 'Pupkin', '08.03.2019') - write_order_to_json('Груша', 4, 500, 'Pupkin', '08.03.2019') diff --git a/lesson02/task03.py b/lesson02/task03.py deleted file mode 100644 index 59d2de8..0000000 --- a/lesson02/task03.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/python3 -__author__ = "Андрей Петров" - -import yaml - -""" -### 3. Задание на закрепление знаний по модулю yaml. Написать скрипт, автоматизирующий сохранение данных -в файле YAML-формата. Для этого: -Подготовить данные для записи в виде словаря, в котором первому ключу соответствует список, второму — целое число, -третьему — вложенный словарь, где значение каждого ключа — это целое число с юникод-символом, отсутствующим -в кодировке ASCII (например, €); -Реализовать сохранение данных в файл формата YAML — например, в файл file.yaml. При этом обеспечить стилизацию файла -с помощью параметра default_flow_style, а также установить возможность работы с юникодом: allow_unicode = True; -Реализовать считывание данных из созданного файла и проверить, совпадают ли они с исходными. -""" - -def write_dict_to_yaml(dict, file): - with open(file, 'w') as f_n: - yaml.dump(dict, f_n, default_flow_style=False, allow_unicode = True) - - with open(file) as f_n: - f_n_content = yaml.load(f_n) - - print(f_n_content == dict) - -if __name__ == "__main__": - my_dict = { - '100€': [1, 2, 3, 4], - '200€': 8000, - '300€': { - 'first': [1,2,3,4], - 'second': 800, - } - } - - write_dict_to_yaml(my_dict, 'file.yaml') diff --git a/lesson03/client/__main__.py b/lesson03/client/__main__.py deleted file mode 100644 index 0e9c034..0000000 --- a/lesson03/client/__main__.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/python3 -__author__ = "Андрей Петров" - -""" -клиент отправляет запрос серверу; -сервер отвечает соответствующим кодом результата. Клиент и сервер должны быть реализованы в виде отдельных скриптов, -содержащих соответствующие функции. - -Функции клиента: -сформировать presence-сообщение; -отправить сообщение серверу; -получить ответ сервера; -разобрать сообщение сервера; -параметры командной строки скрипта client.py []: addr — ip-адрес сервера; -port — tcp-порт на сервере, -по умолчанию 7777. - -""" -import re -import sys -import argparse -import socket -import json -from datetime import datetime - - -def createParser(): - parser = argparse.ArgumentParser() - parser.add_argument('host', nargs='?', default='localhost') - parser.add_argument('port', nargs='?', default='7777') - return parser - - -parser = createParser() -args = parser.parse_args(sys.argv[1:]) - -port = int(re.search('[0-9]{2,}', args.port).group(0)) - -sock = socket.socket() -sock.connect((args.host, port)) - -# сформировать presence-сообщение; -# В формате JIM -msg_presence = json.dumps( - { - "action": "presence", - "time": datetime.now().timestamp(), - "type": "status", - "user": { - "account_name": "User Name", - "status": "Yep, I am here!" - } - } -) - -# отправить сообщение серверу; -sock.send(msg_presence.encode()) - -# получить ответ сервера; -data = sock.recv(1024) -response = json.loads( - data.decode('utf-8') -) -# разобрать сообщение сервера; -if response.get('response') == 200: - print( - f"Response Message: {response.get('msg')}" - ) -else: - print( - f"Error: {response.get('error')}" - ) -sock.close() diff --git a/lesson03/server/__main__.py b/lesson03/server/__main__.py deleted file mode 100644 index 6a146c4..0000000 --- a/lesson03/server/__main__.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/python3 -__author__ = "Андрей Петров" - -""" -клиент отправляет запрос серверу; -сервер отвечает соответствующим кодом результата. Клиент и сервер должны быть реализованы в виде отдельных скриптов, -содержащих соответствующие функции. - -Функции сервера: -принимает сообщение клиента; -формирует ответ клиенту; -отправляет ответ клиенту; -имеет параметры командной строки: -p — TCP-порт для работы (по умолчанию использует 7777); --a — IP-адрес для прослушивания (по умолчанию слушает все доступные адреса). -""" - -import sys -import json -import socket -import argparse - - -def createParser(): - parser = argparse.ArgumentParser() - parser.add_argument('-a', '--addr', nargs='?', default='') - parser.add_argument('-p', '--port', nargs='?', default='7777') - return parser - - -parser = createParser() -args = parser.parse_args(sys.argv[1:]) - - -sock = socket.socket() -sock.bind((args.addr, int(args.port))) -sock.listen(5) - -while True: - # принимает сообщение клиента; - client, address = sock.accept() - - data = client.recv(1024) - request = json.loads( - data.decode('utf-8') - ) - - # формирует ответ клиенту; - if request.get('action') == 'presence': - response = { - "response": 200, - "msg": f"Hi {request.get('user')['account_name']}" - } - else: - response = { - "response": 400, - "error": "Wrong action, try again" - } - - # отправляет ответ клиенту; - client.send(json.dumps(response).encode('utf-8')) - client.close() \ No newline at end of file diff --git a/lesson04/client/__main__.py b/lesson04/client/__main__.py deleted file mode 100644 index 713d571..0000000 --- a/lesson04/client/__main__.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/python3 -__author__ = "Андрей Петров" - -""" -клиент отправляет запрос серверу; -сервер отвечает соответствующим кодом результата. Клиент и сервер должны быть реализованы в виде отдельных скриптов, -содержащих соответствующие функции. - -Функции клиента: -сформировать presence-сообщение; -отправить сообщение серверу; -получить ответ сервера; -разобрать сообщение сервера; -параметры командной строки скрипта client.py []: addr — ip-адрес сервера; -port — tcp-порт на сервере, -по умолчанию 7777. - -""" -import re -import sys -import argparse -import socket -import json -from datetime import datetime - - -def createParser(): - parser = argparse.ArgumentParser() - parser.add_argument('host', nargs='?', default='localhost') - parser.add_argument('port', nargs='?', default='7777') - return parser - - -parser = createParser() -args = parser.parse_args(sys.argv[1:]) - -port = int(re.search('[0-9]{2,}', args.port).group(0)) - -sock = socket.socket() -sock.connect((args.host, port)) - -# сформировать presence-сообщение; -# В формате JIM -msg_presence = json.dumps( - { - "action": "presence", - "time": datetime.now().timestamp(), - "type": "status", - "user": { - "account_name": "User Name", - "status": "Yep, I am here!" - } - } -) - -msg_lower = json.dumps( - { - "action": "lower_text", - "data": 'GGGGG' - } -) - -# отправить сообщение серверу; -sock.send(msg_presence.encode()) -#sock.send(msg_lower.encode()) - -# получить ответ сервера; -data = sock.recv(1024) -response = json.loads( - data.decode('utf-8') -) -# разобрать сообщение сервера; -if response.get('response') == 200: - print( - f"Response Message: {response.get('msg')}" - ) -else: - print( - f"Error: {response.get('error')}" - ) -sock.close() diff --git a/lesson04/server/__main__.py b/lesson04/server/__main__.py deleted file mode 100644 index c72ea45..0000000 --- a/lesson04/server/__main__.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/python3 -__author__ = "Андрей Петров" - -""" -клиент отправляет запрос серверу; -сервер отвечает соответствующим кодом результата. Клиент и сервер должны быть реализованы в виде отдельных скриптов, -содержащих соответствующие функции. - -Функции сервера: -принимает сообщение клиента; -формирует ответ клиенту; -отправляет ответ клиенту; -имеет параметры командной строки: -p — TCP-порт для работы (по умолчанию использует 7777); --a — IP-адрес для прослушивания (по умолчанию слушает все доступные адреса). -""" - -import sys -import os -import json -import socket -import argparse -from routes import get_server_routes - - -def createParser(): - parser = argparse.ArgumentParser() - parser.add_argument('-a', '--addr', nargs='?', default='') - parser.add_argument('-p', '--port', nargs='?', default='7777') - return parser - - -parser = createParser() -args = parser.parse_args(sys.argv[1:]) - - -sock = socket.socket() -sock.bind((args.addr, int(args.port))) -sock.listen(5) - - -## Без этого не работал код из урока -os.chdir('server') -sys.path.append(os.getcwd()) -## - -while True: - # принимает сообщение клиента; - client, address = sock.accept() - - data = client.recv(1024) - request = json.loads( - data.decode('utf-8') - ) - - # формирует ответ клиенту; - - client_action = request.get('action') - - resolved_routes = list( - filter( - lambda itm: itm.get('action') == client_action, - get_server_routes() - ) - ) - - route = resolved_routes[0] if resolved_routes else None - if route: - controller = route.get('controller') - response = controller(request) - - else: - response = { - "response": 400, - "error": "Wrong action, try again" - } - - # отправляет ответ клиенту; - client.send(json.dumps(response).encode('utf-8')) - client.close() diff --git a/lesson04/server/routes.py b/lesson04/server/routes.py deleted file mode 100644 index 3451d82..0000000 --- a/lesson04/server/routes.py +++ /dev/null @@ -1,20 +0,0 @@ -import os -from importlib import import_module -from functools import reduce - - -def get_server_routes(): - return reduce( - lambda routes, module: routes + getattr(module, 'routes', []), - reduce( - lambda modules, dir: modules + [import_module(f'{dir}.routes')], - filter( - lambda itm: os.path.isdir(itm) and itm != '__pycache__' and itm != '.pytest_cache', - os.listdir() - ), - [] - ), - [] - ) - - diff --git a/lesson04/server/test_module/controllers.py b/lesson04/server/test_module/controllers.py deleted file mode 100644 index 4b1996d..0000000 --- a/lesson04/server/test_module/controllers.py +++ /dev/null @@ -1,5 +0,0 @@ -def send_presence(request): - return { - "response": 200, - "msg": f"Hi {request.get('user')['account_name']}" - } diff --git a/lesson04/server/test_module/routes.py b/lesson04/server/test_module/routes.py deleted file mode 100644 index 1eb5c4c..0000000 --- a/lesson04/server/test_module/routes.py +++ /dev/null @@ -1,6 +0,0 @@ -from .controllers import send_presence - - -routes = [ - {'action': 'presence', 'controller': send_presence} -] \ No newline at end of file diff --git a/lesson04/tests/test_server.py b/lesson04/tests/test_server.py deleted file mode 100644 index 46ed84b..0000000 --- a/lesson04/tests/test_server.py +++ /dev/null @@ -1,22 +0,0 @@ -import sys -sys.path.append('../') - -from server.test_module.controllers import send_presence - -REQUEST = { - "action": "presence", - "type": "status", - "user": { - "account_name": "User Name", - "status": "Yep, I am here!" - } - } - -RESPONSE = { - "response": 200, - "msg": "Hi User Name" - } - - -def presence_msg_request_to_response(): - assert send_presence(REQUEST) == RESPONSE diff --git a/lesson05/log/client.log b/log/client.log similarity index 100% rename from lesson05/log/client.log rename to log/client.log diff --git a/lesson05/log/server.log b/log/server.log similarity index 100% rename from lesson05/log/server.log rename to log/server.log diff --git a/lesson05/server/__main__.py b/server/__main__.py similarity index 100% rename from lesson05/server/__main__.py rename to server/__main__.py diff --git a/lesson05/server/presence/controllers.py b/server/presence/controllers.py similarity index 100% rename from lesson05/server/presence/controllers.py rename to server/presence/controllers.py diff --git a/lesson05/server/presence/routes.py b/server/presence/routes.py similarity index 100% rename from lesson05/server/presence/routes.py rename to server/presence/routes.py diff --git a/lesson05/server/protocol.py b/server/protocol.py similarity index 100% rename from lesson05/server/protocol.py rename to server/protocol.py diff --git a/lesson05/server/routes.py b/server/routes.py similarity index 100% rename from lesson05/server/routes.py rename to server/routes.py diff --git a/lesson05/server/server_log_config.py b/server/server_log_config.py similarity index 100% rename from lesson05/server/server_log_config.py rename to server/server_log_config.py diff --git a/lesson05/server/settings.py b/server/settings.py similarity index 100% rename from lesson05/server/settings.py rename to server/settings.py diff --git a/lesson05/server/tests/protocol/test_make_response.py b/server/tests/protocol/test_make_response.py similarity index 100% rename from lesson05/server/tests/protocol/test_make_response.py rename to server/tests/protocol/test_make_response.py diff --git a/lesson05/server/tests/protocol/test_validate_request.py b/server/tests/protocol/test_validate_request.py similarity index 100% rename from lesson05/server/tests/protocol/test_validate_request.py rename to server/tests/protocol/test_validate_request.py diff --git a/lesson05/server/tests/routes/test_resolve.py b/server/tests/routes/test_resolve.py similarity index 100% rename from lesson05/server/tests/routes/test_resolve.py rename to server/tests/routes/test_resolve.py diff --git a/lesson05/server/text/controllers.py b/server/text/controllers.py similarity index 100% rename from lesson05/server/text/controllers.py rename to server/text/controllers.py diff --git a/lesson05/server/text/routes.py b/server/text/routes.py similarity index 100% rename from lesson05/server/text/routes.py rename to server/text/routes.py diff --git a/lesson05/server/text/tests/controllers/__init__.py b/server/text/tests/controllers/__init__.py similarity index 100% rename from lesson05/server/text/tests/controllers/__init__.py rename to server/text/tests/controllers/__init__.py diff --git a/lesson05/server/text/tests/controllers/test_lower.py b/server/text/tests/controllers/test_lower.py similarity index 100% rename from lesson05/server/text/tests/controllers/test_lower.py rename to server/text/tests/controllers/test_lower.py diff --git a/lesson05/server/text/tests/controllers/test_upper.py b/server/text/tests/controllers/test_upper.py similarity index 100% rename from lesson05/server/text/tests/controllers/test_upper.py rename to server/text/tests/controllers/test_upper.py From 7cadcff748936cb6a0fc13f8f164ae7485d554bd Mon Sep 17 00:00:00 2001 From: PAND-or Date: Fri, 22 Mar 2019 15:52:56 +0300 Subject: [PATCH 07/12] hw06 --- server/__main__.py | 12 ++++++++---- server/exception/__init__.py | 0 server/exception/controllers.py | 6 ++++++ server/exception/routes.py | 6 ++++++ server/log.py | 12 ++++++++++++ server/presence/controllers.py | 3 ++- server/settings.py | 2 +- server/text/controllers.py | 4 +++- 8 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 server/exception/__init__.py create mode 100644 server/exception/controllers.py create mode 100644 server/exception/routes.py create mode 100644 server/log.py diff --git a/server/__main__.py b/server/__main__.py index c63036f..e9b7ea7 100644 --- a/server/__main__.py +++ b/server/__main__.py @@ -40,7 +40,7 @@ def createParser(): while True: # принимает сообщение клиента; client, address = sock.accept() - logger.debug(f'Client detected {address}') + logger.info(f'Client detected {address}') data = client.recv(1024) request = json.loads( @@ -52,8 +52,8 @@ def createParser(): if controller: try: response = controller(request) - except Exception: - logger.critical(f'error 500 controller: {controller}') + except Exception as err: + logger.critical(err, exc_info=True) response = make_response( request, 500, error='Internal server error.' @@ -65,9 +65,13 @@ def createParser(): response = make_400(request) logger.critical(f"error 400 bad request: {request}") + 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.debug(f"client {address} closed") + logger.info(f"client {address} closed") except KeyboardInterrupt: + logger.info(f"client {address} closed") sock.close() diff --git a/server/exception/__init__.py b/server/exception/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/exception/controllers.py b/server/exception/controllers.py new file mode 100644 index 0000000..654ab85 --- /dev/null +++ b/server/exception/controllers.py @@ -0,0 +1,6 @@ +from protocol import make_response, make_400 +from log import log + +@log +def get_error(request): + raise Exception('Some test error') \ No newline at end of file diff --git a/server/exception/routes.py b/server/exception/routes.py new file mode 100644 index 0000000..015d7c8 --- /dev/null +++ b/server/exception/routes.py @@ -0,0 +1,6 @@ +from .controllers import get_error + + +routes = [ + {'action': 'get_error', 'controller': get_error}, +] \ No newline at end of file diff --git a/server/log.py b/server/log.py new file mode 100644 index 0000000..a746752 --- /dev/null +++ b/server/log.py @@ -0,0 +1,12 @@ +import inspect + +def log(func): + def wrap(request, *args, **kwargs): + print('*' * 50) + + print(func) + print(request) + #print(inspect.function(request)) + print('*' * 50) + return func(request, *args, **kwargs) + return wrap diff --git a/server/presence/controllers.py b/server/presence/controllers.py index bf56412..aff2945 100644 --- a/server/presence/controllers.py +++ b/server/presence/controllers.py @@ -1,6 +1,7 @@ from protocol import make_response, make_400 +from log import log - +@log def send_presence(request): user = request.get('user') if not user: diff --git a/server/settings.py b/server/settings.py index fe7eb4c..8968d2d 100644 --- a/server/settings.py +++ b/server/settings.py @@ -5,5 +5,5 @@ ) INSTALLED_MODULES = [ - 'text', 'presence' + 'text', 'presence', 'exception' ] \ No newline at end of file diff --git a/server/text/controllers.py b/server/text/controllers.py index f2ae160..c4cc8b7 100644 --- a/server/text/controllers.py +++ b/server/text/controllers.py @@ -1,6 +1,8 @@ from protocol import make_response, make_400 +from log import log +@log def get_upper_text(request): data = request.get('data') if not data: @@ -11,7 +13,7 @@ def get_upper_text(request): data.upper() ) - +@log def get_lower_text(request): data = request.get('data') if not data: From 5cc873af08037dd8a04951b3b28974d4e3e4c684 Mon Sep 17 00:00:00 2001 From: PAND-or Date: Fri, 22 Mar 2019 23:37:17 +0300 Subject: [PATCH 08/12] hw06 fix --- log/client.log | 10 +++------- log/server.log | 9 ++++----- server/log.py | 22 ++++++++++++++++------ 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/log/client.log b/log/client.log index 4f3b8ea..7461fbb 100644 --- a/log/client.log +++ b/log/client.log @@ -1,7 +1,3 @@ - -2019-03-19 03:05:05,291 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 -2019-03-19 03:10:20,565 - DEBUG - client - __main__ - Response Message: Hi vASYA -2019-03-19 03:10:29,685 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 -2019-03-19 03:11:09,124 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 -2019-03-19 03:11:14,589 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 -2019-03-19 03:11:57,166 - DEBUG - client - __main__ - Response Message: Hi gfd +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 diff --git a/log/server.log b/log/server.log index 934ad27..1ddc1a2 100644 --- a/log/server.log +++ b/log/server.log @@ -1,5 +1,4 @@ -2019-03-19 03:10:13,134 - DEBUG - __main__ - Client detected ('127.0.0.1', 64775) -2019-03-19 03:10:20,565 - DEBUG - __main__ - client ('127.0.0.1', 64775) closed -2019-03-19 03:10:56,456 - DEBUG - __main__ - Client detected ('127.0.0.1', 64819) -2019-03-19 03:11:50,998 - DEBUG - __main__ - Client detected ('127.0.0.1', 64851) -2019-03-19 03:11:57,166 - DEBUG - __main__ - client ('127.0.0.1', 64851) closed +2019-03-22 23:36:01,704 - INFO - __main__ - client ('127.0.0.1', 55328) closed +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 diff --git a/server/log.py b/server/log.py index a746752..2e2c2e6 100644 --- a/server/log.py +++ b/server/log.py @@ -1,12 +1,22 @@ +"""" +2. В декораторе @log реализовать фиксацию функции, из которой была вызвана декорированная. Если имеется такой код: +@log +def func_z(): + pass + +def main(): + func_z() +...в логе должна быть отражена информация: +"<дата-время> Функция func_z() вызвана из функции main" +""" + import inspect +from server_log_config import logger def log(func): def wrap(request, *args, **kwargs): - print('*' * 50) - - print(func) - print(request) - #print(inspect.function(request)) - print('*' * 50) + file_name = inspect.currentframe().f_back.f_code.co_filename + mname = inspect.getmodulename(file_name) + logger.info(f'function {func.__name__}{args} call from {mname}') return func(request, *args, **kwargs) return wrap From bcf4cac74e4cc5d1fc85b789ee22c089f6986fae Mon Sep 17 00:00:00 2001 From: PAND-or Date: Sat, 23 Mar 2019 14:03:02 +0300 Subject: [PATCH 09/12] lesson07 --- client/__main__.py | 119 +++++++++++++++++++++++-------------- log/client.log | 23 +++++++ log/server.log | 37 ++++++++++++ server/__main__.py | 70 +++++++++++----------- server/authentication.py | 21 +++++++ server/customlogging.py | 49 +++++++++++++++ server/handlers.py | 27 +++++++++ server/text/controllers.py | 9 +++ 8 files changed, 276 insertions(+), 79 deletions(-) create mode 100644 server/authentication.py create mode 100644 server/customlogging.py create mode 100644 server/handlers.py diff --git a/client/__main__.py b/client/__main__.py index bc7c8bc..3970dba 100644 --- a/client/__main__.py +++ b/client/__main__.py @@ -21,6 +21,7 @@ import argparse import socket import json +import hashlib from datetime import datetime from client_log_config import logger @@ -29,6 +30,7 @@ def createParser(): 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 @@ -38,55 +40,84 @@ def createParser(): port = int(re.search('[0-9]{2,}', args.port).group(0)) - -sock = socket.socket() try: + sock = socket.socket() 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': + 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": input("Enter user Name: "), + "status": input("Status message: ") + } + } ) - else: - logger.critical(f"Error request: {response.get('error')}") + # отправить сообщение серверу; + sock.send(msg_presence.encode()) + """ + msg_action = json.dumps( + { + "action": input("Enter action (lower_text): "), + "data": input("Enter data: ") + } + ) + + sock.send(msg_action.encode()) + """ + while True: + # получить ответ сервера; + 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')}" + ) + sock.close() + break + else: + logger.critical(f"Error request: {response.get('error')}") + else: + while True: + # получить ответ сервера; + 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')}" + ) + sock.close() + break + else: + logger.critical(f"Error request: {response.get('error')}") + + #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..bb5a47a 100644 --- a/server/__main__.py +++ b/server/__main__.py @@ -2,13 +2,10 @@ __author__ = "Андрей Петров" import sys - - - import json import socket import argparse - +import select @@ -19,6 +16,7 @@ ) from routes import resolve from server_log_config import logger +from handlers import handle_client_request def createParser(): parser = argparse.ArgumentParser() @@ -35,43 +33,45 @@ def createParser(): sock.bind((args.addr, int(args.port))) sock.listen(5) +responses = [] +connections = [] try: while True: # принимает сообщение клиента; client, address = sock.accept() + connections.append(client) + 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) - else: - response = make_400(request) - logger.critical(f"error 400 bad request: {request}") - - 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") + rlist, wlist, xlist = select.select(connections, connections, [], 0) + + for client in connections: + if client in rlist: #соеденения на запись + data = client.recv(1024) + request = json.loads( + data.decode('utf-8') + ) + action_name = request.get('action') + response = handle_client_request(request) + + if response.get('code') == 400: + logger.error(f'Bad Request: { action_name } request: { request }') + + if response.get('code') == 200: + responses.append(response) + response_string = json.dumps(response) + client.send(response_string.encode('utf-8')) + + if client in wlist: #соеденения слушатели + if responses: + for conn in wlist: + response_obj_string = json.dumps(responses) + conn.send(response_obj_string.encode('utf-8')) + if client in xlist: + pass + #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/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: From 4572eb26516173b6bc46900fc7bafe6f724768c8 Mon Sep 17 00:00:00 2001 From: PAND-or Date: Tue, 26 Mar 2019 14:52:55 +0300 Subject: [PATCH 10/12] ls07 fix --- client/__main__.py | 43 +++++---------------------- server/__main__.py | 73 +++++++++++++++++++++++++++------------------- 2 files changed, 50 insertions(+), 66 deletions(-) diff --git a/client/__main__.py b/client/__main__.py index 3970dba..e4017ad 100644 --- a/client/__main__.py +++ b/client/__main__.py @@ -24,6 +24,7 @@ import hashlib from datetime import datetime from client_log_config import logger +import select def createParser(): @@ -75,46 +76,16 @@ def createParser(): sock.send(msg_action.encode()) """ - while True: - # получить ответ сервера; - 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')}" - ) - sock.close() - break - else: - logger.critical(f"Error request: {response.get('error')}") else: while True: - # получить ответ сервера; - 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')}" - ) - sock.close() - break - else: - logger.critical(f"Error request: {response.get('error')}") + rlist, wlist, xlist = select.select([], [sock], [], 0) - #sock.close() + response = sock.recv(1024) + + if response: + print(response.decode()) + break except KeyboardInterrupt: logger.info(f"client closed") sock.close() diff --git a/server/__main__.py b/server/__main__.py index bb5a47a..868faa4 100644 --- a/server/__main__.py +++ b/server/__main__.py @@ -9,7 +9,6 @@ - from protocol import ( validate_request, make_response, make_400, make_404 @@ -24,6 +23,8 @@ def createParser(): parser.add_argument('-p', '--port', nargs='?', default='7777') return parser +def get_client_fullname(host, port): + return f'{ host }:{ port }' parser = createParser() args = parser.parse_args(sys.argv[1:]) @@ -33,45 +34,57 @@ def createParser(): sock.bind((args.addr, int(args.port))) sock.listen(5) -responses = [] +requests = [] connections = [] + + try: while True: # принимает сообщение клиента; + client, address = sock.accept() - connections.append(client) + client_full_name = get_client_fullname(*address) + connections.append((client_full_name, client)) - logger.info(f'Client detected {address}') + client_sockets = list(map(lambda item: item[1], connections)) - rlist, wlist, xlist = select.select(connections, connections, [], 0) + logger.info(f'Client detected {address}') - for client in connections: - if client in rlist: #соеденения на запись - data = client.recv(1024) - request = json.loads( - data.decode('utf-8') + rlist, wlist, xlist = select.select(client_sockets, client_sockets, [], 0) + + for client in wlist: + read_client_host, read_client_port = client.getsockname() + read_client_fullname = get_client_fullname( + read_client_host, + read_client_port + ) + data = client.recv(1024) + request = json.loads(data.decode('utf-8')) + requests.append((read_client_fullname, request)) + + print(requests) + + if requests: + request_client_fullname, request = requests.pop() + response = handle_client_request(request) + + print(request_client_fullname, request) + for client in rlist: + print('2' * 50) + write_client_host, write_client_port = client.getsockname() + write_client_fullname = get_client_fullname( + write_client_host, + write_client_port ) - action_name = request.get('action') - response = handle_client_request(request) - - if response.get('code') == 400: - logger.error(f'Bad Request: { action_name } request: { request }') - - if response.get('code') == 200: - responses.append(response) - response_string = json.dumps(response) - client.send(response_string.encode('utf-8')) - - if client in wlist: #соеденения слушатели - if responses: - for conn in wlist: - response_obj_string = json.dumps(responses) - conn.send(response_obj_string.encode('utf-8')) - if client in xlist: - pass - #client.close() - #logger.info(f"client {address} closed") + + if write_client_fullname != write_client_fullname: + response_string = json.dumps(response) + client.send(response_string.encode('utf-8')) + logger.info( + f'Response { response_string } sended to {client.getsockname()}' + ) + except KeyboardInterrupt: logger.info(f"server {address} closed") sock.close() From de4c24ab6cb02c9eb3f8c4dd530492d951ece9ae Mon Sep 17 00:00:00 2001 From: PAND-or Date: Tue, 26 Mar 2019 17:19:37 +0300 Subject: [PATCH 11/12] hw07 fix --- client/__main__.py | 32 ++++++++----- server/__main__.py | 117 +++++++++++++++++++++++++++------------------ server/protocol.py | 1 + 3 files changed, 92 insertions(+), 58 deletions(-) diff --git a/client/__main__.py b/client/__main__.py index e4017ad..7949d49 100644 --- a/client/__main__.py +++ b/client/__main__.py @@ -19,7 +19,7 @@ import re import sys import argparse -import socket +from socket import socket, AF_INET, SOCK_STREAM import json import hashlib from datetime import datetime @@ -42,7 +42,7 @@ def createParser(): port = int(re.search('[0-9]{2,}', args.port).group(0)) try: - sock = socket.socket() + sock = socket(AF_INET, SOCK_STREAM) sock.connect((args.host, port)) if args.mode == 'w': @@ -76,16 +76,26 @@ def createParser(): sock.send(msg_action.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')}" + ) + else: + logger.critical(f"Error request: {response.get('error')}") else: - while True: - rlist, wlist, xlist = select.select([], [sock], [], 0) - - response = sock.recv(1024) - - if response: - print(response.decode()) - break + while True: # Постоянный опрос сервера + tm = sock.recv(1024) + print("Текущее время: %s" % tm.decode('utf-8')) + s.close() except KeyboardInterrupt: logger.info(f"client closed") sock.close() diff --git a/server/__main__.py b/server/__main__.py index 868faa4..b885c85 100644 --- a/server/__main__.py +++ b/server/__main__.py @@ -3,7 +3,7 @@ import sys import json -import socket +from socket import socket, AF_INET, SOCK_STREAM import argparse import select @@ -26,65 +26,88 @@ def createParser(): 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) + 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 sock in w_clients: + if sock in requests: + #print('write_responses') + response = handle_client_request(requests[sock]) + response_string = json.dumps(response) + + try: + # Подготовить и отправить ответ сервера + print('Сообщение отправлено') + sock.send(response_string.encode('utf-8')) + except: # Сокет недоступен, клиент отключился + print('Клиент {} {} отключилсяя'.format(sock.fileno(), sock.getpeername())) + #sock.close() + #all_clients.remove(sock) + + + 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() - client_full_name = get_client_fullname(*address) - connections.append((client_full_name, client)) - - client_sockets = list(map(lambda item: item[1], connections)) - - logger.info(f'Client detected {address}') - - rlist, wlist, xlist = select.select(client_sockets, client_sockets, [], 0) - - for client in wlist: - read_client_host, read_client_port = client.getsockname() - read_client_fullname = get_client_fullname( - read_client_host, - read_client_port - ) - data = client.recv(1024) - request = json.loads(data.decode('utf-8')) - requests.append((read_client_fullname, request)) - - print(requests) - - if requests: - request_client_fullname, request = requests.pop() - response = handle_client_request(request) - - print(request_client_fullname, request) - for client in rlist: - print('2' * 50) - write_client_host, write_client_port = client.getsockname() - write_client_fullname = get_client_fullname( - write_client_host, - write_client_port - ) - - if write_client_fullname != write_client_fullname: - response_string = json.dumps(response) - client.send(response_string.encode('utf-8')) - logger.info( - f'Response { response_string } sended to {client.getsockname()}' - ) + try: + conn, addr = sock.accept() # Проверка подключений + except OSError as e: + pass # timeout вышел + else: + 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 # Ничего не делать, если какой-то клиент отключился + + except KeyboardInterrupt: - logger.info(f"server {address} closed") + #logger.info(f"server {address} closed") sock.close() 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: From a07bf7c0575ec65804227de29d3931430b329b7a Mon Sep 17 00:00:00 2001 From: PAND-or Date: Tue, 26 Mar 2019 17:54:26 +0300 Subject: [PATCH 12/12] hw07 fix --- client/__main__.py | 52 +++++++++++++++++++++------------- server/__main__.py | 35 +++++++++++------------ server/presence/controllers.py | 2 +- 3 files changed, 50 insertions(+), 39 deletions(-) diff --git a/client/__main__.py b/client/__main__.py index 7949d49..8845a51 100644 --- a/client/__main__.py +++ b/client/__main__.py @@ -27,7 +27,7 @@ import select -def createParser(): +def create_parser(): parser = argparse.ArgumentParser() parser.add_argument('host', nargs='?', default='localhost') parser.add_argument('port', nargs='?', default='7777') @@ -35,17 +35,41 @@ def createParser(): return parser +def read_response(response, mode='w'): + response = json.loads( + data.decode('utf-8') + ) + # разобрать сообщение сервера; -parser = createParser() + 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 = create_parser() args = parser.parse_args(sys.argv[1:]) port = int(re.search('[0-9]{2,}', args.port).group(0)) + + try: sock = socket(AF_INET, SOCK_STREAM) sock.connect((args.host, port)) if args.mode == 'w': + username = input("Enter user Name: ") while True: # сформировать presence-сообщение; # В формате JIM @@ -59,8 +83,8 @@ def createParser(): "time": datetime.now().timestamp(), "type": "status", "user": { - "account_name": input("Enter user Name: "), - "status": input("Status message: ") + "account_name": username, + "status": input("Your message: ") } } ) @@ -78,24 +102,12 @@ def createParser(): """ # получить ответ сервера; 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')}" - ) - else: - logger.critical(f"Error request: {response.get('error')}") + read_response(data) else: while True: # Постоянный опрос сервера - tm = sock.recv(1024) - print("Текущее время: %s" % tm.decode('utf-8')) - s.close() + data = sock.recv(1024) + read_response(data, 'r') + #sock.close() except KeyboardInterrupt: logger.info(f"client closed") sock.close() diff --git a/server/__main__.py b/server/__main__.py index b885c85..705023f 100644 --- a/server/__main__.py +++ b/server/__main__.py @@ -30,40 +30,39 @@ def get_client_fullname(host, port): def read_requests(r_clients, all_clients): """ Чтение запросов из списка клиентов """ - responses = {} # Словарь ответов сервера вида {сокет: запрос} + 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[sock] = json.loads(data) + responses.append(json.loads(data)) print(responses[sock]) except: print('Клиент {} {} отключился'.format(sock.fileno(), sock.getpeername())) - all_clients.remove(sock) + #all_clients.remove(sock) return responses def write_responses(requests, w_clients, all_clients): - """ Эхо-ответ сервера клиентам, от которых были запросы - """ - - for sock in w_clients: - if sock in requests: - #print('write_responses') - response = handle_client_request(requests[sock]) - response_string = json.dumps(response) - - try: - # Подготовить и отправить ответ сервера - print('Сообщение отправлено') + 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')) - except: # Сокет недоступен, клиент отключился - print('Клиент {} {} отключилсяя'.format(sock.fileno(), sock.getpeername())) + #print('Сообщение отправлено') + except: # Сокет недоступен, клиент отключился + print('Клиент {} {} отключился'.format(sock.fileno(), sock.getpeername())) #sock.close() #all_clients.remove(sock) - + requests.remove(req) parser = createParser() 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 " )