--- a/schedule_viewer.py +++ b/schedule_viewer.py @@ -22,6 +22,9 @@ import BaseHTTPServer, sys, urlparse +from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler +from SocketServer import ThreadingMixIn +import threading import bisect from gtfsscheduleviewer.marey_graph import MareyGraph import gtfsscheduleviewer @@ -57,34 +60,8 @@ return list(iterable) return simplejson.JSONEncoder.default(self, obj) -# Code taken from -# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/425210/index_txt -# An alternate approach is shown at -# http://mail.python.org/pipermail/python-list/2003-July/212751.html -# but it requires multiple threads. A sqlite object can only be used from one -# thread. -class StoppableHTTPServer(BaseHTTPServer.HTTPServer): - def server_bind(self): - BaseHTTPServer.HTTPServer.server_bind(self) - self.socket.settimeout(1) - self._run = True - - def get_request(self): - while self._run: - try: - sock, addr = self.socket.accept() - sock.settimeout(None) - return (sock, addr) - except socket.timeout: - pass - - def stop(self): - self._run = False - - def serve(self): - while self._run: - self.handle_request() - +class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): + """Handle requests in a separate thread.""" def StopToTuple(stop): """Return tuple as expected by javascript function addStopMarkerFromList""" @@ -254,9 +231,11 @@ parsed_params['time'] = int(round(float(parsed_params['time']),-2)) paramkey = tuple(sorted(parsed_params.items())) if handler_name in self.cache and paramkey in self.cache[handler_name] : - print ("Cache hit for ",handler_name," params ",parsed_params) + print ("Cache hit for ",handler_name," params ",parsed_params, + " thread ", threading.currentThread().getName()) else: - print ("Cache miss for ",handler_name," params ",parsed_params) + print ("Cache miss for ",handler_name," params ",parsed_params, + " thread ", threading.currentThread().getName()) result = handler(parsed_params) if not handler_name in self.cache: self.cache[handler_name] = {} @@ -282,6 +261,23 @@ result.sort(key = lambda x: x[1:3]) return result + def handle_json_GET_routesearch(self, params): + """Return a list of routes with matching short name.""" + schedule = self.server.schedule + routeshortname = params.get('routeshortname', None) + result = [] + for r in schedule.GetRouteList(): + if r.route_short_name == routeshortname: + servicep = None + for t in schedule.GetTripList(): + if t.route_id == r.route_id: + servicep = t.service_period + break + result.append( (r.route_id, r.route_short_name, r.route_long_name, servicep.service_id) ) + result.sort(key = lambda x: x[1:3]) + return result + + def handle_json_GET_routerow(self, params): schedule = self.server.schedule route = schedule.GetRoute(params.get('route', None)) @@ -299,8 +295,19 @@ except: print "Error for GetStartTime of trip #" + t.trip_id + sys.exc_info()[0] else: - result.append ( (starttime, t.trip_id) ) - return sorted(result, key=lambda trip: trip[0]) + cursor = t._schedule._connection.cursor() + cursor.execute( + 'SELECT arrival_secs,departure_secs FROM stop_times WHERE ' + 'trip_id=? ORDER BY stop_sequence DESC LIMIT 1', (t.trip_id,)) + (arrival_secs, departure_secs) = cursor.fetchone() + if arrival_secs != None: + endtime = arrival_secs + elif departure_secs != None: + endtime = departure_secs + else: + endtime =0 + result.append ( (starttime, t.trip_id, endtime) ) + return sorted(result, key=lambda trip: trip[2]) def handle_json_GET_triprows(self, params): """Return a list of rows from the feed file that are related to this @@ -477,8 +484,8 @@ result = {} for trip in trips: route = schedule.GetRoute(trip.route_id) - if not trip.route_short_name+route.route_long_name in result: - result[trip.route_short_name+route.route_long_name] = (route.route_id, route.route_short_name, route.route_long_name, trip.trip_id) + if not route.route_short_name+route.route_long_name+trip.service_id in result: + result[route.route_short_name+route.route_long_name+trip.service_id] = (route.route_id, route.route_short_name, route.route_long_name, trip.trip_id, trip.service_id) return result def handle_json_GET_stopalltrips(self, params): @@ -509,6 +516,8 @@ if service_period == None or trip.service_id == service_period: result.append((time, (trip.trip_id, trip_name, trip.service_id), tp)) return result + + def handle_json_GET_stoptrips(self, params): """Given a stop_id and time in seconds since midnight return the next @@ -683,14 +692,13 @@ t0 = datetime.datetime.now() schedule.Load(options.feed_filename) print ("Loaded in", (datetime.datetime.now() - t0).seconds , "seconds") - server = StoppableHTTPServer(server_address=('', options.port), + server = ThreadedHTTPServer(server_address=('', options.port), RequestHandlerClass=RequestHandlerClass) server.key = options.key server.schedule = schedule server.file_dir = options.file_dir server.host = options.host - server.feed_path = options.feed_filename - + server.feed_path = options.feed_filename print ("To view, point your browser at http://localhost:%d/" %