Skip to content

Instantly share code, notes, and snippets.

@mrjoes
Last active August 29, 2015 14:08
Show Gist options
  • Select an option

  • Save mrjoes/749e61191627c2d89081 to your computer and use it in GitHub Desktop.

Select an option

Save mrjoes/749e61191627c2d89081 to your computer and use it in GitHub Desktop.
import socket
import select
import sys
# Start this server locally as follows
# python server.py 127.0.0.1 4444 1
BACKLOG = 1
def cmd_help(user, msg):
user.send('Commands:\n')
for cmd in all_commands:
user.send(' %s\n' % cmd)
def cmd_say(user, msg):
room = user.room
if room:
user.room.broadcast('%s said %s\n' % (user.name, msg), ignore=user)
user.send('You said %s\n' % msg)
def cmd_look(user, msg):
user.send_room_description(user.room)
all_commands = {
'help': cmd_help,
'say': cmd_say,
'look': cmd_look
}
class User(object):
def __init__(self, sock):
self.sock = sock
self.room = None
# TODO: Read line
self.name = sock.recv(4096).strip()
self.send('Welcome %s!\n' % self.name)
self.move_to(entry)
self.send_prompt()
self.broadcast('%s connected.\n' % self.name)
def got_stuff(self):
try:
data = self.sock.recv(4096)
except:
disconnect(self.sock)
return
if not data:
disconnect(self.sock)
self.handle_command(data.strip())
# Logic
def handle_command(self, msg):
command = msg.split(' ', 1)
rest = None
if len(command) > 1:
command, rest = command
else:
command = command[0]
if not command:
return
handler = all_commands.get(command)
if handler:
handler(self, rest)
else:
direction = self.room.get_exit(command)
if direction:
self.move_to(direction)
else:
self.send('Huh?\n')
self.send_prompt()
def move_to(self, room):
if self.room:
self.room.remove_user(self)
self.room = room
self.room.add_user(self)
self.send_room_description(room)
# Helpers
def send_prompt(self):
self.send('> ');
def send_room_description(self, room):
self.send('%s\n\n' % room.description)
if room.participants:
users = [u for u in room.participants if u is not self]
if users:
if len(users) > 1:
self.send('%s are here.\n' % ', '.join(u.name for u in room.participants))
else:
self.send('%s is here.\n' % users[0].name)
else:
self.send('There\'s no one else here.\n')
self.send('\nExits:\n')
for side, room in room.exits.iteritems():
self.send(' %s leads to %s\n' % (side, room.name))
# Networking
def send(self, msg):
try:
self.sock.send(msg)
except:
disconnect(self.sock)
def notify(self, msg):
self.send('\n%s' % msg)
self.send_prompt()
def broadcast(self, msg, ignore=None):
for user in all_users.itervalues():
if user is not ignore:
user.notify(msg)
def close(self):
if self.room:
self.room.remove_user(self)
class Room(object):
def __init__(self, name, description):
self.name = name
self.description = description
self.participants = set()
self.exits = {}
# API
def add_user(self, user):
self.broadcast('%s entered room.\n' % user.name)
self.participants.add(user)
def remove_user(self, user):
if user in self.participants:
self.participants.remove(user)
self.broadcast('%s left room.\n' % user.name)
def add_exit(self, side, room):
self.exits[side] = room
def get_exit(self, side):
return self.exits.get(side)
# Networking
def broadcast(self, msg, ignore=None):
for u in self.participants:
if u is not ignore:
u.notify(msg)
# Global State
all_users = {}
entry = Room('Portal room', 'You\'re in a small portal room. Welcome to the dungeon. Type `help` to get list of commands.')
connections = []
# Game
def create_world():
# Garden
garden = Room('Garden', 'Garden. Very pretty. Butterflies, grass, cows.')
entry.add_exit('left', garden)
garden.add_exit('right', entry)
# Factory
factory = Room('Factory', 'Factory.\nLots of weird mechanisms and it is quite noisy here.')
entry.add_exit('right', factory)
factory.add_exit('back', entry)
def disconnect(sock):
sock.close()
if sock in connections:
connections.remove(sock)
if sock in all_users:
all_users[sock].close()
def serve(address, port, timeout=None, backlog=None):
# Create a TCP/IP socket
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind the socket to the port
server_address = (address, port)
print >>sys.stderr, 'Starting up on %s port %s' % server_address
server_sock.bind(server_address)
# Listen for incoming connections
server_sock.listen(backlog)
connections.append(server_sock)
while True:
readable, _, exceptional = select.select(connections, [], connections)
# Handle events
for s in readable:
if s is server_sock:
sock, addr = s.accept()
connections.append(sock)
sock.send('Enter your name: ')
else:
user = all_users.get(s)
if user is not None:
all_users[s].got_stuff()
else:
all_users[s] = User(s)
# Handle disconnects
for s in exceptional:
disconnect(s)
if __name__ == '__main__':
address = sys.argv[1]
port = int(sys.argv[2])
timeout = float(sys.argv[3])
backlog = int(sys.argv[4]) if len(sys.argv) > 4 else BACKLOG
create_world()
serve(address, port, timeout=timeout, backlog=backlog)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment