Here is an implementation using circuits:
server.py:
#!/usr/bin/env python
from uuid import uuid4 as uuid
from subprocess import Popen, PIPE
from circuits import handler, Component, Debugger, Event
from circuits.io import File
from circuits.net.sockets import TCPServer
from circuits.net.events import close, write
class kill(Event):
"""kill Event"""
class Command(Component):
channel = "cmd"
def __init__(self, sock, command, channel=channel):
super(Command, self).__init__(channel=channel)
self._sock = sock
self._command = command
self._buffer = None
self._p = Popen(command, shell=True, stdin=PIPE, stdout=PIPE)
self._stdin = File(
self._p.stdin, channel="{0:s}.stdin".format(self.channel)
).register(self)
self._stdout = File(
self._p.stdout, channel="{0:s}.stdout".format(self.channel)
).register(self)
self.addHandler(
handler("eof", channel=self._stdout.channel)(self._on_stdout_eof)
)
self.addHandler(
handler("read", channel=self._stdout.channel)(self._on_stdout_read)
)
def write(self, data):
self.fire(write(data), self._stdin.channel)
def kill(self):
self._p.terminate()
self.unregister()
@staticmethod
def _on_stdout_eof(self):
self.fire(kill(), self.channel)
self.fire(close(self._sock), self.parent.channel)
@staticmethod
def _on_stdout_read(self, data):
self.fire(write(self._sock, data), "server")
class Server(Component):
channel = "server"
def init(self, bind, cmd):
self.cmd = cmd
self.clients = {}
TCPServer(bind).register(self)
def connect(self, sock, host, port):
command = Command(sock, self.cmd, channel=uuid()).register(self)
self.clients[sock] = command
def disconnect(self, sock):
command = self.clients[sock]
self.fire(kill(), command.channel)
del self.clients[sock]
def read(self, sock, data):
command = self.clients[sock]
self.fire(write(data), command.channel)
server = Server(("0.0.0.0", 8000), "python app.py")
Debugger().register(server)
server.run()
app.py:
#!/usr/bin/env python
from __future__ import print_function
import sys
def function1():
print("I am function 1!")
def function2():
print("I am function 2!")
def function3():
raise SystemExit(0)
MENU_OPTIONS = (
(1, "Function 1"),
(2, "Function 2"),
(3, "Function 3")
)
FUNCTIONS = {
1: function1,
2: function2,
3: function3
}
def main():
while True:
try:
print("Menu:")
for option, description in MENU_OPTIONS:
print("{0:d}) {1:s}".format(option, description))
print()
sys.stdout.flush()
choice = raw_input("> ")
try:
FUNCTIONS[int(choice)]()
except ValueError:
print("Invalid Input")
except (KeyboardInterrupt, EOFError):
raise SystemExit(0)
if __name__ == "__main__":
main()
For an example session (this example has been thoroughly tested):
Have fun! :)
Note: I'm actually the developer/author of 1[circuits]. I thought this would be a nice example to write up.