-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPythonChatSatt.py
188 lines (174 loc) · 7.01 KB
/
PythonChatSatt.py
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
#!/usr/bin/python
#Then do py PythonChatServer.py 127.0.0.1 20000
# or py -3 PythonChatServer.py 127.0.0.1 8000
"""This is version 0.0 of the satellite-based python chat server.
It will make NO attempts currently to work with the ground-based server
"""
import base64
import os
import re
import socket
import socketserver
import time
import pychatfuncs
from pychatfuncs import b, d, join, ClientError
#####STARTING LOG FILE#########
foo = time.asctime().split(' ')
l = [foo[4], foo[1], foo[2]]
ADMIN_EMAIL_ADDRESS = "[email protected]"
VALID_CHARS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
##### END LOG FILE SECTION #####
class UserId():
def __init__(self, name, userid=None):
self.name = name
if userid is not None:
if type(userid) != str:
userid = None
else:
if len(userid) != 9:
userid = None
self.userid = userid
if userid is None:
#We must have a new user, so we need to generate
#a user id. the id consists of 9 chars, each of
# which can be a letter or number
allowed = []##Do later
raise Exception("Do stuff here")
self.userid = None
def text(self):
return "UserId(\"%s\", \"%s\""%(self.name,self.userid)
class PythonChatServerSatt(socketserver.ThreadingTCPServer):
"The server class for the satellite."
def __init__(self, server_address, RequestHandlerClass, users_file):
"""Set up an initially empty mapping between a user's nickname
and the file-like object used to send data to that user."""
socketserver.ThreadingTCPServer.__init__(self, server_address,
RequestHandlerClass)
self.users = {}
self.users_file = users_file
def confirm_user(self, username):
user_file = open(self.users_file, 'r')
user_line = username
for line in user_file:
if line.strip() == user_line:
return True
del user_file, user_line, line
return False
class RequestHandler(socketserver.StreamRequestHandler):
"""Handles the life cycle of a user's connection to the chat
server: connecting, chatting, running server commands, and
disconnecting."""
NICKNAME = re.compile('^[A-Za-z0-9_-]+$') #Regex for a valid nickname
def handle(self):
"""Handle the user's input. No nickname is used, but
user-id IS needed. It takes in input in the form of
a command, and can reply back. A connection is quick,
with not much happening.
"""
self.userid = None
self.privateMessage("PythonChatServerSatt")
#The above line is for authentication reasons
username_userid = self._readline()
if d(username_userid).count(":") != 1:
self.privateMessage("Hey! Let the required client software")
self.privateMessage("take care of that!")
done = True
return
print("got username %s"%username)
confirm = self.server.confirm_user(username_userid)
if not confirm:
self.privateMessage("Hey! You need a valid username and user-id")
self.privateMessage("To get one, contact the system admins at")
self.privateMessage(ADMIN_EMAIL_ADDRESS)
return
self.privateMessage("Valid login.")
message = self._readline()
self.continue_code(message)
def continue_code(self, message):
print(message)
def processInput(self):
"""Reads a line from the socket input and either runs it as a
command, or broadcasts it as chat text."""
done = False
l = self._readline()
command, arg = self._parseCommand(l)
if command:
pychatfuncs.write_p("\"%s\" has executed %s.\n"%(d(self.nickname), d(l)) ,1)
done = command(arg)
else:
l = '<%s> %s\n' % (d(self.nickname), d(l))
pychatfuncs.write_p("To all: %s"%l)
self.broadcast(l)
return done
def broadcast(self, message, includeThisUser=True):
"""Send a message to every connected user, possibly exempting the
user who's the cause of the message."""
message = self._ensureNewline(message)
for user, output in self.server.users.items():
if includeThisUser or user != self.nickname:
output.write(b(message))
def privateMessage(self, message):
"Send a private message to this user."
# message=encode_text(message)
n=self._ensureNewline(message).encode()
self.wfile.write(n)
def _readline(self):
"Reads a line, removing any whitespace."
return self.rfile.readline().strip()
def _ensureNewline(self, s):
"Makes sure a string ends in a newline."
if s and s[-1] != '\n':
s += '\r\n'
return s
def _parseCommand(self, i):
"""Try to parse a string as a command to the server. If it's an
implemented command, run the corresponding method."""
try:
i=d(i)
except AttributeError:
pychatfuncs.write_p("User %s tried to run '/_parse'."%d(self.nickname),1)
raise ClientError("Don't try that!")
commandMethod, arg = None, None
if i and i[0] == '/':
if len(i) < 2:
raise ClientError( 'Invalid command: "%s"' % i)
commandAndArg = i[1:].split(' ', 1)
if len(commandAndArg) == 2:
command, arg = commandAndArg
else:
command, = commandAndArg
commandMethod = getattr(self, command + 'Command', None)
if not commandMethod:
raise ClientError( 'No such command: "%s"' % command)
return commandMethod, arg
if __name__ == '__main__':
import sys
# sys.argv.append('127.0.0.1');sys.argv.append('27272')
if len(sys.argv) == 1:
print('Usage: %s [hostname] [port number]' % sys.argv[0])
sys.exit(1)
elif len(sys.argv) == 2:
if sys.argv[1] in ['help','commands','-h','--help']:
print("Future help here")
sys.exit(1)
elif sys.argv[1] in ('log', 'logs'):
print("Logs are in the ./logs folder.")
sys.exit(1)
else:
print("Unknown command")
sys.exit(1)
elif len(sys.argv) > 3:
print("[WARNING] Only first 3 args are used currently! ")
hostname = sys.argv[1]
port = int(sys.argv[2])
try:
PythonChatServerSatt((hostname, port), RequestHandler, "./users").serve_forever()
except (KeyboardInterrupt, EOFError):
print("Stopped Server")
pychatfuncs.write_p("Stopped Server at %s\n"%time.asctime())
sys.exit(0)