rosweb.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 """
3 usage: %(progname)s [--debug]
4 """
5 
6 # Software License Agreement (BSD License)
7 #
8 # Copyright (c) 2009, Willow Garage, Inc.
9 # All rights reserved.
10 #
11 # Redistribution and use in source and binary forms, with or without
12 # modification, are permitted provided that the following conditions
13 # are met:
14 #
15 # * Redistributions of source code must retain the above copyright
16 # notice, this list of conditions and the following disclaimer.
17 # * Redistributions in binary form must reproduce the above
18 # copyright notice, this list of conditions and the following
19 # disclaimer in the documentation and/or other materials provided
20 # with the distribution.
21 # * Neither the name of Willow Garage, Inc. nor the names of its
22 # contributors may be used to endorse or promote products derived
23 # from this software without specific prior written permission.
24 #
25 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 # POSSIBILITY OF SUCH DAMAGE.
37 #
38 # Revision $Id$
39 
40 PKG_NAME = 'rosweb'
41 import roslib; roslib.load_manifest(PKG_NAME)
42 
43 import getopt
44 import cStringIO
45 import os
46 import signal
47 import string
48 import sys
49 import threading
50 import time
51 import gzip
52 import traceback
53 import BaseHTTPServer
54 #import logging
55 
56 import BaseHTTPServer, select, socket, SocketServer, urlparse
57 SocketServer.ThreadingMixIn.daemon_threads = True
58 
59 import Cookie
60 import cgi
61 
62 import roslib.scriptutil
63 import rospy
64 import rosservice
65 import rosjson
66 
67 from rosservice import ROSServiceException
68 from genpy.message import MessageException
69 from roslib import rosenv
70 
71 import roslib.message
72 import roslib.rospack
73 
74 class ROSWebException(Exception): pass
75 
76 def splitTopic(topic):
77  parts = topic.split(":", 2)
78  topic = parts[0]
79  subtopic = None
80  params = None
81  if len(parts) >= 2:
82  subtopic = parts[1]
83  if len(parts) >= 3:
84  params = parts[2]
85  return topic, subtopic, params
86 
87 
88 ## Factory for ROSWebTopic instances
89 class RWTFactory(object):
90  def __init__(self, webserver):
91  self.map = {}
92  self.lock = threading.Lock()
93 
94  self.webserver = webserver
95 
96  self.counter = 1
97  self.cond = threading.Condition()
98 
99  def close(self):
100  try:
101  self.lock.acquire()
102  for topic in self.map.keys():
103  rwt = self.map[topic]
104  rwt.factory = None
105  rwt = None
106  del self.map[topic]
107  finally:
108  self.lock.release()
109 
110  def unsubscribe(self, topic):
111  try:
112  self.lock.acquire()
113  if topic in self.map:
114  del self.map[topic]
115  finally:
116  self.lock.release()
117 
118  def subscribe(self, topic):
119  maintopic, subtopic, params = splitTopic(topic)
120  main_rwt = None
121  try:
122  self.lock.acquire()
123  if topic in self.map:
124  return self.map[topic]
125  main_rwt = ROSWebTopic(maintopic, self)
126  self.map[maintopic] = main_rwt
127  rwt = main_rwt
128  if subtopic:
129  handlerClass = self.webserver._subtopics["%s:%s" % (maintopic, subtopic)]
130  rwt = handlerClass(topic, self, main_rwt)
131  self.map[topic] = rwt
132  finally:
133  self.lock.release()
134  return main_rwt
135 
136  def get(self, topic):
137  return self.map.get(topic, None)
138 
139  def registerVirtualTopic(self, topic, thread):
140  vt = VirtualTopic(topic, self, thread)
141  try:
142  self.lock.acquire()
143  self.map[topic] = vt
144  vt.init()
145  finally:
146  self.lock.release()
147 
148 
149 class ROSWebTopic(object):
150  def __init__(self, topic, factory):
151  self.topic = topic
152  self.initialized = False
153  self.sub = None
154  self.factory = factory
155 
156  self.last_message = None
157  self.messages = []
158  self.subtopics = []
159 
160  def init(self):
161  if self.initialized: return
162 
163  try:
164  self.factory.cond.acquire()
165  m = roslib.scriptutil.get_master()
166 
167  code, _, topics = m.getPublishedTopics('/'+PKG_NAME, '/')
168  if code != 1:
169  raise ROSWebException("unable to communicate with master")
170 
171  for t, topic_type in topics:
172  if t == self.topic: break
173  else:
174  raise ROSWebException("%s is not a published topic"%self.topic)
175 
176  msg_class = roslib.message.get_message_class(topic_type)
177 
178  #print "RosWebtopic", self.topic, msg_class
179  try:
180  self.sub = rospy.Subscriber(self.topic, msg_class, self.topic_callback)
181  except:
182  print self.topic, msg_class
183  raise
184  self.initialized = True
185  except ROSWebException:
186  raise
187  except Exception, e:
188  # fatal for now
189  rospy.signal_shutdown(str(e))
190  raise
191  finally:
192  self.factory.cond.release()
193 
194  def close(self):
195  self.factory = None
196  for rwt, subtopic in self.subtopics:
197  subtopic.close()
198 
199  def topic_callback(self, data):
200  try:
201  self.factory.cond.acquire()
202 
203  self.messages.append((self.factory.counter, data))
204  self.factory.counter = self.factory.counter + 1
205  self.messages = self.messages[-1:]
206 
207  for rwt, subtopic in self.subtopics:
208  rwt.subtopic_callback(data)
209 
210  self.factory.cond.notifyAll()
211  finally:
212  self.factory.cond.release()
213 
214  def subscribeSubTopic(self, rwt, subtopic):
215  self.subtopics.append((rwt, subtopic))
216 
217 
218 class ROSWebSubTopic(object):
219  def __init__(self, topic, factory, main_rwt):
220  self.factory = factory
221  self.topic = topic
222 
223  self.messages = []
224  self.maintopic, self.subtopic, params = splitTopic(topic)
225  main_rwt.subscribeSubTopic(self, self.subtopic)
226 
227  def init(self):
228  pass
229 
230  def subtopic_callback(self, msg):
231  ## no locks needed since this will be called from the main topic
232 
233  newmsg = self.transform(msg)
234 
235  if not newmsg: return
236 
237  self.messages.append((self.factory.counter, newmsg))
238  self.factory.counter = self.factory.counter + 1
239  self.messages = self.messages[-1:]
240 
241 
242 
243 
244 class VirtualTopic(object):
245  def __init__(self, topic, factory, thread, intopics=[]):
246  self.factory = factory
247  self.topic = topic
248  self.intopics = intopics
249 
250  self.messages = []
251 
252  self.thread = thread
253  self.initialized = False
254 
255  def init(self):
256  if not self.initialized:
257  for _topic in self.intopics:
258  self.factory.subscribe(_topic)
259 
260  self.initialized = True
261  self.thread.setCallback(self.callback)
262  self.thread.start()
263 
264  def callback(self, data):
265  try:
266  self.factory.cond.acquire()
267 
268  self.messages.append((self.factory.counter, data))
269  self.factory.counter = self.factory.counter + 1
270  self.messages = self.messages[-3:]
271 
272  self.factory.cond.notifyAll()
273  finally:
274  self.factory.cond.release()
275 
276 
277 class ROSWebHandler(BaseHTTPServer.BaseHTTPRequestHandler):
278  def __init__(self, *args):
279  self.failed_topics = []
280  BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args)
281 
282  def subscribe(self, topic):
283  rwt = self.server.factory.subscribe(topic)
284  try:
285  rwt.init()
286  except ROSWebException, e:
287  self.server.factory.unsubscribe(topic)
288  if topic not in self.failed_topics:
289  rospy.logwarn("Cannot subscribe to %s" % topic)
290  self.failed_topics.append(topic)
291  #traceback.print_exc()
292  return None
293  return rwt
294 
295  def _do_GET_topic(self, topics, since, nowait=False, callback=None):
296  rwttopics = []
297 
298  for topic in topics:
299  rwt = self.server.factory.get(topic)
300  if rwt:
301  rwttopics.append((topic, rwt))
302  else:
303  rwt = self.subscribe(topic)
304  if rwt: rwttopics.append((topic, rwt))
305 
306  if len(rwttopics) == 0:
307  rospy.logwarn("no valid topics")
308  self.send_failure()
309  return
310 
311  (messages, lastSince) = self._get_messages(rwttopics, since, nowait)
312 
313  buf = cStringIO.StringIO()
314  buf.write("{")
315  buf.write('"since": %s,' % lastSince)
316  buf.write('"msgs": [')
317  _i = 0
318  for (topic, msg) in messages:
319  _i = _i + 1
320  if _i > 1: buf.write(',')
321  buf.write("{")
322  buf.write('"topic": "%s",' % topic)
323  buf.write('"msg": ')
324  buf.write(rosjson.ros_message_to_json(msg))
325  buf.write("}")
326  buf.write(']')
327  buf.write('}')
328 
329  buf = buf.getvalue()
330 
331  self.send_success(buf, callback)
332 
333 
334  def _get_messages(self, rwttopics, since, nowait=False):
335  messages = []
336  lastSince = 0
337  try:
338  self.server.factory.cond.acquire()
339  # timeout?
340 
341  if since > self.server.factory.counter:
342  ## reset the since if it is invalid.
343  rospy.logerr("invalid since counter, reseting... %s" % (since, ))
344  since = 0
345 
346  ## check for some old messages first
347  lastSince = since
348  for topic, rwt in rwttopics:
349  if not rwt: continue
350  for t,msg in rwt.messages:
351  if t > since:
352  messages.append((topic, msg))
353  lastSince = max(t, lastSince)
354 
355  if nowait:
356  ## do not wait for message, for grabbing messages
357  return messages, lastSince
358 
359  ## if no old messages, then wait for a new one.
360  while not messages:
361  self.server.factory.cond.wait()
362 
363  # get the last message under lock
364  for topic, rwt in rwttopics:
365  if not rwt: continue
366  for t,msg in rwt.messages:
367  if t > lastSince:
368  messages.append((topic, msg))
369  lastSince = max(t, lastSince)
370  finally:
371  self.server.factory.cond.release()
372  return (messages, lastSince)
373 
374 
375  def _connect_to(self, netloc, soc):
376  i = netloc.find(':')
377  if i >= 0:
378  host_port = netloc[:i], int(netloc[i+1:])
379  else:
380  host_port = netloc, 80
381 # print "\t" "connect to %s:%d" % host_port
382  try: soc.connect(host_port)
383  except socket.error, arg:
384  try: msg = arg[1]
385  except:
386  msg = arg
387  self.send_error(404, msg)
388  return 0
389  return 1
390 
391  def _send_responsepage(self, retcode=200, buf = "{}", callback = None):
392  try:
393  self.send_response(retcode)
394  if callback:
395  #buf = callback + "(" + buf + "); var _xsajax$transport_status=200;"
396  buf = callback + "=" + buf + ";\nvar _xsajax$transport_status=200;"
397  self.send_header('Content-Type', 'text/javascript')
398  else:
399  self.send_header('Content-Type', 'application/json')
400 
401  if len(buf) > 500:
402  acceptEncoding = self.headers.get('Accept-Encoding', '')
403  if acceptEncoding.find('gzip') != -1:
404  zbuf = cStringIO.StringIO()
405  zfile = gzip.GzipFile(None, "wb", 9, zbuf)
406  zfile.write(buf)
407  zfile.close()
408 
409  nbuf = len(buf)
410  buf = zbuf.getvalue()
411  self.send_header('Content-encoding', 'gzip')
412 
413  self.send_header('Content-Length', str(len(buf)))
414 
415  if self.headers.get("Connection", '').lower() == "keep-alive":
416  self.send_header('Connection', 'keep-alive')
417 
418  self.send_header("Access-Control-Allow-Origin", "*") #"http://ta110.willowgarage.com")
419 
420  self.end_headers()
421 
422 
423  self.wfile.write(buf)
424  except socket.error, (ecode, reason):
425  if ecode == 32:
426  print ecode, reason
427  else:
428  raise
429 
430 
431  def send_success(self, buf = "{}", callback=None):
432  self._send_responsepage(200, buf, callback)
433 
434  def send_failure(self, buf = "{}", callback=None):
435  self._send_responsepage(404, buf, callback)
436 
437  def send_forbidden(self, buf = "{}", callback=None):
438  self._send_responsepage(403, buf, callback)
439 
440  def address_string(self):
441  host, port = self.client_address[:2]
442  return host
443 
444  def handle_ROS(self, path, qdict):
445  cstring = self.headers.get('Cookie', '')
446 
447  cookie = Cookie.BaseCookie()
448  cookie.load(cstring)
449 
450  path_parts = path.split("/")
451 
452  username = ""
453 
454  cmd = path_parts[2]
455 
456  ## parse out the username from the cookie
457  if cookie.has_key('MB_L1'):
458  l1 = cookie['MB_L1'].value
459  if l1.startswith("V1/"):
460  code = l1[3:]
461  parts = code.split(":", 1)
462  username = parts[0]
463 
464  ## Make a service call
465  ## Args can be passed as an ordered list of parameters:
466  ## /ros/service/<service_name>?args=<arg1>&args=<arg2>&<...>
467  ## or as a dictionary of named parameters
468  ## /ros/service/<service_name>?json=<json-encoded dictionary of args>
469  if cmd == "ping":
470  self.send_success("{'ping': %f}" % time.time())
471 
472  if cmd == "service":
473  name = "/".join(path_parts[3:])
474  callback = qdict.get("callback", [''])[0]
475 
476  try:
477  service_class = rosservice.get_service_class_by_name("/" + name)
478  except ROSServiceException:
479  self.send_failure()
480  return
481 
482  request = service_class._request_class()
483 
484  args = qdict.get('args', None)
485  if not args:
486  args = qdict.get('json', ['{}'])[0]
487  args = eval(args)
488  try:
489  now = rospy.get_rostime()
490  keys = { 'now': now, 'auto': rospy.Header(stamp=now) }
491  roslib.message.fill_message_args(request, args, keys=keys)
492  except MessageException:
493  raise ROSServiceException("Not enough arguments to call service.\n"+\
494  "Args should be: [%s], but are actually [%s] " %
495  (roslib.message.get_printable_message_args(request), args))
496 
497  rospy.logdebug("service call: name=%s, args=%s" % (name, args))
498  rospy.wait_for_service(name)
499  service_proxy = rospy.ServiceProxy(name, service_class)
500  try:
501  msg = service_proxy(request)
502  except rospy.ServiceException:
503  self.send_failure()
504  return
505  msg = rosjson.ros_message_to_json(msg)
506 
507  rospy.logdebug("service call: name=%s, resp=%s" % (name, msg))
508  self.send_success(msg, callback=callback)
509  return
510 
511  if cmd == "publish":
512  topic = string.join(path_parts[3:], "/")
513 
514  callback = qdict.get("callback", [''])[0]
515  topic_type = qdict.get("topic_type", [''])[0]
516 
517  message_klass = roslib.message.get_message_class(topic_type)
518 
519  message = message_klass()
520 
521  args = qdict.get('args', None)
522  if not args:
523  args = qdict.get('json', ['{}'])[0]
524  args = eval(args)
525  try:
526  now = rospy.get_rostime()
527  keys = { 'now': now, 'auto': rospy.Header(stamp=now) }
528  roslib.message.fill_message_args(message, args, keys=keys)
529  except MessageException:
530  raise ROSServiceException("Not enough arguments to call service.\n"+\
531  "Args should be: [%s], but are actually [%s] " %
532  (roslib.message.get_printable_message_args(message), args))
533 
534  rospy.logdebug("publish: topic=%s, topic_type=%s, args=%s" % (topic, topic_type, args))
535 
536  pub = rospy.Publisher(topic, message_klass, latch=True)
537 
538  try:
539  pub.publish(message)
540  except rospy.ServiceException:
541  self.send_failure()
542  return
543 
544  self.send_success(callback=callback)
545  return
546 
547  if cmd == "receive":
548  since = int(qdict.get('since', ['0'])[0])
549  topics = qdict.get("topic", "")
550  callback = qdict.get("callback", [''])[0]
551  nowait = int(qdict.get('nowait', ['0'])[0])
552  self._do_GET_topic(topics, since, nowait=nowait, callback=callback)
553  return
554 
555 
556 
557  def do_GET(self):
558  if get_robot_type().startswith("texas"):
559  try:
560  stored_cookie = open("/var/ros/user_cookie.dat").read()
561  request_cookie = self.headers.get('Cookie', '')
562  if stored_cookie.find(request_cookie) == -1:
563  rospy.logwarn("cookie did not match stored cookie \n%s\n%s" % (stored_cookie, request_cookie))
564  self.send_forbidden()
565  return
566  except:
567  self.send_forbidden()
568  return
569 
570  (scm, netloc, path, params, query, fragment) = urlparse.urlparse(
571  self.path, 'http')
572  qdict = cgi.parse_qs(query)
573  pdict = cgi.parse_qs(str(self.rfile._rbuf))
574  qdict.update(pdict)
575 
576  self.log_request()
577 
578  for handler in self.server._handlers:
579  if path.startswith(handler['url']):
580  handler['handler'](self, path, qdict)
581  return
582 
583  netloc = "localhost:80"
584  scm = "http"
585 
586  soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
587  try:
588  if self._connect_to(netloc, soc):
589  soc.send("%s %s %s\r\n" % (
590  self.command,
591  urlparse.urlunparse(('', '', path, params, query, '')),
592  self.request_version))
593  self.headers['Connection'] = 'close'
594  del self.headers['Proxy-Connection']
595  for key_val in self.headers.items():
596  soc.send("%s: %s\r\n" % key_val)
597  soc.send("\r\n")
598  self._read_write(soc)
599  finally:
600  soc.close()
601  self.connection.close()
602 
603 
604  def _read_write(self, soc, max_idling=20):
605  iw = (self.connection, soc)
606  ow = ()
607  count = 0
608 
609  while 1:
610  count += 1
611  (ins, _, exs) = select.select(iw, ow, iw, 3)
612  if exs: break
613  if ins:
614  for i in ins:
615  if i is soc:
616  out = self.connection
617  elif i is self.connection:
618  out = soc
619  else:
620  print "error"
621  data = i.recv(8192)
622  if data:
623  bytes_sent = 0
624  while bytes_sent != len(data):
625  n = out.send(data[bytes_sent:])
626  bytes_sent += n
627  count = 0
628  else:
629  pass
630  if count == max_idling: break
631 
632  do_POST = do_GET
633  do_OPTIONS = do_GET
634 
635  def log_message(self, format, *args):
636  self.server.accesslog_fp.write("%s - - [%s] %s\n" %
637  (self.address_string(),
638  self.log_date_time_string(),
639  format%args))
640  self.server.accesslog_fp.flush()
641 
642 
644  def run(self):
645  global running
646  master = roslib.scriptutil.get_master()
647  while running:
648  try:
649  master.getSystemState('/rostopic')
650  except:
651  import traceback
652  #traceback.print_exc()
653  return
654  time.sleep(1)
655 
656 class ThreadingHTTPServer (threading.Thread,
657  SocketServer.ThreadingMixIn,
658  BaseHTTPServer.HTTPServer):
659  def __init__(self, hostport, handlerClass):
660  threading.Thread.__init__(self)
661  SocketServer.TCPServer.__init__(self, hostport, handlerClass)
662 
663  self.factory = RWTFactory(self)
664 
665  logfn = os.path.join(rosenv.get_log_dir(), "access_log")
666  self.accesslog_fp = open(logfn, "a+")
667 
668  self._handlers = []
669  self.register_handler('/ros', ROSWebHandler.handle_ROS)
670 
671  self._subtopics = {}
672 
673  self.__load_plugins()
675 
676  def register_handler(self, urlprefix, handler):
677  h = {'url': urlprefix, 'handler': handler}
678  self._handlers.append(h)
679 
680  def register_subtopic(self, topic, handlerClass):
681  self._subtopics[topic] = handlerClass
682 
683  def __load_plugins(self):
684  plugins = roslib.rospack.rospack_plugins(PKG_NAME)
685  for (package, plugin) in plugins:
686  try:
687  roslib.load_manifest(package)
688  mods = plugin.split('.')
689  mod = __import__(plugin)
690  for sub_mod in mods[1:]:
691  mod = getattr(mod, sub_mod)
692 
693  mod.config_plugin(self)
694 
695  except Exception, reason:
696  rospy.logerr("plugin %s got exception %s" % (plugin, reason))
697 
698 
700  import topics
701  ut = topics.TopicThread()
702  ut.setDaemon(True)
703  self.factory.registerVirtualTopic("/topics", ut)
704 
705  import params
706  ut = params.ParamThread()
707  ut.setDaemon(True)
708  self.factory.registerVirtualTopic("/parameters", ut)
709 
710  def run(self):
711  while 1:
712  self.handle_request()
713 
715  web_server = None
716  mm = None
717 
718  try:
719  rospy.init_node(PKG_NAME, disable_signals=True)
720 
721  web_server = ThreadingHTTPServer(('', 8068), ROSWebHandler)
722 
723  web_server.setDaemon(True)
724  web_server.start()
725  rospy.loginfo("starting Web server")
726 
727  mm = MasterMonitor()
728  mm.run()
729 
730  finally:
731  rospy.signal_shutdown(PKG_NAME + ' exiting')
732  if web_server: web_server.server_close()
733 
734 error_log_fp = None
735 
736 def signal_handler(signal, frame):
737  global running
738  running = False
739 
740 def usage(progname):
741  print __doc__ % vars()
742 
743 
745  try:
746  return open(os.path.join("/etc/ros/env", "ROBOT")).read().strip()
747  except IOError:
748  return "desktop"
749 
750 def main(argv, stdout, environ):
751  progname = argv[0]
752  optlist, args = getopt.getopt(argv[1:], "", ["help", "debug"])
753 
754  debugFlag = False
755  for (field, val) in optlist:
756  if field == "--help":
757  usage(progname)
758  return
759  elif field == "--debug":
760  debugFlag = True
761 
762  global running, error_log
763  running = True
764  #if debugFlag:
765  # logging.basicConfig(level=logging.DEBUG)
766  # pass
767  #else:
768  # logging.basicConfig(filename="error_log", level=logging.DEBUG)
769 
770  signal.signal(signal.SIGINT, signal_handler)
771 
772 
773  while running:
774  rospy.loginfo("starting")
775  try:
776  rosweb_start()
777  except:
778  import traceback
779  traceback.print_exc()
780  time.sleep(1)
781 
782  if error_log_fp: error_log_fp.close()
783 
784 if __name__ == '__main__':
785  main(sys.argv, sys.stdout, os.environ)
def _do_GET_topic(self, topics, since, nowait=False, callback=None)
Definition: rosweb.py:295
def __registerVirtualTopics(self)
Definition: rosweb.py:699
def subtopic_callback(self, msg)
Definition: rosweb.py:230
def subscribeSubTopic(self, rwt, subtopic)
Definition: rosweb.py:214
def close(self)
Definition: rosweb.py:99
def _send_responsepage(self, retcode=200, buf="{}", callback=None)
Definition: rosweb.py:391
def get(self, topic)
Definition: rosweb.py:136
def __init__(self, hostport, handlerClass)
Definition: rosweb.py:659
def topic_callback(self, data)
Definition: rosweb.py:199
def __init__(self, args)
Definition: rosweb.py:278
def main(argv, stdout, environ)
Definition: rosweb.py:750
def ros_message_to_json(msg)
def send_forbidden(self, buf="{}", callback=None)
Definition: rosweb.py:437
def unsubscribe(self, topic)
Definition: rosweb.py:110
def close(self)
Definition: rosweb.py:194
def rosweb_start()
Definition: rosweb.py:714
def registerVirtualTopic(self, topic, thread)
Definition: rosweb.py:139
def address_string(self)
Definition: rosweb.py:440
def init(self)
Definition: rosweb.py:227
Factory for ROSWebTopic instances.
Definition: rosweb.py:89
def _connect_to(self, netloc, soc)
Definition: rosweb.py:375
def init(self)
Definition: rosweb.py:160
def register_subtopic(self, topic, handlerClass)
Definition: rosweb.py:680
def __init__(self, webserver)
Definition: rosweb.py:90
def do_GET(self)
Definition: rosweb.py:557
def _read_write(self, soc, max_idling=20)
Definition: rosweb.py:604
def register_handler(self, urlprefix, handler)
Definition: rosweb.py:676
def run(self)
Definition: rosweb.py:644
def __init__(self, topic, factory)
Definition: rosweb.py:150
def callback(self, data)
Definition: rosweb.py:264
def __init__(self, topic, factory, main_rwt)
Definition: rosweb.py:219
def _get_messages(self, rwttopics, since, nowait=False)
Definition: rosweb.py:334
def usage(progname)
Definition: rosweb.py:740
def handle_ROS(self, path, qdict)
Definition: rosweb.py:444
def log_message(self, format, args)
Definition: rosweb.py:635
def __init__(self, topic, factory, thread, intopics=[])
Definition: rosweb.py:245
def signal_handler(signal, frame)
Definition: rosweb.py:736
messages
no locks needed since this will be called from the main topic
Definition: rosweb.py:223
def send_failure(self, buf="{}", callback=None)
Definition: rosweb.py:434
def __load_plugins(self)
Definition: rosweb.py:683
def subscribe(self, topic)
Definition: rosweb.py:118
def get_robot_type()
Definition: rosweb.py:744
def subscribe(self, topic)
Definition: rosweb.py:282
def splitTopic(topic)
Definition: rosweb.py:76
def send_success(self, buf="{}", callback=None)
Definition: rosweb.py:431
def init(self)
Definition: rosweb.py:255


rosweb
Author(s): Scott Noob Hassan, Rob Wheeler, Nate Koenig
autogenerated on Mon Jun 10 2019 15:51:19