Repository navigation
Expand file tree
/
Copy pathmsghost.py
More file actions
259 lines (235 loc) · 11.7 KB
/
Copy pathmsghost.py
File metadata and controls
259 lines (235 loc) · 11.7 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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
import socket
import threading
import json
from datetime import datetime
from time import sleep
def broadcast(msg):
clients_lock.acquire()
for broad_client in clients.values():
broad_client.send(msg.encode())
clients_lock.release()
def handle(client, name, groups_lock, clients_lock):
global groups
while True:
try:
data = client.recv(1024)
clients_lastonline[name] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
data_loaded = json.loads(data.decode())
log(name, f"Recevied following data: {data_loaded}")
cmd = data_loaded['cmd']
if cmd[0] == 'SENDMSG':
receiver = cmd[1]
timestamp = cmd[2]
clients_lock.acquire()
groups_lock.acquire()
if receiver in groups and name in groups[receiver]['members']:
data_loaded['cmd'].insert(2, name)
for member in groups[receiver]['members']:
if member == name:
continue
try:
data = json.dumps(
{'cmd': ['NEWGPMSG', receiver, name, timestamp], 'args': data_loaded['args']})
clients[member].send(data.encode())
except:
log(name, f"{receiver} unable to receive message. Cached.")
data = json.dumps({'cmd': ['OFFLINEGPMSG', receiver, member, clients_lastonline[member]],
'args': data_loaded['args']})
client.send(data.encode())
gp_cache.setdefault(member, []).append(data_loaded)
elif receiver not in clients and receiver not in clients_lastonline:
log(name, f"Tried to send message to {receiver} but it doesn't exist.")
data = json.dumps({'cmd': ["ERROR"], 'args': f"Recevier {receiver} doesn't exist."})
client.send(data.encode())
else:
try:
data = json.dumps({'cmd': ['NEWMSG', name, cmd[2]], 'args': data_loaded['args']})
clients[receiver].send(data.encode())
except:
log(name, f"{receiver} unable to receive message. Cached.")
data = json.dumps({'cmd': ['OFFLINEMSG', receiver, clients_lastonline[receiver]],
'args': data_loaded['args']})
client.send(data.encode())
data_loaded['cmd'][1] = name
cache.setdefault(receiver, []).append(data_loaded)
groups_lock.release()
clients_lock.release()
elif cmd[0] == 'CREATEGROUP':
group_name = cmd[1]
admin = cmd[2]
members = data_loaded['args']
groups_lock.acquire()
if group_name in groups:
log(name, f"Group '{group_name}' already exists.")
data = json.dumps({'cmd': ["ERROR"],
'args': f"Group '{group_name}' already exists. Please pick a new group name."})
client.send(data.encode())
else:
all_exist = True
clients_lock.acquire()
for member in members:
if member not in clients and member not in clients_lastonline:
log(name, f"Tried to add {receiver} user to group {group_name} but the user doesn't exist.")
data = json.dumps(
{'cmd': ["ERROR"], 'args': f"User {receiver} doesn't exist. Please retry"})
client.send(data.encode())
all_exist = False
if all_exist:
members.append(admin)
groups[group_name] = {'admin': admin, 'members': members}
for member in members:
if member != name:
data = json.dumps(
{'cmd': ["BROADCAST"],
'args': f"You have been added to group '{group_name}' with members of {members}."})
clients[member].send(data.encode())
else:
data = json.dumps(
{'cmd': ["BROADCAST"],
'args': f"You have created group '{group_name}' with members of {members}."})
client.send(data.encode())
clients_lock.release()
print(f"Current group list: {groups}")
groups_lock.release()
elif cmd[0] == 'GROUPMAN':
group_name = cmd[2]
groups_lock.acquire()
if group_name not in groups:
data = json.dumps(
{'cmd': ["ERROR"], 'args': f"'{group_name}' group doesn't exist."})
client.send(data.encode())
elif groups[group_name]['admin'] == name:
if cmd[1] == 'ADD':
members_list = data_loaded['args']
for member in members_list:
if member not in groups[group_name]['members']:
groups[group_name]['members'].append(member)
clients_lock.acquire()
for member in groups[group_name]['members']:
data = json.dumps(
{'cmd': ["BROADCAST"],
'args': f"Group '{group_name}' has been updated with new member list: {members}."})
clients[member].send(data.encode())
clients_lock.release()
elif cmd[1] == 'REMOVE':
members_list = data_loaded['args']
for member in members_list:
if member in groups[group_name]['members']:
groups[group_name]['members'].remove(member)
data = json.dumps(
{'cmd': ["BROADCAST"],
'args': f"You have been removed from group '{group_name}'."})
clients[member].send(data.encode())
clients_lock.acquire()
for member in groups[group_name]['members']:
data = json.dumps(
{'cmd': ["BROADCAST"],
'args': f"Group '{group_name}' has been updated with new member list: {members}."})
clients[member].send(data.encode())
clients_lock.release()
else:
data = json.dumps(
{'cmd': ["ERROR"], 'args': f"You are not the admin of '{group_name}'."})
client.send(data.encode())
groups_lock.release()
elif cmd[0] == 'QUIT':
clients_lock.acquire()
del clients[name]
clients_lock.release()
broadcast(json.dumps({'cmd': ['BROADCAST'], 'args': f"{name} has left the chat."}))
data = json.dumps({'cmd': ['QUIT']})
client.send(data.encode())
exit(0)
else:
data = json.dumps(
{'cmd': ["ERROR"], 'args': "Invalid command."})
client.send(data.encode())
except Exception as msg:
# broadcast missing of client
clients_lock.acquire()
if name in clients:
del clients[name]
clients_lock.release()
broadcast(json.dumps({'cmd': ['ERROR'], 'args': f"{name}'s client occured an error."}))
print("Error occured. Closing connection now....")
print(msg)
client.close()
exit(0)
def log(addr, msg):
print(f"{str(addr)}: {msg}")
def setup(socket):
global clients
while True:
client, addr = socket.accept()
print(f"Connected with {str(addr)}")
cmd = json.dumps({'cmd': ['NICK'], 'args': ''})
client.send(cmd.encode())
data = client.recv(1024).decode()
name = json.loads(data)
if name['cmd'][0] == 'NAME':
clients_lock.acquire()
clients[name['args']] = client
clients_lastonline[name['args']] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
clients_lock.release()
log(addr, f"Setup its nickname as {name['args']}")
broadcast(json.dumps({'cmd': ['NEWUSER'], 'args': name['args']}))
if name['args'] in cache and len(cache[name['args']]) > 0:
log(name['args'], "Found cached message. Re-sending right now....")
i = 1
cache_to_sent = []
for cached_data in cache[name['args']]:
log(name['args'], f"Sorting {str(i)}th cached message...")
cached_data_cmd = cached_data['cmd']
cache_to_sent.append([i, cached_data_cmd[1], cached_data_cmd[2], cached_data['args']])
i += 1
data = json.dumps({'cmd': ['CACHEDMSG'], 'args': cache_to_sent})
log(name['args'], f"Sending following cached data: {data}")
client.send(data.encode())
cache[name['args']] = []
if name['args'] in gp_cache and len(gp_cache[name['args']]) > 0:
log(name['args'], "Found cached group message. Re-sending right now....")
i = 1
cache_to_sent = []
for cached_data in gp_cache[name['args']]:
log(name['args'], f"Sorting {str(i)}th cached group message...")
cached_data_cmd = cached_data['cmd']
cache_to_sent.append(
[i, cached_data_cmd[1], cached_data_cmd[2], cached_data_cmd[3], cached_data['args']])
i += 1
data = json.dumps({'cmd': ['CACHEDGPMSG'], 'args': cache_to_sent})
log(name['args'], f"Sending following cached group data: {data}")
sleep(0.05)
client.send(data.encode())
gp_cache[name['args']] = []
# Start Handling Thread For Client
thread = threading.Thread(target=handle, args=(client, name['args'], groups_lock, clients_lock))
thread.start()
else:
print(f"Error establishing username with {str(addr)}.")
print(f"Terminated connection with {str(addr)}.")
client.close()
exit
s4 = socket.socket()
s6 = socket.socket(family=socket.AF_INET6, type=socket.SOCK_STREAM)
host4 = socket.gethostname()
host6 = socket.gethostname()
port4 = 12345
port6 = 12346
print(f"IPv4: {str(socket.gethostbyname(host4))}:{port4}")
print(f"IPv6: {str(socket.getaddrinfo(host6, port6, family=socket.AF_INET6)[0][4][0])}")
s4.bind((host4, port4))
s4.listen(5)
sa = socket.getaddrinfo(host6, port6, family=socket.AF_INET6)[0][4]
s6.bind(sa)
s6.listen(5)
groups = {}
groups_lock = threading.Lock()
clients_lock = threading.Lock()
clients = {}
clients_lastonline = {}
cache = {}
gp_cache = {}
thread = threading.Thread(target=setup, args=(s4,))
thread.start()
thread = threading.Thread(target=setup, args=(s6,))
thread.start()