-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathserver.py
More file actions
executable file
·92 lines (72 loc) · 3.2 KB
/
Copy pathserver.py
File metadata and controls
executable file
·92 lines (72 loc) · 3.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#!/usr/bin/python
import socketserver
import json
from typing import List
clients = []
ROWS, COLS = 24, 79
def replace_substring_at_index(s: str, new_substring: str, index: int) -> str:
return s[:index] + new_substring + s[index + len(new_substring):]
def initial_canvas() -> List[str]:
canvas: List[str] = [f" __MINITALK{'_'*(COLS-12)} "]
canvas.append(f"/{' '*(COLS-2)}\\")
for _ in range(ROWS-3):
canvas.append(f"|{' '*(COLS-2)}|")
canvas.append(f"\\{'_'*(COLS-2)}/")
return canvas
class TextEditorServer(socketserver.BaseRequestHandler):
canvas: List[str] = initial_canvas()
def handle(self):
print(f"Client {self.client_address} connected.")
# Add client to the list
clients.append(self.request)
# First connection: send the whole canvas
first_message = {
"type": "sync",
"canvas": TextEditorServer.canvas
}
self.request.sendall(json.dumps(first_message).encode())
try:
while True:
# Wait for any client to send us data
data = self.request.recv(1024).decode()
if not data:
print(f"Client {self.client_address} disconnected.")
break
print(f"Received data:", data)
# We expect from a client:
# { "type": "update", "text": "...", "row": ..., "col": ..., "client_id": "...", "username": "..." }
# Sometimes multiple messages are sent together
# which means we receive invalid json: {...}{...}
split_data = data.replace("}{", "}|{").split('|')
for d in split_data:
update = json.loads(d)
if update["text"] == "\u000b":
print("received C-k so clearing the canvas")
TextEditorServer.canvas = initial_canvas()
update = {
"type": "sync",
"canvas": TextEditorServer.canvas
}
data = json.dumps(update)
else:
TextEditorServer.canvas[update["row"]] = \
replace_substring_at_index(
TextEditorServer.canvas[update["row"]],
update["text"],
update["col"]
)
# Broadcast received data to other clients
print(f"broadcasting {update['type']}")
data = json.dumps(update)
for client in clients:
if update["type"] == "sync" or client != self.request:
client.sendall(data.encode())
print(f"Sent data to client")
finally:
clients.remove(self.request)
print(f"Client {self.client_address} removed from active clients.")
if __name__ == "__main__":
HOST, PORT = "0.0.0.0", 9999
print(f"Starting server on {HOST}:{PORT}.")
server = socketserver.ThreadingTCPServer((HOST, PORT), TextEditorServer)
server.serve_forever()