1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
#!/usr/bin/env python
import os
import signal
from StringIO import StringIO
from subprocess import Popen, PIPE
from circuits.io import File
from circuits.tools import inspect
from circuits.net.events import write
from circuits.web.events import stream
from circuits import handler, Event, Component
from circuits.web import Server, Controller, Logger, Static, Sessions
BUFFERING = 1
STREAMING = 2
class kill(Event):
"""kill Event"""
class input(Event):
"""input Event"""
class Command(Component):
channel = "cmd"
def __init__(self, request, response, command, channel=channel):
super(Command, self).__init__(channel=channel)
self._request = request
self._response = response
self._command = command
self._state = BUFFERING
self._buffer = None
self._p = Popen(
command, shell=True, stdout=PIPE, stderr=PIPE,
close_fds=True, preexec_fn=os.setsid
)
self._stdin = None
if self._p.stdin is not None:
self._stdin = File(self._p.stdin, channel="%s.stdin" % channel)
self._stdin.register(self)
self._stdout = File(self._p.stdout, channel="%s.stdout" % channel)
self.addHandler(
handler("eof", channel="%s.stdout" % channel)(self._on_stdout_eof)
)
self.addHandler(
handler("read", channel="%s.stdout" % channel)(
self._on_stdout_read
)
)
self._stdout.register(self)
@handler("disconnect", channel="web")
def disconnect(self, sock):
if sock == self._request.sock:
self.fire(kill(), self)
@handler("response", channel="web", priority=-1)
def response(self, response):
if response == self._response:
self._state = STREAMING
def kill(self):
os.killpg(self._p.pid, signal.SIGINT)
self.unregister()
def input(self, data):
if self._stdin is not None:
self.fire(write(data), self._stdin)
@staticmethod
def _on_stdout_eof(self):
if self._buffer is not None:
self._buffer.flush()
data = self._buffer.getvalue()
self.fire(stream(self._response, data), "web")
self.fire(stream(self._response, None), "web")
self.fire(kill())
@staticmethod
def _on_stdout_read(self, data):
if self._state == BUFFERING:
if self._buffer is None:
self._buffer = StringIO()
self._buffer.write(data)
elif self._state == STREAMING:
if self._buffer is not None:
self._buffer.write(data)
self._buffer.flush()
data = self._buffer.getvalue()
self._buffer = None
self.fire(stream(self._response, data), "web")
else:
self.fire(stream(self._response, data), "web")
class Root(Controller):
def GET(self, *args, **kwargs):
self.expires(60 * 60 * 24 * 30)
return self.serve_file(os.path.abspath("static/index.xhtml"))
def POST(self, input=None):
if not input:
return ""
self.response.headers["Content-Type"] = "text/plain"
if input.strip() == "inspect":
return inspect(self)
self.response.stream = True
sid = self.request.sid
self += Command(self.request, self.response, input, channel=sid)
return self.response
from circuits import Debugger
app = Server(("0.0.0.0", 8000))
Debugger().register(app)
Static("/js", docroot="static/js").register(app)
Static("/css", docroot="static/css").register(app)
Sessions().register(app)
Logger().register(app)
Root().register(app)
app.run()
|