123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- """
- Echo server for test purposes.
- This is usually invoked by starting this module as a script:
- :command:`python -m Pyro4.test.echoserver`
- or simply: :command:`pyro4-test-echoserver`
- It is also possible to use the :class:`EchoServer` in user code
- but that is not terribly useful.
- Pyro - Python Remote Objects. Copyright by Irmen de Jong (irmen@razorvine.net).
- """
- from __future__ import print_function
- import sys
- import os
- import time
- import warnings
- import threading
- from optparse import OptionParser
- from Pyro4 import core, naming
- from Pyro4.configuration import config
- __all__ = ["EchoServer"]
- @core.expose
- class EchoServer(object):
- """
- The echo server object that is provided as a Pyro object by this module.
- If its :attr:`verbose` attribute is set to ``True``, it will print messages as it receives calls.
- """
- _verbose = False
- _must_shutdown = False
- def echo(self, message):
- """return the message"""
- if self._verbose:
- message_str = repr(message).encode(sys.stdout.encoding, errors="replace").decode(sys.stdout.encoding)
- print("%s - echo: %s" % (time.asctime(), message_str))
- return message
- def error(self):
- """generates a simple exception without text"""
- if self._verbose:
- print("%s - error: generating exception" % time.asctime())
- raise ValueError("expected error from echoserver error() method")
- def error_with_text(self):
- """generates a simple exception with message"""
- if self._verbose:
- print("%s - error: generating exception" % time.asctime())
- raise ValueError("the message of the error")
- @core.oneway
- def oneway_echo(self, message):
- """just like echo, but oneway; the client won't wait for response"""
- if self._verbose:
- message_str = repr(message).encode(sys.stdout.encoding, errors="replace").decode(sys.stdout.encoding)
- print("%s - oneway_echo: %s" % (time.asctime(), message_str))
- return "bogus return value"
- def slow(self):
- """returns (and prints) a message after a certain delay"""
- if self._verbose:
- print("%s - slow: waiting a bit..." % time.asctime())
- time.sleep(5)
- if self._verbose:
- print("%s - slow: returning result" % time.asctime())
- return "Finally, an answer!"
- def generator(self):
- """a generator function that returns some elements on demand"""
- yield "one"
- yield "two"
- yield "three"
- def nan(self):
- return float("nan")
- def inf(self):
- return float("inf")
- @core.oneway
- def oneway_slow(self):
- """prints a message after a certain delay, and returns; but the client won't wait for it"""
- if self._verbose:
- print("%s - oneway_slow: waiting a bit..." % time.asctime())
- time.sleep(5)
- if self._verbose:
- print("%s - oneway_slow: returning result" % time.asctime())
- return "bogus return value"
- def _private(self):
- """a 'private' method that should not be accessible"""
- return "should not be allowed"
- def __private(self):
- """another 'private' method that should not be accessible"""
- return "should not be allowed"
- def __dunder__(self):
- """a double underscore method that should be accessible normally"""
- return "should be allowed (dunder)"
- def shutdown(self):
- """called to signal the echo server to shut down"""
- if self._verbose:
- print("%s - shutting down" % time.asctime())
- self._must_shutdown = True
- @property
- def verbose(self):
- return self._verbose
- @verbose.setter
- def verbose(self, onoff):
- self._verbose = bool(onoff)
- class NameServer(threading.Thread):
- def __init__(self, hostname, hmac=None):
- super(NameServer, self).__init__()
- self.setDaemon(1)
- self.hostname = hostname
- self.hmac = hmac
- self.started = threading.Event()
- def run(self):
- self.uri, self.ns_daemon, self.bc_server = naming.startNS(self.hostname, hmac=self.hmac)
- self.started.set()
- if self.bc_server:
- self.bc_server.runInThread()
- self.ns_daemon.requestLoop()
- def startNameServer(host, hmac=None):
- ns = NameServer(host, hmac=hmac)
- ns.start()
- ns.started.wait()
- return ns
- def main(args=None, returnWithoutLooping=False):
- parser = OptionParser()
- parser.add_option("-H", "--host", default="localhost", help="hostname to bind server on (default=%default)")
- parser.add_option("-p", "--port", type="int", default=0, help="port to bind server on")
- parser.add_option("-u", "--unixsocket", help="Unix domain socket name to bind server on")
- parser.add_option("-n", "--naming", action="store_true", default=False, help="register with nameserver")
- parser.add_option("-N", "--nameserver", action="store_true", default=False, help="also start a nameserver")
- parser.add_option("-v", "--verbose", action="store_true", default=False, help="verbose output")
- parser.add_option("-q", "--quiet", action="store_true", default=False, help="don't output anything")
- parser.add_option("-k", "--key", help="the HMAC key to use (deprecated)")
- options, args = parser.parse_args(args)
- if options.key:
- warnings.warn("using -k to supply HMAC key on the command line is a security problem "
- "and is deprecated since Pyro 4.72. See the documentation for an alternative.")
- if "PYRO_HMAC_KEY" in os.environ:
- if options.key:
- raise SystemExit("error: don't use -k and PYRO_HMAC_KEY at the same time")
- options.key = os.environ["PYRO_HMAC_KEY"]
- if options.verbose:
- options.quiet = False
- if not options.quiet:
- print("Starting Pyro's built-in test echo server.")
- config.SERVERTYPE = "multiplex"
- hmac = (options.key or "").encode("utf-8")
- if not hmac and not options.quiet:
- print("Warning: HMAC key not set. Anyone can connect to this server!")
- nameserver = None
- if options.nameserver:
- options.naming = True
- nameserver = startNameServer(options.host, hmac=hmac)
- d = core.Daemon(host=options.host, port=options.port, unixsocket=options.unixsocket)
- if hmac:
- d._pyroHmacKey = hmac
- echo = EchoServer()
- echo._verbose = options.verbose
- objectName = "test.echoserver"
- uri = d.register(echo, objectName)
- if options.naming:
- host, port = None, None
- if nameserver is not None:
- host, port = nameserver.uri.host, nameserver.uri.port
- ns = naming.locateNS(host, port, hmac_key=hmac)
- ns.register(objectName, uri)
- if options.verbose:
- print("using name server at %s" % ns._pyroUri)
- if nameserver is not None:
- if nameserver.bc_server:
- print("broadcast server running at %s" % nameserver.bc_server.locationStr)
- else:
- print("not using a broadcast server")
- else:
- if options.verbose:
- print("not using a name server.")
- if not options.quiet:
- print("object name: %s" % objectName)
- print("echo uri: %s" % uri)
- print("echoserver running.")
- if returnWithoutLooping:
- return d, echo, uri # for unit testing
- else:
- d.requestLoop(loopCondition=lambda: not echo._must_shutdown)
- d.close()
- if __name__ == "__main__":
- main()
|