Passed
Push — main ( 115f9a...79ca06 )
by Yohann
01:14
created

core.run_cycle()   A

Complexity

Conditions 4

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 15
rs 9.9
c 0
b 0
f 0
cc 4
nop 3
1
import select
2
import socket
3
4
HEADER_LENGTH = 10
5
6
7
def receive_message(client_socket_):
8
    try:
9
        message_header = client_socket_.recv(HEADER_LENGTH)
10
        if not len(message_header):
11
            return False
12
13
        message_length = int(message_header.decode('utf-8').strip())
14
        return {
15
            "header": message_header,
16
            "data": client_socket_.recv(message_length)
17
        }
18
19
    except Exception as e:
20
        print(e)
21
        return False
22
23
24
def start(ip, port):
25
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
26
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
27
28
    server_socket.bind((ip, port))
29
    server_socket.listen()
30
31
    print("server started")
32
    socket_list = [server_socket]
33
    clients = {}
34
35
    while True:
36
        run_cycle(server_socket, socket_list, clients)
37
38
39
def register_user_connection(server_socket, socket_list, clients):
40
    client_socket, client_address = server_socket.accept()
41
42
    user = receive_message(client_socket)
43
44
    if not user:
45
        return
46
47
    socket_list.append(client_socket)
48
    clients[client_socket] = user
49
50
    print(
51
        f"Accepted new connection from {client_address[0]}:"
52
        f"{client_address[1]} username: {user['data'].decode('utf-8')}"
53
    )
54
55
56
def remove_user_connection(clients, notified_socket, socket_list):
57
    print(
58
        "Closed connection from",
59
        clients[notified_socket]['data'].decode('utf-8')
60
    )
61
62
    socket_list.remove(notified_socket)
63
    clients.pop(notified_socket)
64
    return
65
66
67
def send_message_to(client_socket, user, message):
68
    client_socket.send(
69
        user["header"] + user["data"] + message['header'] + message["data"]
70
    )
71
72
73
def broadcast_message(clients, notified_socket, user, message):
74
    for client_socket in clients:
75
        if client_socket != notified_socket:
76
            send_message_to(client_socket, user, message)
77
78
79
def handle_message(clients, notified_socket, message):
80
    user = clients[notified_socket]
81
    print(
82
        f"receive_message from {user['data'].decode('utf-8')}:",
83
        message['data'].decode('utf-8')
84
    )
85
86
    broadcast_message(clients, notified_socket, user, message)
87
88
89
def handle_notified_socket(clients, notified_socket, socket_list):
90
    message = receive_message(notified_socket)
91
92
    if not message:
93
        remove_user_connection(clients, notified_socket, socket_list)
94
        return
95
96
    handle_message(clients, notified_socket, message)
97
98
99
def run_cycle(server_socket, socket_list, clients):
100
    read_sockets, _, exception_sockets = select.select(
101
        socket_list, [], socket_list
102
    )
103
104
    for notified_socket in read_sockets:
105
        if notified_socket == server_socket:
106
            register_user_connection(server_socket, socket_list, clients)
107
108
        else:
109
            handle_notified_socket(clients, notified_socket, socket_list)
110
111
    for notified_socket in exception_sockets:
112
        socket_list.remove(notified_socket)
113
        clients.pop(notified_socket)
114