forked from rh2513/chat_student
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
19 changed files
with
790 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import time | ||
import socket | ||
import select | ||
import sys | ||
import json | ||
from chat_utils import * | ||
import client_state_machine_student as csm | ||
|
||
import threading | ||
|
||
class Client: | ||
def __init__(self, args): | ||
self.peer = '' | ||
self.console_input = [] | ||
self.state = S_OFFLINE | ||
self.system_msg = '' | ||
self.local_msg = '' | ||
self.peer_msg = '' | ||
self.args = args | ||
|
||
def quit(self): | ||
self.socket.shutdown(socket.SHUT_RDWR) | ||
self.socket.close() | ||
|
||
def get_name(self): | ||
return self.name | ||
|
||
def init_chat(self): | ||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM ) | ||
svr = SERVER if self.args.d == None else (self.args.d, CHAT_PORT) | ||
self.socket.connect(svr) | ||
self.sm = csm.ClientSM(self.socket) | ||
reading_thread = threading.Thread(target=self.read_input) | ||
reading_thread.daemon = True | ||
reading_thread.start() | ||
|
||
def shutdown_chat(self): | ||
return | ||
|
||
def send(self, msg): | ||
mysend(self.socket, msg) | ||
|
||
def recv(self): | ||
return myrecv(self.socket) | ||
|
||
def get_msgs(self): | ||
read, write, error = select.select([self.socket], [], [], 0) | ||
my_msg = '' | ||
peer_msg = [] | ||
#peer_code = M_UNDEF for json data, peer_code is redundant | ||
if len(self.console_input) > 0: | ||
my_msg = self.console_input.pop(0) | ||
if self.socket in read: | ||
peer_msg = self.recv() | ||
return my_msg, peer_msg | ||
|
||
def output(self): | ||
if len(self.system_msg) > 0: | ||
print(self.system_msg) | ||
self.system_msg = '' | ||
|
||
def login(self): | ||
my_msg, peer_msg = self.get_msgs() | ||
if len(my_msg) > 0: | ||
self.name = my_msg | ||
msg = json.dumps({"action":"login", "name":self.name}) | ||
self.send(msg) | ||
response = json.loads(self.recv()) | ||
if response["status"] == 'ok': | ||
self.state = S_LOGGEDIN | ||
self.sm.set_state(S_LOGGEDIN) | ||
self.sm.set_myname(self.name) | ||
self.print_instructions() | ||
return (True) | ||
elif response["status"] == 'duplicate': | ||
self.system_msg += 'Duplicate username, try again' | ||
return False | ||
else: # fix: dup is only one of the reasons | ||
return(False) | ||
|
||
|
||
def read_input(self): | ||
while True: | ||
text = sys.stdin.readline()[:-1] | ||
self.console_input.append(text) # no need for lock, append is thread safe | ||
|
||
def print_instructions(self): | ||
self.system_msg += menu | ||
|
||
def run_chat(self): | ||
self.init_chat() | ||
self.system_msg += 'Welcome to ICS chat\n' | ||
self.system_msg += 'Please enter your name: ' | ||
self.output() | ||
while self.login() != True: | ||
self.output() | ||
self.system_msg += 'Welcome, ' + self.get_name() + '!' | ||
self.output() | ||
while self.sm.get_state() != S_OFFLINE: | ||
self.proc() | ||
self.output() | ||
time.sleep(CHAT_WAIT) | ||
self.quit() | ||
|
||
#============================================================================== | ||
# main processing loop | ||
#============================================================================== | ||
def proc(self): | ||
my_msg, peer_msg = self.get_msgs() | ||
self.system_msg += self.sm.proc(my_msg, peer_msg) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
|
||
from chat_client_class import * | ||
|
||
def main(): | ||
import argparse | ||
parser = argparse.ArgumentParser(description='chat client argument') | ||
parser.add_argument('-d', type=str, default=None, help='server IP addr') | ||
args = parser.parse_args() | ||
|
||
client = Client(args) | ||
client.run_chat() | ||
|
||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
# -*- coding: utf-8 -*- | ||
""" | ||
Created on Sun Apr 5 09:58:31 2015 | ||
@author: zhengzhang | ||
""" | ||
S_ALONE = 0 | ||
S_TALKING = 1 | ||
|
||
#============================================================================== | ||
# Group class: | ||
# member fields: | ||
# - An array of items, each a Member class | ||
# - A dictionary that keeps who is a chat group | ||
# member functions: | ||
# - join: first time in | ||
# - leave: leave the system, and the group | ||
# - list_my_peers: who is in chatting with me? | ||
# - list_all: who is in the system, and the chat groups | ||
# - connect: connect to a peer in a chat group, and become part of the group | ||
# - disconnect: leave the chat group but stay in the system | ||
#============================================================================== | ||
|
||
class Group: | ||
|
||
def __init__(self): | ||
self.members = {} | ||
self.chat_grps = {} | ||
self.grp_ever = 0 | ||
|
||
def join(self, name): | ||
self.members[name] = S_ALONE | ||
return | ||
|
||
def is_member(self, name): | ||
return name in self.members.keys() | ||
|
||
def leave(self, name): | ||
self.disconnect(name) | ||
del self.members[name] | ||
return | ||
|
||
def find_group(self, name): | ||
found = False | ||
group_key = 0 | ||
for k in self.chat_grps.keys(): | ||
if name in self.chat_grps[k]: | ||
found = True | ||
group_key = k | ||
break | ||
return found, group_key | ||
|
||
def connect(self, me, peer): | ||
peer_in_group = False | ||
#if peer is in a group, join it | ||
peer_in_group, group_key = self.find_group(peer) | ||
if peer_in_group == True: | ||
print(peer, "is talking already, connect!") | ||
self.chat_grps[group_key].append(me) | ||
self.members[me] = S_TALKING | ||
else: | ||
# otherwise, create a new group | ||
print(peer, "is idle as well") | ||
self.grp_ever += 1 | ||
group_key = self.grp_ever | ||
self.chat_grps[group_key] = [] | ||
self.chat_grps[group_key].append(me) | ||
self.chat_grps[group_key].append(peer) | ||
self.members[me] = S_TALKING | ||
self.members[peer] = S_TALKING | ||
print(self.list_me(me)) | ||
return | ||
|
||
def disconnect(self, me): | ||
# find myself in the group, quit | ||
in_group, group_key = self.find_group(me) | ||
if in_group == True: | ||
self.chat_grps[group_key].remove(me) | ||
self.members[me] = S_ALONE | ||
# peer may be the only one left as well... | ||
if len(self.chat_grps[group_key]) == 1: | ||
peer = self.chat_grps[group_key].pop() | ||
self.members[peer] = S_ALONE | ||
del self.chat_grps[group_key] | ||
return | ||
|
||
def list_all(self, me): | ||
# a simple minded implementation | ||
full_list = "Users: ------------" + "\n" | ||
full_list += str(self.members) + "\n" | ||
full_list += "Groups: -----------" + "\n" | ||
full_list += str(self.chat_grps) + "\n" | ||
return full_list | ||
|
||
def list_all2(self, me): | ||
print("Users: ------------") | ||
print(self.members) | ||
print("Groups: -----------") | ||
print(self.chat_grps, "\n") | ||
member_list = str(self.members) | ||
grp_list = str(self.chat_grps) | ||
return member_list, grp_list | ||
|
||
def list_me(self, me): | ||
# return a list, "me" followed by other peers in my group | ||
if me in self.members.keys(): | ||
my_list = [] | ||
my_list.append(me) | ||
in_group, group_key = self.find_group(me) | ||
if in_group == True: | ||
for member in self.chat_grps[group_key]: | ||
if member != me: | ||
my_list.append(member) | ||
return my_list | ||
|
||
g = Group() |
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import socket | ||
import time | ||
|
||
# use local loop back address by default | ||
#CHAT_IP = '127.0.0.1' | ||
CHAT_IP = socket.gethostbyname(socket.gethostname()) | ||
CHAT_PORT = 1112 | ||
SERVER = (CHAT_IP, CHAT_PORT) | ||
|
||
menu = "\n++++ Choose one of the following commands\n \ | ||
time: calendar time in the system\n \ | ||
who: to find out who else are there\n \ | ||
c _peer_: to connect to the _peer_ and chat\n \ | ||
? _term_: to search your chat logs where _term_ appears\n \ | ||
p _#_: to get number <#> sonnet\n \ | ||
q: to leave the chat system\n\n" | ||
|
||
S_OFFLINE = 0 | ||
S_CONNECTED = 1 | ||
S_LOGGEDIN = 2 | ||
S_CHATTING = 3 | ||
|
||
SIZE_SPEC = 5 | ||
|
||
CHAT_WAIT = 0.2 | ||
|
||
def print_state(state): | ||
print('**** State *****::::: ') | ||
if state == S_OFFLINE: | ||
print('Offline') | ||
elif state == S_CONNECTED: | ||
print('Connected') | ||
elif state == S_LOGGEDIN: | ||
print('Logged in') | ||
elif state == S_CHATTING: | ||
print('Chatting') | ||
else: | ||
print('Error: wrong state') | ||
|
||
def mysend(s, msg): | ||
#append size to message and send it | ||
msg = ('0' * SIZE_SPEC + str(len(msg)))[-SIZE_SPEC:] + str(msg) | ||
msg = msg.encode() | ||
total_sent = 0 | ||
while total_sent < len(msg) : | ||
sent = s.send(msg[total_sent:]) | ||
if sent==0: | ||
print('server disconnected') | ||
break | ||
total_sent += sent | ||
|
||
def myrecv(s): | ||
#receive size first | ||
size = '' | ||
while len(size) < SIZE_SPEC: | ||
text = s.recv(SIZE_SPEC - len(size)).decode() | ||
if not text: | ||
print('disconnected') | ||
return('') | ||
size += text | ||
size = int(size) | ||
#now receive message | ||
msg = '' | ||
while len(msg) < size: | ||
text = s.recv(size-len(msg)).decode() | ||
if text == b'': | ||
print('disconnected') | ||
break | ||
msg += text | ||
#print ('received '+message) | ||
return (msg) | ||
|
||
def text_proc(text, user): | ||
ctime = time.strftime('%d.%m.%y,%H:%M', time.localtime()) | ||
return('(' + ctime + ') ' + user + ' : ' + text) # message goes directly to screen | ||
|
Oops, something went wrong.