[Sciviews-commits] r353 - in komodo/SciViews-K: components content/js

noreply at r-forge.r-project.org noreply at r-forge.r-project.org
Wed Feb 16 15:50:38 CET 2011


Author: prezez
Date: 2011-02-16 15:50:38 +0100 (Wed, 16 Feb 2011)
New Revision: 353

Modified:
   komodo/SciViews-K/components/svIUtils.idl
   komodo/SciViews-K/components/svUtils.py
   komodo/SciViews-K/content/js/r_new.js
Log:
More additions to svUtils XPCOM interface and new methods in the 'sv.rnew' object (socket server)


Modified: komodo/SciViews-K/components/svIUtils.idl
===================================================================
--- komodo/SciViews-K/components/svIUtils.idl	2011-02-14 21:53:06 UTC (rev 352)
+++ komodo/SciViews-K/components/svIUtils.idl	2011-02-16 14:50:38 UTC (rev 353)
@@ -34,11 +34,22 @@
 #include "nsISupports.idl"
 #include "nsISimpleEnumerator.idl"
 
+// This is implemented in sv.rnew's JavaScript code.
+[scriptable, uuid(ca1bcf00-394d-11e0-bd69-0002a5d5c51b)]
+interface svIStuffListener: nsISupports {
+    wstring onStuff(in wstring data);
+};
+
 [scriptable, uuid(5f82d460-37b6-11e0-b897-0002a5d5c51b)]
 interface svIUtils : nsISupports {
+	wstring execFun(in svIStuffListener stuffLlistener);
+	void execFunInBgr(in svIStuffListener requestHandler);
     nsISimpleEnumerator getproc(in string propertyName);
-	string	execInR(in wstring command, in string host, in long port);
-	void	execInRBgr(in wstring command, in string host, in long port);
+	wstring	execInR(in wstring command, in string host, in long port, in string mode);
+	void	execInRBgr(in wstring command, in string host, in long port, in string mode);
+	boolean startSocketServer(in string host, in long port, in svIStuffListener requestHandler);
+	void stopSocketServer();
 	attribute wstring lastCommand;
 	attribute wstring lastResult;
+	attribute wstring id;
 };

Modified: komodo/SciViews-K/components/svUtils.py
===================================================================
--- komodo/SciViews-K/components/svUtils.py	2011-02-14 21:53:06 UTC (rev 352)
+++ komodo/SciViews-K/components/svUtils.py	2011-02-16 14:50:38 UTC (rev 353)
@@ -35,19 +35,16 @@
 from xpcom import components, nsError, COMException
 from xpcom._xpcom import getProxyForObject, PROXY_SYNC, PROXY_ALWAYS, PROXY_ASYNC
 import os, sys, re
-#import tempfile
 import string
-#import process
-#import koprocessutils
 from xpcom.server.enumerator import SimpleEnumerator
 import socket
-#from threading import Thread
 import threading
-
-
 import logging
 log = logging.getLogger('svUtils')
+#log.setLevel(logging.INFO)
+log.setLevel(logging.DEBUG)
 
+
 class svUtils:
 	_com_interfaces_ = [components.interfaces.svIUtils]
 	_reg_desc_ = "SciViews-K utilities"
@@ -64,8 +61,31 @@
 
 		self.lastCommand = u''
 		self.lastResult = u''
+		self.id = 'svpy'
+		self.runServer = False
+		self.serverIsUp = False
 		pass
 
+
+	def execFun(self, stuffLlistener):
+		listenerProxy = getProxyForObject(1,
+			components.interfaces.svIStuffListener,
+			stuffLlistener, PROXY_ALWAYS | PROXY_SYNC)
+		ret = listenerProxy.onStuff("test 123")
+		return ret
+
+	def execFunInBgr(self, requestHandler):
+		t = threading.Thread(target=self._doExecFn, kwargs={
+			'requestHandler': requestHandler
+			})
+		t.start()
+
+	def _doExecFn(self, requestHandler):
+		listenerProxy = getProxyForObject(1,
+			components.interfaces.svIStuffListener,
+			requestHandler, PROXY_ALWAYS | PROXY_SYNC)
+		listenerProxy.onStuff("test 12345...")
+
 	def _asSString(self, s):
 		ret = components.classes["@mozilla.org/supports-string;1"] \
 			.createInstance(components.interfaces.nsISupportsString)
@@ -74,7 +94,7 @@
 
 	def getproc(self, propertyName):
 #		TODO: error handling here
-#		TODO: checking for correct propertyName
+#		TODO: checking for correct propertyName, return several properties at a time
 		ret = []
 		if sys.platform.startswith('win'):
 			from win32com.client import GetObject
@@ -83,10 +103,6 @@
 				' from Win32_Process where Name="Rgui.exe" or Name="R.exe" or Name="Rterm.exe"')
 			if len(processes) > 0 :
 				for p in processes:
-					#ret.append([p.Properties_('Name').Value, p.Properties_('ProcessId').Value])
-					##ret.append(p.Properties_('ExecutablePath').Value) 'CommandLine'
-					elem = components.classes["@mozilla.org/supports-string;1"] \
-						.createInstance(components.interfaces.nsISupportsString)
 					ret.append(p.Properties_(propertyName).Value)
 		else:
 			propertyName = {
@@ -104,48 +120,137 @@
 		return SimpleEnumerator(ret)
 
 
-	def execInR(self, command, host, port):
-		"""
-		This should send command to R through a socket connection and return the
-		output
-		"""
+	def execInR(self, command, host, port, mode):
 		s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-		s.connect((host, port))
-		s.settimeout(5)
+		s.settimeout(.5) # increase if not localhost
+		try:
+			s.connect((host, port))
+		except BaseException, e:
+			return unicode(e.args[0]);
+
 		# TODO: allow for <<<h>>>
-		s.send('<<<id=SciViewsK>>><<<e>>>' + command)
+		s.send('<<<id=' + self.id + '>>><<<' + mode + '>>>' + command)
 		s.shutdown(socket.SHUT_WR) # does not work without shutdown, why?
 		result = ''
-		while 1:
+		while True:
 			data = s.recv(1024)
 			if not data: break
 			result += data
 		s.close()
 		return unicode(result)
 
-	def execInRBgr(self, command, host='localhost', port=8888):
-		t = threading.Thread(target=self.rconnect, args=(command, host, port))
-		#t.setDaemon(True)
+	def execInRBgr(self, command, host, port, mode):
+		t = threading.Thread(target=self.rconnect, args=(command, host, port, mode))
+		#t.daemon = True
 		t.start()
 
-	def rconnect(self, command, host, port):
+	def rconnect(self, command, host, port, mode):
 		self.lastCommand = unicode(command)
 		s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 		s.connect((host, port))
 		s.settimeout(None)
-		s.send('<<<id=SciViewsK>>><<<e>>>' + command)
+		s.send('<<<id=' + self.id + '>>><<<' + mode + '>>>' + command)
 		s.shutdown(socket.SHUT_WR) # does not work without shutdown, why?
 		result = ''
-		# notify after each chunk, and at the end
+		# notify after each chunk and at the end
 		while 1:
 			data = s.recv(1024)
 			if not data: break
 			self._proxiedObsSvc.notifyObservers(None, 'r-command-chunk', data)
 			result += data
-		self._proxiedObsSvc.notifyObservers(None, 'r-command-finished', result)
 		s.close()
 		self.lastResult = unicode(result)
+		self._proxiedObsSvc.notifyObservers(None, 'r-command-executed', result)
 		#try:
-		self._proxiedObsSvc.notifyObservers(None, 'r-command-executed', result)
+		#self._proxiedObsSvc.notifyObservers(None, 'r-command-executed', result)
 		#except Exception:
 			#log.exception("r-command-executed notification failed")
+
+	def startSocketServer(self, host, port, requestHandler):
+		# TODO: do not run two! use semaphore
+		if(self.serverIsUp): return False
+		self.runServer = True
+		t = threading.Thread(target=self._SocketServer, kwargs={
+			'host': host,
+			'port': port,
+			'requestHandler': requestHandler
+			})
+		t.start()
+		log.debug('Started socket server at port %d' % port)
+		return True
+
+	def stopSocketServer(self):
+		self.runServer = False
+		log.debug('Told socket server to stop')
+
+
+	def _SocketServer(self, host, port, requestHandler):
+		# requestHandler is a Javascript object with component 'onStuff'
+		# which is a function accepting one argument (string), and returning
+		# a string
+		requestHandlerProxy = getProxyForObject(1,
+			components.interfaces.svIStuffListener,
+			requestHandler, PROXY_ALWAYS | PROXY_SYNC)
+		s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+		s.settimeout(5)
+		try:
+			s.bind((host, port))
+		except Exception, e:
+			log.exception(e)
+			return
+		self.serverIsUp = True
+		s.listen(1)
+		log.debug('Socket server listening at %d' % port)
+		count = 0
+		connected = False
+		while self.runServer:
+			while self.runServer:
+				connected = False
+				try:
+					conn, addr = s.accept()
+					connected = True
+					conn.setblocking(1)
+					count += 1
+					break
+				except Exception, e:
+					#print(e)
+					continue
+			if not connected: continue
+			data_all = ''
+			while connected:
+				log.debug('Connected by %s : %d' % addr)
+				data = conn.recv(1024)
+				data_all += data
+				if (not data) or (data[-1] == '\n'): break
+			#print "Sending:", data_all + "."
+			## Process data here
+			#result = data_all # echo request
+			#unicode(data_all) ?????
+			try:
+				result = requestHandlerProxy.onStuff(data_all)
+			except BaseException, e:
+				result = e.args[0]
+				log.debug('JS request exception: %s' % result)
+			if (result == None): conn.send('\n')
+			else: conn.send(result + '\n')
+			conn.shutdown(socket.SHUT_RDWR)
+			conn.close()
+			log.debug('conn closed')
+		#s.shutdown(socket.SHUT_RDWR) #  Is it necessarry?
+		s.close()
+		self.serverIsUp = False
+		log.debug("Exiting after %d connections" % count)
+		pass
+
+
+#    conn.setblocking(1)
+#  File "<string>", line 1, in setblocking
+#  File "/home/kamil/Komodo-Edit-6/lib/python/lib/python2.6/socket.py", line 165, in _dummy
+#    raise error(EBADF, 'Bad file descriptor')
+#error: [Errno 9] Bad file descriptor
+
+
+	#def Run(self, command, env, console):
+	#	pass
+	#
+	#def _WaitNotifyAndCleanUp(self, child, command, scriptFileName=None):

Modified: komodo/SciViews-K/content/js/r_new.js
===================================================================
--- komodo/SciViews-K/content/js/r_new.js	2011-02-14 21:53:06 UTC (rev 352)
+++ komodo/SciViews-K/content/js/r_new.js	2011-02-16 14:50:38 UTC (rev 353)
@@ -6,19 +6,37 @@
 //.result (Read only) last result returned
 //.getRProc(property) get information on currently running R processes
 //		(property is one of 'Handle','ProcessId' or 'CommandLine'
-//.setObserver(callback) set callback function for R command
-//.removeObserver
 //.rEval(command, callback) evaluate in R, optional callback (if not provided,
 //		the most recent one is used)
 //.rEvalQuick(command) - do 'quick' evaluation in R, and
-//return the result
+//		return the result
+//.startSocketServer(requestHandler) - optional 'requestHandler' is a function that
+//		handles the received data and returns a string
+//.stopSocketServer()
+//.testRAvailability(checkProc) - test whether R is available, check connection and
+//		optionally look up running processes
+//Debugging functions:
+//.testRCommand(command)
+//.testRCommandNotify(chunk)
+//.enumObservers()
+//Functions below should not be called directy by the user.
+//	they will become private later
+//*.setObserver(callback, topic) set callback function for R command
+//*.removeObserver
 
 
+try { // in case we inject the script more then one time
+	sv.rnew.removeObserver();
+} catch(e) {}
 
+
 sv.rnew = {};
 
 (function() {
 	var _this = this;
+	this.port = 8888;
+	this.serverPort = 7052;
+	this.host = 'localhost';
 
 // get string from nsISupportsString
 function _str(sString) sString.QueryInterface(Components
@@ -29,7 +47,7 @@
 var _obsSvc = Components.classes["@mozilla.org/observer-service;1"]
     .getService(Components.interfaces.nsIObserverService);
 
-var observer;
+var observers = {};
 var obsCallback = function() { sv.cmdout.append("test")};
 
 this.__defineGetter__ ('command', function () _svuSvc.lastCommand);
@@ -46,67 +64,149 @@
 }
 
 // Observer of 'r-command-executed' notification
-function rObserver() this.register();
+function rObserver(topic, callback) this.register(topic, callback);
 rObserver.prototype = {
 	observe: function(subject, topic, data) {
 		//ko.dialogs.alert(topic + ":\r\n" + data);
-		obsCallback(_svuSvc.lastCommand, data);
+		this.callback(_svuSvc.lastCommand, data);
 	},
-	register: function() {
-		_obsSvc.addObserver(this, "r-command-executed", false);
+	register: function(topic, callback) {
+		if(callback) this.callback = callback;
+		this.topic = topic;
+		_obsSvc.addObserver(this, topic, false);
 	},
 	unregister: function() {
-		_obsSvc.removeObserver(this, "r-command-executed");
-	}
+		_obsSvc.removeObserver(this, this.topic);
+	},
+
+	topic: null,
+	callback: function(cmd, data) ko.dialogs.alert(cmd, data)
 }
 
-this.removeObserver = function() {
-	observer.unregister();
-	callback = function() {};
+this.removeObserver = function(topic) {
+	if (!topic)	for (var i in observers) {
+		observers[i].unregister();
+		delete observers[i];
+	}
+	else {
+		observers[topic].unregister();
+		delete observers[topic];
+	}
 }
 
 // Set callback for executing R command
-this.setObserver = function(callback) {
+this.setObserver = function(callback, topic) {
+	if(!topic) topic = "r-command-executed";
+
 	try {
-		_this.removeObserver();
+		_this.removeObserver(topic);
 	} catch(e) {}
-	observer = new rObserver();
-	if (callback) obsCallback = callback;
+	observers[topic] = new rObserver(topic, callback);
 }
 
+this.enumObservers = function() {
+	var ret = [];
+	for (var i in observers) ret.push(observers[i]);
+	return ret;
+}
 
 // Evaluate in R
-this.rEval = function(command, callback) {
-	if(callback) _this.setObserver(callback);
-	_svuSvc.execInRBgr(command, 'localhost', 8888);
+this.rEval = function(command, callback, hidden) {
+	if(callback) _this.setObserver(callback, "r-command-executed");
+	_svuSvc.execInRBgr(command, _this.host, _this.port, hidden? "h" : "e");
 }
 
 // TODO: this should use <<<h>>>
 // Evaluate in R quickly - and return result
 this.rEvalQuick = function(command)
-	_svuSvc.execInR(command, 'localhost', 8888);
+	_svuSvc.execInR(command, _this.host, _this.port, "h");
 
 
 // For debugging purposes only
 this.testRCommand = function(command) {
 	if(!command) command = "sample(LETTERS, 10)";
-	_svuSvc.execInRBgr(command, 'localhost', 8888);
+	_svuSvc.execInRBgr(command, _this.host, _this.port, "e");
 }
 
-this.testRCommandNotify = function() {
-	_obsSvc.notifyObservers(null, "r-command-executed", "!!!");
+this.testRCommandNotify = function(chunk) {
+	topic = "r-command" + (chunk? "chunk" : "executed");
+	_obsSvc.notifyObservers(null, topic, "You are notified. {" + topic + "}");
 }
 
+var rCallback = function(cmd, res) {
+	//sv.cmdout.clear();
+	sv.cmdout.append("::>"+ cmd + ": END")
+}
+
+var rCallbackChunk = function(cmd, res) {
+	sv.cmdout.append("\n<++CHUNK++>\n"+ res, false)
+}
+
+this.testRAvailability = function(checkProc) {
+	var result = _this.rEvalQuick("cat(1)").trim();
+	var connectionUp = result == "1";
+	var rProcess = checkProc? _this.getRProc() : undefined;
+	var rProcessCount = (rProcess == undefined)? -1 : rProcess.length;
+	ret = '';
+	if(!connectionUp) {
+		ret += "Cannot connect to R";
+		if (rProcessCount > 0) {
+			ret += ", but there " + ((rProcessCount > 1)? "are " + rProcessCount
+				+ " R processes": "is one R process") + " running.";
+			result += "\n\nR processes currently running:\n" + rProcess.join("\n");
+		} else if (rProcessCount == 0) {
+			ret += ",  R is not running.";
+		}
+	} else {
+		result = null;
+		ret += "Connection with R successful.";
+	}
+	//ko.dialogs.alert(ret, result, "R connection test");
+	sv.cmdout.append("R connection test:\n" + ret + "\n"  + result);
+	return connectionUp;
+}
+
+_this.setObserver(rCallbackChunk, "r-command-chunk");
+_this.setObserver(rCallback, "r-command-executed");
+
+var defaultRequestHandler = function(str) {
+	str = str.trim();
+	//sv.cmdout.append(str);
+	try {
+		if (str.indexOf("<<<js>>>") == 0)
+			return eval(str.substring(8));
+		 else if(str.indexOf("<<<rjsonp>>>") == 0)
+			return sv.rjson.eval(str.substring(12));
+	} catch(e) {
+		return e.message;
+	}
+	sv.cmdout.append(str);
+	return "Received: [" + str + "]"; // echo
+}
+
+
+this.startSocketServer = function(requestHandler) {
+	_this.host = sv.prefs.getString("sciviews.server.host");
+	_this.serverPort = parseInt(sv.prefs.getString("sciviews.server.socket"));
+
+	if(!requestHandler) requestHandler = defaultRequestHandler;
+	return _svuSvc.startSocketServer(_this.host, _this.serverPort, {onStuff: requestHandler});
+}
+
+this.stopSocketServer = function() _svuSvc.stopSocketServer();
+
+addEventListener("load", function() {
+	sv.command.updateRStatus(_this.testRAvailability(false));
+	_this.startSocketServer();
+}, false);
+
+
 }).apply(sv.rnew);
 
 
 // seems to be no problem with encoding (!!?)
-//sv.rnew.testRCommand("cat('pchn¹æ w tê ³ódŸ je¿a i óœm skrzyñ fig')")
+//sv.rnew.testRCommand("cat('pchn¹æ w tê ³ódŸ je¿a i óœm skrzyñ fig')") // Note this is CP1250 encoding
 
-var rCallback = function(cmd, res) {
-	sv.cmdout.clear();
-	sv.cmdout.append("::>"+ cmd + "\n" + res)
-}
 
 //sv.rnew.rEval("cat(1:10)", ko.dialogs.alert);
 //result = sv.rnew.rEvalQuick("cat(1:10)");



More information about the Sciviews-commits mailing list