Implemented entire chat client according to given protocol.

parent e9191165
......@@ -41,7 +41,7 @@ class ClientConnection(object, asyncore.dispatcher):
self.port = addr[1]
super(ClientConnection, self).connect(addr)
def send(self, cmd):
def send_raw(self, cmd):
"""
Send raw command to the chat server.
"""
......@@ -52,6 +52,8 @@ class ClientConnection(object, asyncore.dispatcher):
Retreive list of users active at the chat server.
"""
self.request_user_list_sent = True
self.retrieved_user_list = False
self.send_queue.put('NAMES')
def username(self, name=''):
......@@ -94,7 +96,6 @@ class ClientConnection(object, asyncore.dispatcher):
# Remove trailing '\n\r' from multi line response
buf = buf[:-2]
break
multi_line = False
buf += chunk
buf = buf[:-1]
......@@ -110,8 +111,9 @@ class ClientConnection(object, asyncore.dispatcher):
def handle_write(self):
if not self.send_buffer:
self.send_buffer = self.send_queue.get() + '\r\n'
self.debug_log('> %s' % self.send_buffer[:-2])
self.send_buffer = self.send_queue.get()
self.debug_log('> %s' % self.send_buffer)
self.send_buffer += '\r\n'
sent = self.send(self.send_buffer)
self.send_buffer = self.send_buffer[sent:]
......@@ -134,27 +136,40 @@ class ClientConnection(object, asyncore.dispatcher):
if 'response' in self.event_list:
self.event_list['response'](self, buf)
# First authenticate the user.
if not self.authenticated:
if not self.authentification_sent:
self.send_queue.put('USER %s' % self.user)
self.authentification_sent = True
elif buf[1:10] == 'Username':
elif buf[1:9] == 'Username':
# TODO: handle 'username is taken'.
self.authenticated = True
if 'authenticated' in self.event_list:
self.event_list['authenticated'](self, self.user)
#if not self.retrieved_user_list:
# if not self.request_user_list_sent:
# self.request_user_list_sent = True
# self.retrieve_users()
# else:
# # TODO: process user list
# self.retrieved_user_list = True
# #self.debug_log('i Users: %s' % str(buf.split('\r\n')[:-1]))
if not self.authenticated:
return
# After authentification, fetch the list of users currently logged in.
if not self.retrieved_user_list:
if not self.request_user_list_sent:
self.request_user_list_sent = True
self.retrieve_users()
else:
# TODO: process user list
self.retrieved_user_list = True
msg = 'Users: [%s]' % '] ['.join(buf.split('\r\n')[1:])
if 'info' in self.event_list:
self.event_list['info'](self, msg)
else:
self.debug_log(msg)
def parse_notification(self, buf):
if 'notify' in self.event_list:
match = re.match('^SAY ([^\r\n:/]+)/(.+)', buf)
if match:
if 'message' in self.event_list:
self.event_list['message'](self, match.group(1), match.group(2))
elif 'notify' in self.event_list:
self.event_list['notify'](self, buf)
def writable(self):
......
import curses
from Queue import Queue
from time import strftime
class BaseWindow(object):
def __init__(self, main, top, left, height, width):
......@@ -28,7 +29,7 @@ class BaseWindow(object):
while not self.line_queue.empty():
self.lines.append(self.line_queue.get())
if self.displayed_help:
if hasattr(self,'displayed_help') and self.displayed_help:
return
for y, line in enumerate(self.lines[-self.height:]):
......@@ -42,7 +43,9 @@ class BaseWindow(object):
self.window.refresh()
def append(self, msg):
time_prefix = strftime('%H:%M') + ' '
while msg:
msg = time_prefix + msg
self.line_queue.put(msg[:self.width])
msg = msg[self.width:]
self.redraw()
......
......@@ -81,7 +81,7 @@ class CLI:
self.chat_window = ChatWindow(self, 0, 0, self.max_y - 8, self.max_x)
# Debug bar between chat window and info bar
self.debug_window = DebugWindow(self, self.max_y - 5, 0, 3, self.max_x)
self.debug_window = DebugWindow(self, self.max_y - 7, 0, 5, self.max_x)
# Info bar between debug window and command bar
self.info_bar = InfoBar(self, self.max_y - 2, 0, self.max_x)
......@@ -118,7 +118,7 @@ class CLI:
def connect(main, host, port=16897):
if getattr(port, '__class__') != '<type \'int\'>':
if not isinstance(port, int):
port = int(port)
# Disconnect an active connection.
......@@ -132,6 +132,8 @@ class CLI:
main.connection.main = main
main.connection.event_list['debug'] = main.debug_event
main.connection.event_list['connect'] = main.connect_event
main.connection.event_list['info'] = main.info_event
main.connection.event_list['message'] = main.message_event
main.connection.event_list['notify'] = main.notify_event
main.connection.event_list['authenticated'] = \
main.authenticated_event
......@@ -185,8 +187,15 @@ All commands listed below should be preceded by a slash:
help This help page.
names Retrieve and display a list of usernames currently logged in on
the chat server.
quit Quit this chat application (shortcut: ^c).
raw Send a raw command to the server. This is useful during debugging
the client and/or server since you do not have to restart the
application to send an unimplemented message to the server/client.
user Change your username to USER.
"""
......@@ -199,7 +208,7 @@ All commands listed below should be preceded by a slash:
e = None
try:
del self.connection
except:
except Exception, e:
pass
# Reverse the curses-friendly terminal settings.
......@@ -216,9 +225,16 @@ All commands listed below should be preceded by a slash:
sys.exit(0)
def raw(main, cmd):
main.connection.send(cmd)
# Skip "/raw " and send the remaining command to the server.
if main.connection:
main.connection.send_raw(cmd[5:])
def names(main):
if main.connection:
main.connection.retrieve_users()
def user(main, name):
if main.connection:
main.connection.username(name)
def _exec(main, cmd):
......@@ -232,11 +248,15 @@ All commands listed below should be preceded by a slash:
'disconnect': disconnect,
'exec': _exec,
'help': help,
'names': names,
'quit': quit,
'raw': raw,
'user': user,
}
def say(self, msg):
self.connection.send_raw('SAY %s' % msg)
def refresh(self):
self.chat_window.refresh()
self.debug_window.refresh()
......@@ -255,11 +275,19 @@ All commands listed below should be preceded by a slash:
self.refresh()
def debug_event(self, conn, msg):
self.chat_window.append(msg)
self.debug_window.append(msg)
self.refresh()
def message_event(self, conn, user, msg):
self.chat_window.append('%s: %s' % (user, msg))
self.refresh()
def info_event(self, conn, msg):
self.chat_window.append('i %s' % msg)
self.refresh()
def notify_event(self, conn, msg):
self.chat_window.append(msg)
self.chat_window.append('~ %s' % msg)
self.refresh()
def display_info(self, msg):
......
......@@ -54,5 +54,6 @@ class CommandBar(BaseBar):
self.main.execute(cmd, args, command)
else:
pass
# User sends a chat message.
self.main.say(command)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment