Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 24 additions & 63 deletions client.py
Original file line number Diff line number Diff line change
@@ -1,71 +1,32 @@
#!/usr/bin/env python3
"""Script for Tkinter GUI chat client."""
from socket import AF_INET, socket, SOCK_STREAM
from threading import Thread
import tkinter
import socket
import json
from config import get_client_socket
from console_menu import print_menu, get_command

def send_data(s):
data = {
"text": input("Input text: "),
"user": input("Input username: "),
"age": int(input("Input age: "))
}

def receive():
"""Handles receiving of messages."""
while True:
try:
msg = client_socket.recv(BUFSIZ).decode("utf8")
msg_list.insert(tkinter.END, msg)
except OSError: # Possibly client has left the chat.
break


def send(event=None): # event is passed by binders.
"""Handles sending of messages."""
msg = my_msg.get()
my_msg.set("") # Clears input field.
client_socket.send(bytes(msg, "utf8"))
if msg == "{quit}":
client_socket.close()
top.quit()

s.send(json.dumps(data).encode("utf-8"))

def on_closing(event=None):
"""This function is to be called when the window is closed."""
my_msg.set("{quit}")
send()
print("Data sended")

top = tkinter.Tk()
top.title("Chatter")
def exit_program(s):
s.send(json.dumps({"exit": ""}).encode("utf-8"))
print("Exit")
exit()

messages_frame = tkinter.Frame(top)
my_msg = tkinter.StringVar() # For the messages to be sent.
my_msg.set("Type your messages here.")
scrollbar = tkinter.Scrollbar(messages_frame) # To navigate through past messages.
# Following will contain the messages.
msg_list = tkinter.Listbox(messages_frame, height=15, width=50, yscrollcommand=scrollbar.set)
scrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y)
msg_list.pack(side=tkinter.LEFT, fill=tkinter.BOTH)
msg_list.pack()
messages_frame.pack()
if __name__ == "__main__":
s = get_client_socket()
menu = ["Send data", "Exit"]

entry_field = tkinter.Entry(top, textvariable=my_msg)
entry_field.bind("<Return>", send)
entry_field.pack()
send_button = tkinter.Button(top, text="Send", command=send)
send_button.pack()
actions = {"1":send_data, "2":exit_program}

top.protocol("WM_DELETE_WINDOW", on_closing)

#----Now comes the sockets part----
HOST = input('Enter host: ')
PORT = input('Enter port: ')
if not PORT:
PORT = 33000
else:
PORT = int(PORT)

BUFSIZ = 1024
ADDR = (HOST, PORT)

client_socket = socket(AF_INET, SOCK_STREAM)
client_socket.connect(ADDR)
while True:
print_menu(menu)
command = get_command(menu)

receive_thread = Thread(target=receive)
receive_thread.start()
tkinter.mainloop() # Starts GUI execution.
actions[command](s)
15 changes: 15 additions & 0 deletions config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import socket

ADDRESS = "localhost"
PORT = 9292

def get_client_socket():
s = socket.socket()
s.connect((ADDRESS, PORT))
return s

def get_server_socket():
s = socket.socket()
s.bind((ADDRESS, PORT))
s.listen(10)
return s
19 changes: 19 additions & 0 deletions console_menu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
def print_menu(menu):
for i,m in enumerate(menu, start=1):
print(f"{i}.{m}")

def get_command(menu):

while True:
command = input("Input command: ")

if command.isdigit() and (1 <= int(command) <= len(menu)):
return command
else:
print("Wrong command. Try again!")


if __name__ == "__main__":
pass

# import this
32 changes: 32 additions & 0 deletions lesson03/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import socket
import json
from config import get_client_socket
from console_menu import print_menu, get_command

def send_data(s):
data = {
"text": input("Input text: "),
"user": input("Input username: "),
"age": int(input("Input age: "))
}

s.send(json.dumps(data).encode("utf-8"))

print("Data sended")

def exit_program(s):
s.send(json.dumps({"exit": ""}).encode("utf-8"))
print("Exit")
exit()

if __name__ == "__main__":
s = get_client_socket()
menu = ["Send data", "Exit"]

actions = {"1":send_data, "2":exit_program}

while True:
print_menu(menu)
command = get_command(menu)

actions[command](s)
15 changes: 15 additions & 0 deletions lesson03/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import socket

ADDRESS = "localhost"
PORT = 9292

def get_client_socket():
s = socket.socket()
s.connect((ADDRESS, PORT))
return s

def get_server_socket():
s = socket.socket()
s.bind((ADDRESS, PORT))
s.listen(10)
return s
19 changes: 19 additions & 0 deletions lesson03/console_menu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
def print_menu(menu):
for i,m in enumerate(menu, start=1):
print(f"{i}.{m}")

def get_command(menu):

while True:
command = input("Input command: ")

if command.isdigit() and (1 <= int(command) <= len(menu)):
return command
else:
print("Wrong command. Try again!")


if __name__ == "__main__":
pass

# import this
74 changes: 74 additions & 0 deletions lesson03/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import socket
import json
from config import get_server_socket
s = get_server_socket()
print("Server started")
client, addr = s.accept()
print("Client connected: ",client, addr)

while True:
print("Waiting data")

data = json.loads(client.recv(1024).decode("utf-8"))
print("Data received")

if "exit" not in data:
print(data)
else:
client.close()
s.close()
print("Exit")
break






# Присутствие
# Каждый пользователь при подключении к серверу отсылает сервисное сообщение о присутствии — presence с необязательным полем type:
# {
# "action": "presence",
# "time": <unix timestamp>,
# "type": "status",
# "user": {
# "account_name": "C0deMaver1ck",
# "status": "Yep, I am here!"
# }
# }
#

# Коды ответов сервера
# JIM-протокол использует коды ошибок HTTP. Перечислим поддерживаемые:
# 1xx — информационные сообщения:
# 100 — базовое уведомление;
# 101 — важное уведомление.
# 2xx — успешное завершение:
# 200 — OK;
# 201 (created) — объект создан;
# 202 (accepted) — подтверждение.
# 4xx — ошибка на стороне клиента:
# 400 — неправильный запрос/JSON-объект;
# 401 — не авторизован;
# 402 — неправильный логин/пароль;
# 403 (forbidden) — пользователь заблокирован;
# 404 (not found) — пользователь/чат отсутствует на сервере;
# 409 (conflict) — уже имеется подключение с указанным логином;
# 410 (gone) — адресат существует, но недоступен (offline).
# 5xx — ошибка на стороне сервера:
# 500 — ошибка сервера.
# Коды ошибок могут быть дополнены новыми.
#
# Сообщения-ответы имеют следующий формат (в зависимости от кода ответа):
# {
# "response": 1xx / 2xx,
# "time": <unix timestamp>,
# "alert": "message (optional for 2xx codes)"
# }
#
# Или такой:
# {
# "response": 4xx / 5xx,
# "time": <unix timestamp>,
# "error": "error message (optional)"
# }
22 changes: 22 additions & 0 deletions lesson05/01_logging_basic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# ------- Журналирование (логгирование) с использованием модуля logging -------
# Базовая настройка

import logging

# Быстрая настройка логгирования может быть выполнена так:
logging.basicConfig(
# filename = "app_01.log",
format = "%(levelname)s %(asctime)s %(message)s",
level = logging.DEBUG
)

# Для использования логгера его нужно получить/создать функцией getLogger
log = logging.getLogger('basic')

# После этого можно использовать логгирование таким образом
log.debug('There will be debug information')
log.info('Hello, World!')
log.warning('It seems to be a bug...')
log.critical('Critical bug in app! Hello, World!')

# Обратите внимание, что не все сообщения попали в лог-файл. Почему?
21 changes: 21 additions & 0 deletions lesson05/02_logging_formatter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# ------- Журналирование (логгирование) с использованием модуля logging -------
# Расширенная настройка настройка. Форматирование, обработчики

import logging
import sys

# Определить формат сообщений
_format = logging.Formatter("%(levelname)-10s %(asctime)s %(message)s")

# Создать обработчик, который выводит сообщения с уровнем CRITICAL в поток stderr
crit_hand = logging.StreamHandler(sys.stderr)
crit_hand.setLevel(logging.CRITICAL)
crit_hand.setFormatter(_format)

# Создать регистратор
log = logging.getLogger('basic')

# Добавить обработчик к регистратору
log.addHandler(crit_hand)
# Передать сообщение обработчику
log.critical('Oghr! Kernel panic!')
23 changes: 23 additions & 0 deletions lesson05/03_use_log_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# ------- Журналирование (логгирование) с использованием модуля logging -------
# Вынесение настройки логгирования в отдельный модуль


import logging

import log_config

# Обратите внимание, логгер уже создан в модуле log_config,
# теперь нужно его просто получить
log = logging.getLogger('app.main')

def main():
''' Тестовая главная функция
'''
# logger.debug('Старт приложения')
log.debug('There will be debug information')
log.info('Hello, World!')
log.warning('It seems to be a bug...')
log.critical('Critical bug in app! Hello, World!')

if __name__ == '__main__':
main()
Loading