Permalink
Browse files

Implemented /osh/web/user JS console for GraphTerm

  • Loading branch information...
1 parent 2204894 commit e5c46d939a6502cce208f9c87eb3639c419710b6 @mitotic committed Sep 26, 2012
Showing with 83 additions and 7 deletions.
  1. +5 −3 graphterm/gtermhost.py
  2. +53 −3 graphterm/gtermserver.py
  3. +25 −1 graphterm/www/graphterm.js
View
8 graphterm/gtermhost.py
@@ -631,8 +631,8 @@ def gterm_shutdown_aux():
Host_connections = {}
def gterm_connect(host_name, server_addr, server_port=DEFAULT_HOST_PORT, connect_kw={},
oshell_globals=None, oshell_thread=False, oshell_unsafe=False, oshell_workdir="",
- oshell_init="", oshell_db_interface=None, oshell_hold_wrapper=None,
- oshell_no_input=True, gterm_callback=None, io_loop=None):
+ oshell_init="", oshell_db_interface=None, oshell_web_interface=None,
+ oshell_hold_wrapper=None, oshell_no_input=True, gterm_callback=None, io_loop=None):
""" Returns (host_connection, host_secret, trace_shell)
If io_loop is provided, it is assumed that the caller controls io_loop. Otherwise, gterm_connect
starts io_loop on a separate thread.
@@ -675,7 +675,9 @@ def gterm_connect(host_name, server_addr, server_port=DEFAULT_HOST_PORT, connect
allow_unsafe=oshell_unsafe, work_dir=oshell_workdir,
add_env={"GRAPHTERM_COOKIE": host_connection.osh_cookie,
"GRAPHTERM_SHARED_SECRET": host_secret},
- init_file=oshell_init, db_interface=oshell_db_interface,
+ init_file=oshell_init,
+ db_interface=oshell_db_interface,
+ web_interface=oshell_web_interface,
hold_wrapper=oshell_hold_wrapper,
no_input=oshell_no_input,
eventloop_callback=io_loop.add_callback)
View
56 graphterm/gtermserver.py
@@ -378,7 +378,7 @@ def open(self):
self.oshell = (term_name == gtermhost.OSHELL_NAME)
self._counter[0] += 1
- self.websocket_id = self._counter[0]
+ self.websocket_id = str(self._counter[0])
if "?" in path or "*" in path or "[" in path:
self.wildcard = re.compile("^"+path.replace("+", "\\+").replace(".", "\\.").replace("?", ".?").replace("*", ".*")+"$")
@@ -504,7 +504,13 @@ def on_message(self, message):
req_list = []
try:
for msg in msg_list:
- if msg[0] == "reconnect_host":
+ if msg[0] == "osh_stdout":
+ TraceInterface.receive_output("stdout", from_user or self.websocket_id, msg[1])
+
+ elif msg[0] == "osh_stderr":
+ TraceInterface.receive_output("stderr", from_user or self.websocket_id, msg[1])
+
+ elif msg[0] == "reconnect_host":
if conn:
# Close host connection (should automatically reconnect)
conn.on_close()
@@ -581,6 +587,48 @@ def updates_callback(self, feed_data):
self.write_json([["updates_response", feed_list]])
logging.warning(feed_data["feed"]["title"])
+# OTrace websocket interface
+class TraceInterface(object):
+ root_depth = 1 # Max. path components for web directory (below /osh/web)
+ trace_hook = None
+
+ @classmethod
+ def set_web_hook(cls, hook):
+ cls.trace_hook = hook
+
+ @classmethod
+ def get_root_tree(cls):
+ """Returns directory dict tree (with depth=root_depth) that is updated automatically"""
+ return GTSocket._all_users or GTSocket._all_websockets
+
+ @classmethod
+ def send_command(cls, path_comps, command):
+ """ Send command to browser via websocket (invoked in the otrace thread)
+ path_comps: path component array (first element identifies websocket)
+ command: Javascript expression to be executed on the browser
+ """
+ # Must be thread-safe
+ if GTSocket._all_users:
+ websocket_id = GTSocket._all_users.get(path_comps[0])
+ else:
+ websocket_id = path_comps[0]
+ websocket = GTSocket._all_websockets.get(websocket_id)
+ if not websocket:
+ cls.receive_output("stderr", "", "No such socket: %s" % path_comps[0])
+ return
+
+ # Schedules callback in event loop
+ tornado.ioloop.IOLoop.instance().add_callback(functools.partial(websocket.write_message,
+ json.dumps([["osh_stdin", command]])))
+
+ @classmethod
+ def receive_output(cls, channel, username, message):
+ """Receive channel="stdout"/"stderr" output from browser via websocket and forward to oshell
+ """
+ path_comps = [username] if username else []
+ cls.trace_hook(channel, path_comps, message)
+
+
def xterm(command="", name=None, host="localhost", port=gtermhost.DEFAULT_HTTP_PORT):
"""Create new terminal"""
pass
@@ -1036,7 +1084,9 @@ def get(self):
"widget_port":
(gtermhost.DEFAULT_HTTP_PORT-2 if options.widgets else 0)},
oshell_globals=oshell_globals,
- oshell_unsafe=True, oshell_no_input=(not options.oshell_input),
+ oshell_unsafe=True,
+ oshell_no_input=(not options.oshell_input),
+ oshell_web_interface=TraceInterface,
io_loop=IO_loop)
xterm = Local_client.xterm
killterm = Local_client.remove_term
View
26 graphterm/www/graphterm.js
@@ -32,6 +32,8 @@ var WRITE_LOG = function (str) {};
var DEBUG_LOG = function (str) {};
var DEBUG_LOG = function (str) {console.log(str)};
+var OSH_ECHO = true;
+
var ELLIPSIS = "...";
var gRowHeight = 16;
@@ -611,7 +613,29 @@ GTWebSocket.prototype.onmessage = function(evt) {
var command = payload_obj[j];
var action = command[0];
- if (action == "abort") {
+ if (action == "osh_stdin") {
+ // Execute JS "command" from otrace console
+ var stdout = "";
+ var stderr = "";
+ try {
+ if (OSH_ECHO)
+ console.log(command[1]);
+ var evalout = eval(command[1]);
+ stdout = evalout ? evalout+"" : "";
+ if (OSH_ECHO && stdout)
+ console.log(stdout);
+ } catch (err) {
+ stderr = err+"";
+ if (OSH_ECHO && stderr)
+ console.log(stderr);
+ }
+ var osh_send = [];
+ if (stderr)
+ osh_send.push(["osh_stderr", stderr]);
+ osh_send.push(["osh_stdout", stdout]);
+ gWebSocket.write(osh_send);
+
+ } else if (action == "abort") {
alert(command[1]);
window.location = "/";

0 comments on commit e5c46d9

Please sign in to comment.