Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 import logging
00038
00039 import socket
00040 import tornado.ioloop
00041 import tornado.web
00042 from .webrequest_handler import WebRequestHandler
00043 from .utils import run_shellcommand, split_words, get_packages
00044
00045 class ROSWWWServer():
00046
00047 def __init__(self, name, webpath, ports):
00048 '''
00049 :param str name: webserver name
00050 :param str webpath: package relative path to web page source.
00051 :param tuple ports: ports to use in webserver. Provides default and scan range (default, start, end)
00052 '''
00053 self._name = name
00054 self._webpath = webpath
00055 self._ports = ports
00056 self._logger = self._set_logger()
00057 self._packages = get_packages()
00058 self._application = self._create_webserver(self._packages)
00059
00060 def _create_webserver(self, packages):
00061 '''
00062 @type packages: {str, str}
00063 @param packages: name and path of ROS packages.
00064 '''
00065 handlers = [(r"/", WebRequestHandler, {"packages": packages})]
00066
00067 for package in packages:
00068 handler_root = ("/" + package['name'] + "/?()",
00069 tornado.web.StaticFileHandler,
00070 {"path": package['path'] + "/" + self._webpath + "/index.html"})
00071 handlers.append(handler_root)
00072 handler = ("/" + package['name'] + "/(.*)",
00073 tornado.web.StaticFileHandler,
00074 {"path": package['path'] + "/" + self._webpath,
00075 "default_filename": "index.html"})
00076 handlers.append(handler)
00077
00078 self.loginfo("# of packages : %s"%(len(packages)))
00079 self.loginfo("Weg Page root : %s"%(self._webpath))
00080 application = tornado.web.Application(handlers)
00081 return application
00082
00083 def _bind_webserver(self):
00084 default, start, end = self._ports
00085
00086 """ First, we try the default http port """
00087 bound = self._bind_to_port(self._application, default)
00088 if not bound:
00089 """ Otherwise bind any available port within the specified range """
00090 bound = self._bind_in_range(self._application, start, end)
00091 return True
00092
00093 def _bind_in_range(self, application, start_port, end_port):
00094 if (end_port > start_port):
00095 for i in range(start_port, end_port):
00096 if self._bind_to_port(application, i):
00097 return True
00098 return False
00099
00100 def _bind_to_port(self, application, portno):
00101 self.loginfo("Attempting to start webserver on port %s"%portno)
00102 try:
00103 application.listen(portno)
00104 self.loginfo("Webserver successfully started on port %s"%portno)
00105 except socket.error as err:
00106
00107 if err.errno == 13:
00108 self.logwarn("Insufficient priveliges to run webserver " +
00109 "on port %s. Error: %s"%(portno, err.strerror))
00110 self.loginfo("-- Try re-running as super-user: sudo su; " +
00111 "source ~/.bashrc)")
00112 elif err.errno == 98:
00113 self.logwarn("There is already a webserver running on port %s. " +
00114 "Error: %s"%(portno, err.strerror))
00115 self.loginfo("-- Try stopping your web server. For example, " +
00116 "to stop apache: sudo /etc/init.d/apache2 stop")
00117 else:
00118 self.logerr("An error occurred attempting to listen on " +
00119 "port %s: %s"%(portno, err.strerror))
00120 return False
00121 return True
00122
00123 def _start_webserver(self):
00124 try:
00125 tornado.ioloop.IOLoop.instance().start()
00126 except KeyboardInterrupt:
00127 self.loginfo("Webserver shutting down")
00128
00129 def spin(self):
00130 try:
00131 bound = self._bind_webserver()
00132 if bound:
00133 self._start_webserver()
00134 else:
00135 raise Exception()
00136 except Exception as exc:
00137 self.logerr("Unable to bind webserver. Exiting. %s" % exc)
00138
00139 def _set_logger(self):
00140 logger = logging.getLogger('roswww')
00141 logger.setLevel(logging.DEBUG)
00142
00143
00144 ch = logging.StreamHandler()
00145 ch.setLevel(logging.DEBUG)
00146
00147
00148 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
00149
00150
00151 ch.setFormatter(formatter)
00152
00153
00154 logger.addHandler(ch)
00155
00156 return logger
00157
00158
00159 def loginfo(self, msg):
00160 self._logger.info('%s : %s'%(self._name, msg))
00161
00162 def logwarn(self, msg):
00163 self._logger.warning('%s : %s'%(self._name, msg))
00164
00165 def logerr(self, msg):
00166 self._logger.error('%s : %s'%(self._name, msg))