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