-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchat.py
More file actions
139 lines (132 loc) · 3.95 KB
/
chat.py
File metadata and controls
139 lines (132 loc) · 3.95 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
from .chattools import *
import time
import threading
from socket import *
from .manager import Manager
def now():
return time.ctime(time.time())
#functions for manipulating
def encode(data):
msg = Frame.buildMessage(data.encode(),mask=False)
return msg
def decode(f):
return "".join([chr(x) for x in f.message()])
#not actually sure if it doesn't overeat memory
class SocketServer:
def __init__(self,host,port,manager):
self.manager = manager
self.sock = socket(AF_INET,SOCK_STREAM)
self.sock.bind((host,port))
self.sock.listen(5)
self.lock = threading.Lock()
def start(self):
while True:
connection,address = self.sock.accept()
print("New connection at " + now() + "!")
Handler(connection,self.manager,self.lock).start()
self.stop()
def stop(self):
self.sock.close()
class Client(threading.Thread):
handshaken = []
def __init__(self,con,manager,lock):
self.lock = lock
self.sock = con
self.sock.settimeout(60*60*3)
self.manager = manager
self.uname = None
self.thread = None
self.password = None
threading.Thread.__init__(self)
def close(self):
if self.sock in self.handshaken:
self.handshaken.remove(self.sock)
self.sock.close()
self.manager.remove(self)
def run(self):
while True:
#it should be running only for 4 hours
try:
if self.sock not in self.handshaken:
data = self.sock.recv(10000)
upgrade = Handshake.upgrade(data)
if not upgrade:break
self.handshaken.append(self.sock)
self.sock.send(upgrade.encode())
continue
else:
data = self.sock.recv(1024)
if not data:break
frame = Frame(data)
if frame.opcode == 1:
#actually not sure if this lock is necessary
with self.lock:
self.handle(decode(frame))
else:
break
except timeout:break
self.close()
print("Connection closed! ", now())
class Handler(Client):
#format : a: b\r\nc: d\r\n,query type is a must
def parse_headers(self,headers):
final = {}
s = headers.split('\r\n')
for val in s:
if len(val) > 4:
delim = val.find(":")
final[val[:delim]] = val[delim+2:]
return final
def handle(self,query):
data = self.parse_headers(query)
qr = data.get('query')
if not qr:return False
if qr in "auth|message|subscribe|unsubscribe".split("|"):
getattr(self,qr)(data)
else:self.sock.send(encode("Invalid query!"))
def auth(self,data):
name = data.get('name')
password = data.get('password')
self.uname = name
self.password = password
action = self.manager.add(self)
if action:
self.uname = name
self.sock.send(encode("You've connected!"))
self.manager.send(self,encode("User "+ self.uname + " has connected!"))
else:
self.sock.send(encode("""You cannot connect as you did not log in on the server
or you have already logged in in the chat!"""))
def message(self,data):
if not self.check_auth():return
message = data.get('message')
if message:
self.manager.send(self,encode("User " + self.uname + " : " + message))
else:
self.sock.send(encode("You cannot send this message =("))
def subscribe(self,data):
if not self.check_auth():return
topic = data.get('topic')
if topic:
self.sock.send(encode("Trying to subscribe to the " + topic))
sub = self.manager.subscribe(self,topic)
if sub:self.manager.send(self,encode("User " + self.uname + " has joined us!"))
else:self.sock.send(encode("Subscription failed!"))
else:
self.sock.send(encode("You did not define the topic!"))
def unsubscribe(self,data):
if not self.check_auth():return
self.sock.send(encode("Unsubscribing..."))
self.manager.send(self,encode("User " + self.uname + " unsubscribed"))
unsub = self.manager.unsubscribe(self)
if unsub:self.sock.send(encode("You've unsubscribed!"))
def check_auth(self):
if not self.uname:
self.sock.send(encode("You should log in!"))
return False
return True
#the way to start it
#if __name__ == '__main__':
#manager = Manager([{'name':'test'}])
#server = SocketServer('',50001,manager)
#server.start()