00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 import re
00018 import cgi
00019 import json
00020 from urlparse import urlparse, parse_qs
00021 from BaseHTTPServer import BaseHTTPRequestHandler
00022
00023 from include.logger import Log
00024 from include.constants import SEPARATOR_CHAR, DEFAULT_CONTEXT_TYPE
00025 from include.confManager import getRobots
00026 from include.ros.rosutils import ros2Definition
00027 from include.ros.rosConfigurator import RosConfigurator, setWhiteList
00028 from include.ros.topicHandler import TopicHandler, loadMsgHandlers, ROBOT_TOPICS
00029 from include.pubsub.pubSubFactory import SubscriberFactory, QueryBuilderFactory
00030
00031 CloudSubscriber = SubscriberFactory.create()
00032 CloudQueryBulder = QueryBuilderFactory.create()
00033
00034 TOPIC_TIMESTAMPS = {}
00035
00036
00037 class RequestHandler(BaseHTTPRequestHandler):
00038
00039 def do_GET(self):
00040
00041
00042 path = urlparse("http://localhost" + self.path).path
00043 action = getAction(path, "GET")
00044 if action is not None:
00045 action["action"](self, action)
00046 else:
00047 self.send_response(200)
00048 self.send_header('Content-type', 'text/html')
00049 self.end_headers()
00050 self.wfile.write("GENERIC PAGE")
00051 return
00052
00053 def do_POST(self):
00054
00055
00056 path = urlparse("http://localhost" + self.path).path
00057 action = getAction(path, "POST")
00058 if action is not None:
00059 action["action"](self, action)
00060 else:
00061 self.send_response(200)
00062 self.send_header('Content-type', 'text/html')
00063 self.end_headers()
00064 self.wfile.write("GENERIC PAGE")
00065 return
00066
00067
00068 def pathParams(request, regexp):
00069
00070
00071
00072 return list(re.match(regexp, urlparse("http://localhost" + request.path).path).groups())
00073
00074
00075 def getParams(request):
00076
00077
00078 return parse_qs(urlparse("http://localhost" + request.path).query)
00079
00080
00081 def postParams(request):
00082
00083
00084 ctype, pdict = cgi.parse_header(request.headers.getheader('content-type'))
00085 if ctype == 'multipart/form-data':
00086 return cgi.parse_multipart(request.rfile, pdict)
00087 elif ctype == 'application/x-www-form-urlencoded':
00088 length = int(request.headers.getheader('content-length'))
00089 return cgi.parse_qs(request.rfile.read(length), keep_blank_values=1)
00090 elif ctype == 'application/json':
00091 json_data = request.rfile.read(int(request.headers['Content-Length']))
00092 return json.loads(json_data)
00093 else:
00094 return {}
00095
00096
00097 def getAction(path, method):
00098
00099
00100
00101 for route in MAPPER[method]:
00102 if re.search(route['regexp'], path):
00103 return route
00104 return None
00105
00106
00107
00108
00109
00110
00111 def onTopic(request, action):
00112
00113
00114
00115 try:
00116 contexts = postParams(request)
00117 contexts = contexts['contextResponses']
00118 for context in contexts:
00119 if context['statusCode']['code'] == "200":
00120 robot = context['contextElement']
00121 robotName = robot['id']
00122 if robotName not in TOPIC_TIMESTAMPS:
00123 TOPIC_TIMESTAMPS[robotName] = {}
00124 for topic in robot['attributes']:
00125 if topic["name"] == "COMMAND":
00126 commands = topic["value"]
00127 robot['attributes'].remove(topic)
00128 break
00129 for topic in robot['attributes']:
00130 if topic["name"] != "descriptions" and topic["name"] in commands:
00131 value = CloudSubscriber.parseData(topic['value'])
00132 if (topic["name"] not in TOPIC_TIMESTAMPS[robotName]) or ("firosstamp" in value and TOPIC_TIMESTAMPS[robotName][topic["name"]] != value["firosstamp"]) or ("firosstamp" not in value):
00133 if "firosstamp" in value:
00134 TOPIC_TIMESTAMPS[robotName][topic["name"]] = value["firosstamp"]
00135
00136 TopicHandler.publish(robotName, topic['name'], value)
00137 except Exception as e:
00138 Log("ERROR", e)
00139 request.send_response(200)
00140 request.send_header('Content-type', 'text/plain')
00141 request.end_headers()
00142 request.wfile.write("Received by firos")
00143
00144
00145 def onRobots(request, action):
00146
00147
00148
00149 robots = getRobots(False, True)
00150 data = []
00151 for robot_name in robots.keys():
00152 robot_data = {"name": robot_name, "topics": []}
00153 robot = robots[robot_name]
00154 for topic_name in robot["topics"]:
00155 topic = robot["topics"][topic_name]
00156 topic_data = {
00157 "name": topic_name,
00158 "pubsub": topic["type"]
00159 }
00160 if type(topic["msg"]) is dict:
00161 topic_data["type"] = "Custom"
00162 topic_data["structure"] = topic["msg"]
00163 else:
00164 topic_data["type"] = topic["msg"]
00165 topic_data["structure"] = ros2Definition(ROBOT_TOPICS[robot_name][topic["type"]][topic_name]["class"]())
00166 robot_data["topics"].append(topic_data)
00167 data.append(robot_data)
00168 request.send_response(200)
00169 request.send_header('Content-type', 'application/json')
00170 setCors(request)
00171 request.end_headers()
00172 request.wfile.write(json.dumps(data))
00173
00174
00175 def onRobotData(request, action):
00176
00177
00178
00179 robot_name = pathParams(request, action["regexp"])[0]
00180 data = CloudQueryBulder.findById(robot_name, "ROBOT", False)
00181 if "errorCode" in data:
00182 request.send_response(int(data["errorCode"]["code"]))
00183 else:
00184 request.send_response(200)
00185 robot_list = []
00186 for context in data["contextResponses"]:
00187 for attribute in context["contextElement"]["attributes"]:
00188 if attribute["name"] != "COMMAND" and attribute["name"] != "descriptions":
00189 print attribute["name"]
00190 print attribute["value"]
00191 attribute["value"] = json.loads(attribute["value"].replace(SEPARATOR_CHAR, '"'))
00192 context["contextElement"].pop("isPattern", None)
00193 robot_list.append(context["contextElement"])
00194 data = robot_list
00195
00196 request.send_header('Content-type', 'application/json')
00197 setCors(request)
00198
00199 request.end_headers()
00200 request.wfile.write(json.dumps(data))
00201
00202
00203 def onConnect(request, action):
00204
00205
00206
00207 Log("INFO", "Connecting robots")
00208 loadMsgHandlers(RosConfigurator.systemTopics(True))
00209 request.send_response(200)
00210 request.end_headers()
00211 request.wfile.write("")
00212
00213
00214 def onDisConnect(request, action):
00215
00216
00217
00218 robot_name = pathParams(request, action["regexp"])[0]
00219 Log("INFO", "Disconnecting robot" + robot_name)
00220 if robot_name in ROBOT_TOPICS:
00221 CloudSubscriber.deleteEntity(robot_name, DEFAULT_CONTEXT_TYPE)
00222 CloudSubscriber.disconnect(robot_name, True)
00223 for topic in ROBOT_TOPICS[robot_name]["publisher"]:
00224 ROBOT_TOPICS[robot_name]["publisher"][topic]["publisher"].unregister()
00225 for topic in ROBOT_TOPICS[robot_name]["subscriber"]:
00226 ROBOT_TOPICS[robot_name]["subscriber"][topic]["subscriber"].unregister()
00227 RosConfigurator.removeRobot(robot_name)
00228 request.send_response(200)
00229 request.end_headers()
00230 request.wfile.write("")
00231
00232
00233 def onWhitelistWrite(request, action):
00234
00235
00236
00237 data = postParams(request)
00238 setWhiteList(data, None)
00239 request.send_response(200)
00240 request.end_headers()
00241 request.wfile.write("")
00242
00243
00244 def onWhitelistRemove(request, action):
00245
00246
00247
00248 data = postParams(request)
00249 setWhiteList(None, data)
00250 request.send_response(200)
00251 request.end_headers()
00252 request.wfile.write("")
00253
00254
00255 def onWhitelistRestore(request, action):
00256
00257
00258
00259 setWhiteList(None, None, True)
00260 request.send_response(200)
00261 request.end_headers()
00262 request.wfile.write("")
00263
00264
00265
00266
00267
00268
00269 MAPPER = {
00270 "GET": [
00271 {"regexp": "^/robots/*$", "action": onRobots},
00272 {"regexp": "^/robot/(\w+)/*$", "action": onRobotData}],
00273 "POST": [
00274 {"regexp": "^/firos/*$", "action": onTopic},
00275 {"regexp": "^/robot/connect/*$", "action": onConnect},
00276 {"regexp": "^/robot/disconnect/(\w+)/*$", "action": onDisConnect},
00277 {"regexp": "^/whitelist/write/*$", "action": onWhitelistWrite},
00278 {"regexp": "^/whitelist/remove/*$", "action": onWhitelistRemove},
00279 {"regexp": "^/whitelist/restore/*$", "action": onWhitelistRestore}],
00280 "PUT": [],
00281 "DELETE": [],
00282 }
00283
00284
00285 def setCors(request):
00286
00287
00288 request.send_header("Access-Control-Allow-Credentials", True)
00289 request.send_header("Access-Control-Allow-Headers", "api-version, content-length, content-md5, content-type, date, request-id, response-time")
00290 request.send_header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE")
00291 request.send_header("Access-Control-Expose-Headers", "api-version, content-length, content-md5, content-type, date, request-id, response-time")
00292 request.send_header("Access-Control-Allow-Origin", "*")