Я делаю простой чат asyncio.Protocol Сервер-Клиент. Осталось сохранить историю чата, чтобы каждый новый клиент после установки псевдонима получал историю чата.
Понятия не имею, как избежать дублирования сообщений в потоке данных. Я попытался захватить то, что отображается в экземпляре сервера в файл. У меня не было этой проблемы в версии с розетками и протекторами.
Что-то ускользает от меня, и это определенно клише.
CLIENT.py
import asyncio
import threading
import socket
import sServer
import random
class Client(asyncio.Protocol):
def __init__(self):
self.name = None
def connection_made(self, transport):
self.name = set_nickname()
print("Type your message below or 'EXIT' to quit")
self.transport = transport
try:
with open('history.txt', 'rt') as history:
content = history.read()
print(content)
except FileNotFoundError:
pass
transport.write(('USR:'+self.name).encode())
thread = threading.Thread(target=self.handle_input, daemon=True)
thread.start()
def data_received(self, data):
print(data.decode())
def eof_received(self):
print("Connection lost...")
def connection_lost(self, exc):
self.transport.close()
def handle_input(self):
while True:
message = input('ME> ')
if message == 'EXIT':
self.transport.write(message.encode())
# elif message == 'HIST':
# self.load_history()
else:
self.transport.write(('MSG:'+message).encode())
def set_nickname():
try:
#user = 'hardcoded'
print("Type your nickname: ")
user = input().strip()
print("Hello {}".format(user))
client_name = socket.gethostname()
ip = socket.gethostbyname(client_name)
# create random n
rest = random.randrange(1, 100, 1)
# for local purpose and testing multiply clients
client_ip = "@{}-{}".format(ip, str(rest))
user = user + client_ip
return user
except:
pass
def main():
loop = asyncio.get_event_loop()
coroutine = loop.create_connection(Client, sServer.HOST, sServer.PORT)
loop.run_until_complete(coroutine)
loop.run_forever()
loop.close()
if __name__ == "__main__":
main()
SERVER.py
import asyncio
import json
import sys
import os.path
HOST = '127.0.0.1'
PORT = 6666
active_users = []
history = {}
class Server(asyncio.Protocol):
""" Overriding Protocol methods:
connection_made
data_received
connection_lost
"""
def connection_made(self, transport):
self.transport = transport
self.address = transport.get_extra_info('peername')
print('Connection from {}'.format(self.address))
def data_received(self, data):
stream = data.decode()
if stream.startswith("USR:"):
self.username = stream[4:]
add_user(self)
elif stream.startswith("MSG:"):
msg = stream[4:]
receive_message((self.username + ': ' + msg), self)
#update_history((self.username + ': ' + msg), self)
history.update({self.username: msg})
with open('history.txt', 'a+') as sample:
for save in [history]:
sample.write('{}\n'.format(save))
elif stream == 'EXIT':
remove_user(self)
self.transport.close()
def add_user(user):
active_users.append(user)
receive_message(user.username + ' has joined!', user)
def remove_user(user):
active_users.remove(user)
receive_message(user.username + ' has left.', user)
def receive_message(msg, author):
print(msg)
for user in active_users:
# don't show user's own messages in session
if user is not author:
user.transport.write(msg.encode())
def main():
loop = asyncio.get_event_loop()
coroutine = loop.create_server(Server, HOST, PORT)
server = loop.run_until_complete(coroutine)
print('Server established on {}'.format(server.sockets[0].getsockname()))
try:
loop.run_forever()
except KeyboardInterrupt:
if os.path.exists('history.txt'):
try:
os.remove('history.txt')
sys.exit()
except OSError:
pass
finally:
server.close()
loop.close()
if __name__ == '__main__':
main()