Package VisionEgg :: Module TCPController
[frames] | no frames]

Source Code for Module VisionEgg.TCPController

  1  # The Vision Egg: TCPController 
  2  # 
  3  # Copyright (C) 2001-2003 Andrew Straw. 
  4  # Author: Andrew Straw <astraw@users.sourceforge.net> 
  5  # URL: <http://www.visionegg.org/> 
  6  # 
  7  # Distributed under the terms of the GNU Lesser General Public License 
  8  # (LGPL). See LICENSE.TXT that came with this file. 
  9  # 
 10  # $Id$ 
 11   
 12  """ 
 13  Allows control of parameter values over the network. 
 14   
 15  Don't use for realtime control unless you think your network is that 
 16  fast and reliable. Also, this code has not been optimized for speed, 
 17  and I think it is unwise to attempt to change the value of controllers 
 18  in realtime.  In other words, do not design an experiment where, on a 
 19  remote computer, you have determined that a certain amount of time has 
 20  passed, and you require a certain new controller value NOW.  In this 
 21  case, it would be better to use parameter=eval_str() with an if 
 22  statement involving time. 
 23   
 24  To control parameters over a network, start a server with an instance 
 25  of TCPServer.  The server spawns an instance of SocketListenController 
 26  for each connected socket.  (Most commonly you will only want 
 27  connection over a single socket.)  The instance of 
 28  SocketListenController handles all communication for that connection 
 29  and serves as a container and (meta) controller for instances of 
 30  TCPController. 
 31   
 32  This module contains ABSOLUTELY NO SECURITY FEATURES, and could easily 
 33  allow arbitrary execution of code on your computer. For this reason, 
 34  if you use this module, I recommend operating behind a firewall. This 
 35  could be an inexpensive "routing switch" used for cable modems, which 
 36  would provide the added benefit that your local network would be 
 37  isolated.  This would elimate all traffic not to or from computers on 
 38  the switch and therefore reduce/eliminate packet collisions, decrease 
 39  latency, and providing a network performance and reliability. To 
 40  address security concerns, you could also write code that implements 
 41  IP address checking or other security features. 
 42   
 43  """ 
 44   
 45  import VisionEgg 
 46  import VisionEgg.Core 
 47  import VisionEgg.FlowControl 
 48  import VisionEgg.ParameterTypes as ve_types 
 49  import socket, select, re, string, types 
 50  import numpy.oldnumeric as Numeric, math # for eval 
 51   
 52  try: 
 53      import Tkinter 
 54  except: 
 55      pass 
 56   
 57  import logging 
 58   
 59  __version__ = VisionEgg.release_name 
 60  __cvs__ = '$Revision$'.split()[1] 
 61  __date__ = ' '.join('$Date$'.split()[1:3]) 
 62  __author__ = 'Andrew Straw <astraw@users.sourceforge.net>' 
 63   
64 -class TCPServer:
65 """TCP server creates SocketListenController upon connection. 66 67 This class is analagous to VisionEgg.PyroHelpers.PyroServer. 68 69 """
70 - def __init__(self, 71 hostname="", 72 port=7834, 73 single_socket_but_reconnect_ok=0, 74 dialog_ok=1, 75 confirm_address_with_gui=1):
76 """Bind to hostname and port, but don't listen yet. 77 78 """ 79 server_address = (socket.getfqdn(hostname),port) 80 self.dialog_ok = dialog_ok 81 self.single_socket_but_reconnect_ok = single_socket_but_reconnect_ok 82 self.buffer = "" 83 self.server_socket=None 84 if not globals().has_key("Tkinter") or (VisionEgg.config.VISIONEGG_TKINTER_OK==0): 85 self.dialog_ok = 0 86 87 class GetServerAddressWindow(Tkinter.Frame): 88 def __init__(self,server_address,**kw): 89 try: 90 Tkinter.Frame.__init__(self,**kw) 91 except AttributeError,x: 92 tk=Tkinter.Tk() # restart Tk and see if that helps 93 Tkinter.Frame.__init__(self,tk,**kw) 94 self.winfo_toplevel().title("Vision Egg: TCP Server get address") 95 self.server_address = server_address 96 hostname,port = self.server_address 97 self.clicked_ok = 0 98 self.hostname = Tkinter.StringVar() 99 self.hostname.set(hostname) 100 self.port = Tkinter.StringVar() 101 self.port.set(port) 102 row = 0 103 Tkinter.Label(self, 104 text="Please enter the hostname and port you would like to listen for connections on.", 105 ).grid(row=row,columnspan=2) 106 row += 1 107 Tkinter.Label(self, 108 text="Hostname (blank means localhost):", 109 ).grid(row=row,column=0,sticky=Tkinter.E) 110 Tkinter.Entry(self,textvariable=self.hostname).grid(row=row,column=1,sticky=Tkinter.W+Tkinter.E,padx=10) 111 row += 1 112 Tkinter.Label(self, 113 text="Port:", 114 ).grid(row=row,column=0,sticky=Tkinter.E) 115 Tkinter.Entry(self,textvariable=self.port).grid(row=row,column=1,sticky=Tkinter.W+Tkinter.E,padx=10) 116 row += 1 117 b = Tkinter.Button(self, 118 text="Bind port and listen for connections", 119 command=self.click_ok) 120 b.grid(row=row,columnspan=2) 121 b.focus_force() 122 b.bind('<Return>',self.click_ok)
123 def click_ok(self,dummy_arg=None): 124 hostname = self.hostname.get() 125 try: 126 port = int(self.port.get()) 127 except: 128 port = self.port.get() 129 self.server_address = (hostname,port) 130 self.clicked_ok = 1 131 self.winfo_toplevel().destroy()
132 133 bound = 0 134 if not bound: 135 # while not bound: # don't loop until the code is cleaner 136 if confirm_address_with_gui and self.dialog_ok: 137 window = GetServerAddressWindow(server_address) 138 window.pack() 139 window.mainloop() 140 if not window.clicked_ok: 141 return # User wants to quit 142 server_address = window.server_address 143 self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 144 self.server_socket.bind(server_address) 145 bound = 1 146
147 - def create_listener_once_connected(self,eval_frequency=None):
148 """Wait for connection and spawn instance of SocketListenController.""" 149 if eval_frequency is None: 150 # Don't listen to socket during go loop -- especially don't want to skip frames then 151 eval_frequency = VisionEgg.FlowControl.Controller.EVERY_FRAME | VisionEgg.FlowControl.Controller.NOT_DURING_GO 152 host,port = self.server_socket.getsockname() 153 fqdn = socket.getfqdn(host) 154 logger = logging.getLogger('VisionEgg.TCPController') 155 logger.info("Awaiting connection to TCP Server at '%s', port %d"%(fqdn,port)) 156 self.server_socket.listen(1) 157 if self.dialog_ok: 158 # Make a Tkinter dialog box 159 class WaitingDialog(Tkinter.Frame): 160 def __init__(self,server_socket=None,**kw): 161 Tkinter.Frame.__init__(self,**kw) 162 self.winfo_toplevel().title('Vision Egg TCP Server') 163 self.server_socket = server_socket 164 host,port = self.server_socket.getsockname() 165 fqdn = socket.getfqdn(host) 166 spacer = Tkinter.Frame(self,borderwidth=30) 167 spacer.pack() 168 Tkinter.Label(spacer,text= 169 """Awaiting connection to TCP Server at "%s", port %d"""%(fqdn,port) 170 ).pack() 171 b = Tkinter.Button(self,text="Cancel",command=self.stop_listening) 172 b.pack(side=Tkinter.BOTTOM) 173 b.focus_force() 174 b.bind('<Return>',self.stop_listening) 175 self.winfo_toplevel().protocol("WM_DELETE_WINDOW", self.stop_listening) 176 self.server_socket.setblocking(0) 177 self.after(1,self.idle_func)
178 def stop_listening(self,dummy=None): 179 raise SystemExit 180 def idle_func(self): 181 try: 182 # This line raises an exception unless there's an incoming connection 183 self.accepted = self.server_socket.accept() 184 self.quit() 185 except socket.error, x: 186 self.after(1,self.idle_func) 187 dialog = WaitingDialog(server_socket = self.server_socket) 188 dialog.pack() 189 dialog.mainloop() 190 client, client_address = dialog.accepted 191 dialog.winfo_toplevel().destroy() 192 else: 193 client, client_address = self.server_socket.accept() 194 if self.single_socket_but_reconnect_ok: 195 return SocketListenController(client, 196 disconnect_ok = 1, 197 server_socket = self.server_socket) 198 else: 199 return SocketListenController(client) 200
201 -class SocketListenController(VisionEgg.FlowControl.Controller):
202 r"""Handle connection from remote machine, control TCPControllers. 203 204 This meta controller handles a TCP socket to control zero to many 205 instances of TCPController. As a subclass of Controller, it gets 206 called at specified moments in time via the Presentation 207 class. When called in this way, it checks for any strings from the 208 TCP socket. It parses this information into a command or fails 209 and sends an error. 210 211 This class is analagous to VisionEgg.PyroHelpers.PyroListenController. 212 213 TCP commands (sent over network socket) 214 ======================================= 215 216 close -- close the connection 217 exit -- close the connection 218 quit -- quit the server program 219 help -- print help message 220 <name> -- show the value of the controller of <name> 221 <name>=const(<args>) -- assign a new ConstantController to <name> 222 <name>=eval_str(<args>) -- assign a new EvalStringController to <name> 223 <name>=exec_str(<args>) -- assign a new ExecStringController to <name> 224 <name>=exec_str(*<args>) -- assign a new unrestricted namespace ExecStringController to <name> 225 226 TCP commands are always on a single line. (Newlines in string 227 literals can be specified by using "\n" without the quotes.) 228 229 The assignment commands share common behavior: 230 231 <name> -- value passed as argument "tcp_name" to method create_tcp_controller 232 <args> -- during_go [, between_go [, eval_frequency [, temporal_variables [, return_type ]]]] 233 234 The <args> string is parsed by the Python's eval() function. If 235 you don't want to explicitly set an argument early in the argument 236 list, but you need to set one late in the list, use "None". If 237 not set, the optional arguments default to: 238 239 eval_frequency = EVERY_FRAME 240 temporal_variables = TIME_SEC_SINCE_GO 241 return_type = (evaluates during_go function to find) 242 between_go = (see below, depends on assignment type) 243 244 The only difference between the assignment commands are in the 245 first two arguments. For "const(...)", the first two arguments 246 are constant values, for "eval_str(...)" they are strings that 247 evaluate to a single variable, and for "exec_str(...)", they are 248 strings that set the variable "x" in their local namespace, which 249 is then returned. (An unrestricted namespace is available with 250 "exec_str(*...)".) If the argument between_go is set to None or 251 is not defined, the behavior depends on the assignment command. 252 If this is a <name>=const(...) assignment, between_go_value is set 253 to during_go_value. If this is a <name>=eval_str(...) or 254 <name>=exec_str(...) assignment, the correct value cannot be 255 guessed, and therefore the between_go_eval function will never be 256 called (the eval_frequency flag NOT_BETWEEN_GO is set). 257 258 Because the default value for temporal_variables is 259 TIME_SEC_SINCE_GO, the variable "t" may be safely used in the 260 during_go string for the eval_str or exec_str assignment commands. 261 See the documentation for VisionEgg.FlowControl.EvalStringController for 262 more information. 263 264 Example commands from TCP port (try with telnet): 265 266 <name>=const(1.0) 267 <name>=eval_str("t*360.0") 268 <name>=exec_str("x=t*360.0") 269 270 <name>=const(0.,1.,EVERY_FRAME) 271 <name>=const(1,None,ONCE) 272 273 <name>=const(1.0,0.0,EVERY_FRAME,TIME_INDEPENDENT,types.FloatType) 274 <name>=eval_str("t*360.0","t_abs*360.0",None,TIME_SEC_ABSOLUTE|TIME_SEC_SINCE_GO) 275 <name>=eval_str("t_abs*360.0","t_abs*360.0",EVERY_FRAME,TIME_SEC_ABSOLUTE,types.FloatType) 276 <name>=exec_str("x=t*360.0","x=0.0",EVERY_FRAME,TIME_SEC_SINCE_GO) 277 <name>=exec_str("print 'Time since go=%f'%(t,)\nx=t*360.0","x=0.0",EVERY_FRAME,TIME_SEC_SINCE_GO) 278 279 """ 280 281 help_string = r""" TCP commands (sent over network socket): 282 283 close -- close the connection 284 exit -- close the connection 285 quit -- quit the server program 286 help -- print this message 287 <name> -- show the value of the controller of <name> 288 <name>=const(<args>) -- assign a new ConstantController to <name> 289 <name>=eval_str(<args>) -- assign a new EvalStringController to <name> 290 <name>=exec_str(<args>) -- assign a new ExecStringController to <name> 291 <name>=exec_str(*<args>) -- assign a new unrestricted namespace ExecStringController to <name> 292 293 TCP commands are always on a single line. (Newlines in string 294 literals can be specified by using "\n" without the quotes.) 295 296 The assignment commands share common behavior: 297 298 <name> -- value passed as argument "tcp_name" to method create_tcp_controller 299 <args> -- during_go [, between_go [, eval_frequency [, temporal_variables [, return_type ]]]] 300 """ 301 302 _re_line = re.compile(r"^(.*)\n",re.MULTILINE) 303 _re_x_finder = re.compile(r'\A|\Wx\s?=[^=]') 304 # The real newlines have already been parsed by the time the buffer gets to these statements: 305 _re_const = re.compile(r'^const\(\s?(.*)\s?\)$',re.DOTALL) 306 _re_eval_str = re.compile(r'^eval_str\(\s?(.*)\s?\)$',re.DOTALL) 307 _re_exec_str = re.compile(r'^exec_str\(\s?(\*)?\s?(.*)\s?\)$',re.DOTALL) 308 _parse_args_globals = {'types':types} 309 _parse_args_locals = VisionEgg.FlowControl.Controller.flag_dictionary
310 - def __init__(self, 311 socket, 312 disconnect_ok = 0, 313 server_socket = None, # Only needed if reconnecting ok 314 temporal_variables = VisionEgg.FlowControl.Controller.TIME_INDEPENDENT, 315 eval_frequency = VisionEgg.FlowControl.Controller.EVERY_FRAME):
316 """Instantiated by TCPServer.""" 317 VisionEgg.FlowControl.Controller.__init__(self, 318 return_type = types.NoneType, 319 temporal_variables = temporal_variables, 320 eval_frequency = eval_frequency) 321 self.socket = socket 322 self.disconnect_ok = disconnect_ok 323 if self.disconnect_ok and server_socket is None: 324 # Warning -- no ability to accept further incoming sockets... 325 pass 326 self.server_socket = server_socket 327 328 logger = logging.getLogger('VisionEgg.TCPController') 329 logger.info("Handling connection from %s"%(self.socket.getsockname(),)) 330 self.socket.setblocking(0) # don't block on this socket 331 332 self.socket.send("Hello. This is %s version %s.\n"%(self.__class__,__version__)) 333 self.socket.send(SocketListenController.help_string+"\n") 334 self.socket.send("Begin sending commands now.\n") 335 336 self.buffer = "" 337 338 self.last_command = {} 339 340 self.names = {} # ( controller, name_re, parser, require_type )
341
342 - def send_raw_text(self,text):
343 """Send text over the TCP socket.""" 344 self.socket.send(text)
345
346 - def __check_socket(self):
347 if self.socket is not None: # Normal, connected behavior 348 # First, update the buffer 349 ready_to_read, temp, temp2 = select.select([self.socket],[],[],0) 350 new_info = 0 351 while len(ready_to_read): 352 try: 353 new = self.socket.recv(1024) # When disconnected, this fails on Win32 354 except socket.error, x: 355 if not self.disconnect_ok: 356 raise 357 else: 358 self.socket.close() 359 self.socket = None 360 if self.server_socket is not None: 361 self.server_socket.setblocking(0) 362 return 363 if len(new) == 0: # When disconnected, this happens on unix 364 # Disconnected 365 self.socket.close() # close socket 366 self.socket = None 367 if not self.disconnect_ok: 368 raise RuntimeError("Socket disconnected!") 369 else: 370 if self.server_socket is not None: 371 self.server_socket.setblocking(0) 372 return # don't do any more 373 #assert(ready_to_read[0] == self.socket) 374 self.buffer += new 375 new_info = 1 376 ready_to_read, temp, temp2 = select.select([self.socket],[],[],0) 377 378 # Second, convert the buffer to command_queue entries 379 if new_info: 380 # Handle variations on newlines: 381 self.buffer = string.replace(self.buffer,chr(0x0D),"") # no CR 382 self.buffer = string.replace(self.buffer,chr(0x0A),"\n") # LF = newline 383 # Handle each line for which we have a tcp_name 384 for tcp_name in self.names.keys(): 385 (controller, name_re_str, parser, require_type) = self.names[tcp_name] 386 387 # If the following line makes a match, it 388 # sticks the result in self.last_command[tcp_name] by calling the parser function. 389 self.buffer = name_re_str.sub(parser,self.buffer) 390 # Now act based on the command parsed 391 command = self.last_command[tcp_name] 392 if command is not None: 393 self.__do_assignment_command(tcp_name,command,require_type) 394 self.last_command[tcp_name] = None 395 # Clear any complete lines for which we don't have a tcp_name 396 self.buffer = SocketListenController._re_line.sub(self.__unprocessed_line,self.buffer) 397 elif self.server_socket is not None: 398 # Not connected on self.socket, check self.server_socket for new connection 399 try: 400 # This line raises an exception unless there's an incoming connection (if server is not blocking, which it shouldn't be) 401 (client, client_address) = self.server_socket.accept() 402 self.socket = client 403 self.socket.send("Hello. This is %s version %s.\n"%(self.__class__,__version__)) 404 self.socket.send(SocketListenController.help_string+"\n") 405 self.socket.send("Begin sending commands now.\n") 406 for tcp_name in self.names.keys(): 407 (controller, name_re_str, parser, require_type) = self.names[tcp_name] 408 self.socket.send('"%s" controllable with this connection.\n'%tcp_name) 409 except socket.error, x: 410 pass
411
412 - def __unprocessed_line(self,match):
413 text = match.group(1) 414 text = string.strip(text).lower() 415 if text=="quit": # this a hack, really (should be a controller in charge of Presentation.parameters.quit) 416 raise SystemExit 417 elif text=="close" or text=="exit": 418 self.socket = None # close socket 419 if not self.disconnect_ok: 420 raise RuntimeError("Socket disconnected!") 421 else: 422 if self.server_socket is not None: 423 self.server_socket.setblocking(0) 424 return "" 425 elif text=="help": 426 self.socket.send(SocketListenController.help_string+"\n") 427 return "" 428 elif text in self.names.keys(): 429 (controller, name_re_str, parser, require_type) = self.names[text] 430 self.socket.send(text+"="+str(controller)+"\n") 431 return "" 432 self.socket.send("Error: Invalid command line \""+text+"\"\n") 433 logger = logging.getLogger('VisionEgg.TCPController') 434 logger.warning('Invalid command line: "%s"'%(text,)) 435 return ''
436
437 - def create_tcp_controller(self, 438 tcp_name=None, 439 initial_controller=None, 440 require_type=None):
441 """Create new instance of TCPController. 442 443 Arguments: 444 445 tcp_name -- String to reference new TCPController over TCP 446 447 Optional arguments: 448 449 initial_controller -- Initial value of TCPController instance 450 require_type -- force this as TCPController instance's return_type 451 """ 452 class Parser: 453 def __init__(self,tcp_name,most_recent_command): 454 self.tcp_name = tcp_name 455 self.most_recent_command = most_recent_command
456 457 def parse_func(self,match): 458 # Could make this into a lambda function 459 self.most_recent_command[self.tcp_name] = match.groups()[-1] 460 return ""
461 if tcp_name is None: 462 raise ValueError("Must specify tcp_name") 463 if tcp_name in self.names.keys(): 464 raise ValueError('tcp_name "%s" already in use.'%tcp_name) 465 if string.count(tcp_name,' '): 466 raise ValueError('tcp_name "%s" cannot have spaces.'%tcp_name) 467 if tcp_name == "quit": 468 raise ValueError('tcp_name "%s" conflicts with reserved word.'%tcp_name) 469 if initial_controller is None: 470 # create default controller 471 initial_controller = VisionEgg.FlowControl.ConstantController( 472 during_go_value=1.0, 473 between_go_value=0.0) 474 else: 475 if not isinstance(initial_controller,VisionEgg.FlowControl.Controller): 476 print initial_controller 477 raise ValueError('initial_controller not an instance of VisionEgg.FlowControl.Controller') 478 if require_type is None: 479 require_type = initial_controller.returns_type() 480 # Create initial None value for self.last_command dict 481 self.last_command[tcp_name] = None 482 # Create values for self.names dict tuple ( controller, name_re, most_recent_command, parser ) 483 controller = TCPController( 484 tcp_name=tcp_name, 485 initial_controller=initial_controller 486 ) 487 name_re_str = re.compile("^"+tcp_name+r"\s*=\s*(.*)\s*\n$",re.MULTILINE) 488 parser = Parser(tcp_name,self.last_command).parse_func 489 self.names[tcp_name] = (controller, name_re_str, parser, require_type) 490 self.socket.send('"%s" controllable with this connection.\n'%tcp_name) 491 return controller 492
493 - def __get_five_args(self,arg_string):
494 args = eval("("+arg_string+",)",SocketListenController._parse_args_globals,SocketListenController._parse_args_locals) 495 num_args = len(args) 496 if num_args == 0: 497 args = (None,None,None,None,None) 498 elif num_args == 1: 499 args = (args[0],None,None,None,None) 500 elif num_args == 2: 501 args = (args[0],args[1],None,None,None) 502 elif num_args == 3: 503 args = (args[0],args[1],args[2],None,None) 504 elif num_args == 4: 505 args = (args[0],args[1],args[2],args[3],None) 506 elif num_args > 5: 507 raise ValueError("Too many arguments!") 508 if args[0] is None: 509 raise ValueError("First argument must be set.") 510 return args
511
512 - def __process_common_args(self,kw_args,match_groups):
513 if match_groups[2] is not None: 514 kw_args['eval_frequency'] = match_groups[2] 515 if match_groups[3] is not None: 516 kw_args['temporal_variables'] = match_groups[3] 517 if match_groups[4] is not None: 518 kw_args['return_type'] = match_groups[4]
519
520 - def __do_assignment_command(self,tcp_name,command,require_type):
521 new_contained_controller = None 522 match = SocketListenController._re_const.match(command) 523 if match is not None: 524 try: 525 match_groups = self.__get_five_args(match.group(1)) 526 kw_args = {} 527 kw_args['during_go_value'] = match_groups[0] 528 if match_groups[1] is not None: 529 kw_args['between_go_value'] = match_groups[1] 530 self.__process_common_args(kw_args,match_groups) 531 kw_args.setdefault('return_type',require_type) 532 new_contained_controller = VisionEgg.FlowControl.ConstantController(**kw_args) 533 new_type = new_contained_controller.returns_type() 534 ve_types.assert_type( new_type, require_type) 535 except Exception, x: 536 import traceback 537 traceback.print_exc() 538 self.socket.send("Error %s parsing const for %s: %s\n"%(x.__class__,tcp_name,x)) 539 logger = logging.getLogger('VisionEgg.TCPController') 540 logger.info("%s parsing const for %s: %s"%(x.__class__,tcp_name,x)) 541 else: 542 match = SocketListenController._re_eval_str.match(command) 543 if match is not None: 544 try: 545 match_groups = self.__get_five_args(match.group(1)) 546 kw_args = {} 547 kw_args['during_go_eval_string'] = string.replace(match_groups[0],r"\n","\n") 548 if match_groups[1] is not None: 549 kw_args['between_go_eval_string'] = string.replace(match_groups[1],r"\n","\n") 550 self.__process_common_args(kw_args,match_groups) 551 kw_args.setdefault('return_type',require_type) 552 new_contained_controller = VisionEgg.FlowControl.EvalStringController(**kw_args) 553 if not (new_contained_controller.eval_frequency & VisionEgg.FlowControl.Controller.NOT_DURING_GO): 554 logger = logging.getLogger('VisionEgg.TCPController') 555 logger.debug('Executing "%s" as safety check.'%(kw_args['during_go_eval_string'],)) 556 new_contained_controller._test_self(1) 557 if not (new_contained_controller.eval_frequency & VisionEgg.FlowControl.Controller.NOT_BETWEEN_GO): 558 logger = logging.getLogger('VisionEgg.TCPController') 559 logger.debug('Executing "%s" as safety check.'%(kw_args['between_go_eval_string'],)) 560 new_contained_controller._test_self(0) 561 new_type = new_contained_controller.returns_type() 562 ve_types.assert_type( new_type, require_type) 563 except Exception, x: 564 new_contained_controller = None 565 self.socket.send("Error %s parsing eval_str for %s: %s\n"%(x.__class__,tcp_name,x)) 566 logger = logging.getLogger('VisionEgg.TCPController') 567 logger.info("%s parsing eval_str for %s: %s"%(x.__class__,tcp_name,x)) 568 else: 569 match = SocketListenController._re_exec_str.match(command) 570 if match is not None: 571 try: 572 kw_args = {} 573 match_groups = match.groups() 574 if match_groups[0] == '*': 575 kw_args['restricted_namespace'] = 0 576 else: 577 kw_args['restricted_namespace'] = 1 578 match_groups = self.__get_five_args(match_groups[1]) 579 tmp = string.replace(match_groups[0],r"\n","\n") 580 if not SocketListenController._re_x_finder.match(tmp): 581 raise ValueError("x is not defined for during_go_exec_string") 582 kw_args['during_go_exec_string'] = tmp 583 if match_groups[1] is not None: 584 tmp = string.replace(match_groups[1],r"\n","\n") 585 if not SocketListenController._re_x_finder.match(tmp): 586 raise ValueError("x is not defined for between_go_exec_string") 587 kw_args['between_go_exec_string'] = tmp 588 self.__process_common_args(kw_args,match_groups) 589 kw_args.setdefault('return_type',require_type) 590 new_contained_controller = VisionEgg.FlowControl.ExecStringController(**kw_args) 591 if not (new_contained_controller.eval_frequency & VisionEgg.FlowControl.Controller.NOT_DURING_GO): 592 logger = logging.getLogger('VisionEgg.TCPController') 593 logger.debug('Executing "%s" as safety check.'%(kw_args['during_go_exec_string'],)) 594 new_contained_controller._test_self(1) 595 if not (new_contained_controller.eval_frequency & VisionEgg.FlowControl.Controller.NOT_BETWEEN_GO): 596 logger = logging.getLogger('VisionEgg.TCPController') 597 logger.debug('Executing "%s" as safety check.'%(kw_args['between_go_exec_string'],)) 598 new_contained_controller._test_self(0) 599 new_type = new_contained_controller.returns_type() 600 ve_types.assert_type( new_type, require_type) 601 except Exception, x: 602 new_contained_controller = None 603 self.socket.send("Error %s parsing exec_str for %s: %s\n"%(x.__class__,tcp_name,x)) 604 logger = logging.getLogger('VisionEgg.TCPController') 605 logger.debug("%s parsing exec_str for %s: %s"%(x.__class__,tcp_name,x)) 606 else: 607 self.socket.send("Error: Invalid assignment command for %s: %s\n"%(tcp_name,command)) 608 logger = logging.getLogger('VisionEgg.TCPController') 609 logger.info("Invalid assignment command for %s: %s"%(tcp_name,command)) 610 # create controller based on last command_queue 611 if new_contained_controller is not None: 612 (controller, name_re_str, parser, require_type) = self.names[tcp_name] 613 controller.set_new_controller(new_contained_controller)
614
615 - def during_go_eval(self):
616 """Check socket and act accordingly. Called by instance of Presentation. 617 618 Overrides base class Controller method.""" 619 self.__check_socket() 620 return None
621
622 - def between_go_eval(self):
623 """Check socket and act accordingly. Called by instance of Presentation. 624 625 Overrides base class Controller method.""" 626 self.__check_socket() 627 return None
628
629 -class TCPController(VisionEgg.FlowControl.EncapsulatedController):
630 """Control a parameter from a network (TCP) connection. 631 632 Subclass of Controller to allow control of Parameters via the 633 network. 634 635 This class is analagous to VisionEgg.PyroHelpers.PyroEncapsulatedController. 636 """ 637 # Contains another controller...
638 - def __init__(self, tcp_name, initial_controller):
639 """Instantiated by SocketListenController. 640 641 Users should create instance by using method 642 create_tcp_controller of class SocketListenController.""" 643 VisionEgg.FlowControl.EncapsulatedController.__init__(self,initial_controller) 644 self.tcp_name = tcp_name
645
646 - def __str__(self):
647 value = "" 648 my_class = self.contained_controller.__class__ 649 if my_class == VisionEgg.FlowControl.ConstantController: 650 value += "const( " 651 value += str(self.contained_controller.get_during_go_value()) + ", " 652 value += str(self.contained_controller.get_between_go_value()) + ", " 653 elif my_class == VisionEgg.FlowControl.EvalStringController: 654 value += "eval_str( " 655 str_val = self.contained_controller.get_during_go_eval_string() 656 if str_val is None: 657 value += "None, " 658 else: 659 value += '"' + string.replace(str_val,"\n",r"\n") + '", ' 660 str_val = self.contained_controller.get_between_go_eval_string() 661 if str_val is None: 662 value += "None, " 663 else: 664 value += '"' + string.replace(str_val,"\n",r"\n") + '", ' 665 elif my_class == VisionEgg.FlowControl.ExecStringController: 666 value += "exec_str(" 667 if self.contained_controller.restricted_namespace: 668 value += " " 669 else: # unrestricted 670 value += "* " 671 str_val = self.contained_controller.get_during_go_exec_string() 672 if str_val is None: 673 value += "None, " 674 else: 675 value += '"' + string.replace(str_val,"\n",r"\n") + '", ' 676 str_val = self.contained_controller.get_between_go_exec_string() 677 if str_val is None: 678 value += "None, " 679 else: 680 value += '"' + string.replace(str_val,"\n",r"\n") + '", ' 681 never = 1 682 ef = self.contained_controller.eval_frequency 683 if ef & VisionEgg.FlowControl.Controller.EVERY_FRAME: 684 value += "EVERY_FRAME | " 685 never = 0 686 if ef & VisionEgg.FlowControl.Controller.TRANSITIONS: 687 value += "TRANSITIONS | " 688 never = 0 689 if ef & VisionEgg.FlowControl.Controller.ONCE: 690 value += "ONCE | " 691 never = 0 692 if ef & VisionEgg.FlowControl.Controller.NOT_DURING_GO: 693 value += "NOT_DURING_GO | " 694 never = 0 695 if ef & VisionEgg.FlowControl.Controller.NOT_BETWEEN_GO: 696 value += "NOT_BETWEEN_GO | " 697 never = 0 698 if never: 699 value += "NEVER" 700 else: 701 value = value[:-3] # get rid of trailing "| " 702 value += ", " 703 time_indep = 1 704 tv = self.contained_controller.temporal_variables 705 if tv & VisionEgg.FlowControl.Controller.TIME_SEC_ABSOLUTE: 706 value += "TIME_SEC_ABSOLUTE | " 707 time_indep = 0 708 if tv & VisionEgg.FlowControl.Controller.TIME_SEC_SINCE_GO: 709 value += "TIME_SEC_SINCE_GO | " 710 time_indep = 0 711 if tv & VisionEgg.FlowControl.Controller.FRAMES_ABSOLUTE: 712 value += "FRAMES_ABSOLUTE | " 713 time_indep = 0 714 if tv & VisionEgg.FlowControl.Controller.FRAMES_SINCE_GO: 715 value += "FRAMES_SINCE_GO | " 716 time_indep = 0 717 if time_indep: 718 value += "TIME_INDEPENDENT" 719 else: 720 value = value[:-3] # get rid of trailing "| " 721 value += ", " 722 my_type = self.contained_controller.returns_type() 723 if my_type == types.ClassType: 724 value += str(my_type) 725 else: 726 for t in dir(types): 727 if my_type == getattr(types,t): 728 value += "types."+t 729 break 730 value += " )" 731 return value
732