testserver.py :  » Development » Lyntin » lyntin-4.2 » tools » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Development » Lyntin 
Lyntin » lyntin 4.2 » tools » testserver.py
#!/usr/bin/env python
#######################################################################
# This file is part of Lyntin.
# copyright (c) Free Software Foundation 2001
#
# Lyntin is distributed under the GNU General Public License license.  See the
# file LICENSE for distribution details.
# $Id: testserver.py,v 1.2 2005/01/07 14:50:40 glasssnake Exp $
#######################################################################
"""
This new test-server is a patchwork of stuff from the existing test server
and code I wrote for the Varium mud server way back when.  It is actually
a functional mini-mud now.
"""
import socket, sys, Queue, select, string
import connection, toolsutils
from toolsutils import wrap_text

my_world = None

class Event:
  def __init__(self):
    pass

  def execute(self, world):
    pass

  def __str__(self):
    return ""

class InputEvent(Event):
  def __init__(self, conn, input):
    self._conn = conn
    self._input = input

  def __str__(self):
    return '"%s" for "%s"' % (self._input, str(self._conn))

  def execute(self, world):
    self._conn.handleInput(world, self._input)

class HeartbeatEvent(Event):
  def __init__(self, source):
    self._source = source

  def execute(self, world):
    self._source.heartbeat(world)

class NPC:
  def __init__(self, world):
    self._world = world
    self._name = "Joe"
    self._desc = "A regular looking NPC."

    from random import Random
    self._random = Random()

  def blab(self):
    self._world.spamroom(self._name + " looks fidgety.\n")

  def heartbeat(self, world):
    pass

class Neil(NPC):
  def __init__(self, world):
    NPC.__init__(self, world)
    self._name = "Neil"
    self._desc = "Neil is the bartender at this little mini-tavern."

  def heartbeat(self, world):
    g = (self._random.random() * 10)
    if (g < 2):
      self._world.spamroom(self._name + " flicks a bug off his bar.\n")
    elif (g < 4):
      self._world.spamroom(self._name + " scrubs some glasses with his dishrag.\n")
    elif (g < 5):
      self._world.spamroom(self._name + " says, \"Mighty fine morning, isn't it?\"\n")


class World:
  def __init__(self, options):
    self._event_queue = Queue.Queue(0)
    self._worker = None
    self._options = options
    self._ms = None

    temp = ("Welcome to Neil's Pub--a small tavern of unusual candor.  " +
            "In many ways, this is a dream come true for Neil and it shows " +
            "in the care he gives to the place.  The tavern is both " +
            "infinitely large and terribly small.  There are no exits.  " +
            "Only a long bar and a series of barstools for folks to show " +
            "up, take a load off, and socialize.")

    self._desc = wrap_text(temp, 70, 0, 0)
    self._npcs = []

    self._npcs.append(Neil(self))

  def enqueue(self, ev):
    self._event_queue.put(ev)

  def startup(self):
    from threading import currentThread
    self._worker = currentThread()

    # launch the server
    self._ms = MasterServer(self, self._options)
    self._ms.startup()

    do_heartbeat = self._options["heartbeat"]
    beat = 0

    # this is our main loop thingy!
    while 1:
      if do_heartbeat == "yes":
        beat += 1
        if beat % 30 == 0:
          beat = 0
          self.heartbeat()

      self._ms.networkLoop()

      if not self._event_queue.empty():
        event = self._event_queue.get(0)
        es = str(event)
        if es:
          print "handling: '%s'" % es

        try:
          event.execute(self)
        except Exception, e:
          print "exception: %s" % e

          if hasattr(event, 'conn'):
            try:
              conn.write("exception: %s" % e)
            except: pass

      
  def heartbeat(self):
    # we don't do heartbeats when no one is connected.
    if len(self._ms._conns) > 1:
      for mem in self._npcs:
        self.enqueue(HeartbeatEvent(mem))

  def disconnect(self, conn):
    if conn in self._ms._conns:
      self._ms._conns.remove(conn)
    if hasattr(conn, '_name'):
      self.spamroom("%s has left the game.\n" % conn._name)
    print "Goodbye %s" % str(conn)

  def look(self, conn, item):
    if item:
      for mem in self._npcs:
        if item == mem._name.lower():
          return mem._desc + "\n"

      for mem in self._ms._conns:
        if item == mem._name.lower():
          return mem._desc + "\n"

    else:
      out = self._desc + "\n\n"
      names = map(lambda x:x._name, self._ms._conns)
      for mem in self._npcs:
        names.append(mem._name)
      out += testutils.wrap_text(string.join(names, ', '), 70, 0, 0)
      out += "\n"

      return out

    return "That does not exist.\n"

  def spamroom(self, data):
    # note--we only spam real connections--not npcs
    for mem in self._ms._conns:
      try: mem.write(data)
      except: pass

  def shutdown(self):
    if self._ms:
      self._ms.closedown()
    print "Shutting down."


class MasterServer:
  def __init__(self, world, options):
    self._args = args
    self._master = None
    self._conns = []
    self._shutdown = 0
    self._options = options
    self._world = world

  def startup(self):
    host = self._options["host"]
    port = int(self._options["port"])
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((host, port))
    s.listen(1)

    print "Test server starting up: %s:%d" % (host, port)
    self._master = connection.Connection(self._world, s, "MASTER")
    self._master._name = "Igor"
    self._master._desc = "A very busy old man."

    self._conns = []
    self._conns.append(self._master)

  def networkLoop(self):
    fi = []

    fns = map(lambda x:x.sockid(), self._conns)
    fi = select.select(fns, [], [], .1)[0]
    allconns = filter(lambda x,y=fi:x.sockid() in y, self._conns)

    for conn in allconns:
      if conn._addr == "MASTER":
        newsock, newaddr = conn._sock.accept()
        newconn = connection.Connection(self._world, newsock, newaddr)
        newconn.write("Welcome to Neil's Pub!  Type \"help\" if you're lost.\n")

        self._conns.append(newconn)

      else:
        try: new_data = conn._sock.recv(1024) 
        except Exception, e:
          print "exception: %s" % e
          if conn in self._conns:
            self._conns.remove(conn)
          conn.killConn()
          continue

        if new_data:
          conn.handleNetworkData(new_data)
        else:
          if conn in self._conns:
            self._conns.remove(conn)
          conn.killConn()

  def closedown(self):
    try: self._master.sockid().close()
    except Exception, e: print "closing down master socket: '%s'" % e
    for mem in self._conns:
      if mem._addr == "MASTER":
        continue
      try:
        mem.write("Server shutting down.\n")
        mem.killConn()
      except:
        pass


def print_syntax(message=""):
  print "testserver.py [--help] [options]"
  print "    -h|--host <hostname> - sets the hostname to bind to"
  print "    -p|--port <port>     - sets the port to bind to"
  print "    --heartbeat <yes|no> - sets whether or not to execute heartbeats"
  print
  if message:
    print message

if __name__ == '__main__':
  import testserver, signal

  # parse out arguments
  args = sys.argv[1:]
  i = 0
  optlist = []
  while (i < len(args)):

    if args[i][0] == "-":
      if (i+1 < len(args)):
        if args[i+1][0] != "-":
          optlist.append((args[i], args[i+1]))
          i = i + 1
        else:
          optlist.append((args[i], ""))
      else:
        optlist.append((args[i], ""))

    else:
      optlist.append(("", args[i]))

    i = i + 1

  options = {"host": "localhost", "port": "3000", "heartbeat":"yes"}
  print "Handling arguments."
  for mem in optlist:
    if mem[0] == "--host" or mem[0] == "-h":
      if mem[1]:
        options["host"] = mem[1]
      else:
        print_syntax("error: Host was not specified.")
        sys.exit(1)

    elif mem[0] == "--help":
      print_syntax()
      sys.exit(1)

    elif mem[0] == "--port" or mem[0] == "-p":
      if mem[1] and mem[1].isdigit():
        options["port"] = mem[1]
      else:
        print_syntax("error: Port needs to be a number.")
        sys.exit(1)

    elif mem[0] == "--heartbeat":
      if mem[1].lower() == "yes" or mem[1].lower() == "no":
        options["heartbeat"] = mem[1].lower()
      else:
        print_syntax("error: Valid heartbeat settings are 'yes' or 'no'.")
        sys.exit(1)

  print "Host: %s" % options["host"]
  print "Port: %s" % options["port"]

  # create the world
  testserver.my_world = World(options)
  try:
    testserver.my_world.startup()
  except Exception, e:
    print "Outer loop exception: %s" % e
  testserver.my_world.shutdown()

# Local variables:
# mode:python
# py-indent-offset:2
# tab-width:2
# End:
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.