lib/gtfs/realtime.rb in gtfs-realtime-0.3.0 vs lib/gtfs/realtime.rb in gtfs-realtime-0.4.0

- old
+ new

@@ -1,10 +1,24 @@ require "google/transit/gtfs-realtime.pb" require "gtfs" -require "sequel" +require "active_record" +require "bulk_insert" +require "gtfs/gtfs_gem_patch" require "gtfs/realtime/configuration" +require "gtfs/realtime/model" +require "gtfs/realtime/calendar_date" +require "gtfs/realtime/route" +require "gtfs/realtime/service_alert" +require "gtfs/realtime/shape" +require "gtfs/realtime/stop" +require "gtfs/realtime/stop_time" +require "gtfs/realtime/stop_time_update" +require "gtfs/realtime/trip" +require "gtfs/realtime/trip_update" +require "gtfs/realtime/vehicle_position" +require "gtfs/realtime/version" module GTFS class Realtime # This is a singleton object, so everything will be on the class level class << self @@ -15,11 +29,176 @@ end def configure yield(configuration) + run_migrations load_static_feed! refresh_realtime_feed! + end + + def load_static_feed!(force: false) + return if !force && GTFS::Realtime::Route.count > 0 + + static_data = GTFS::Source.build(@configuration.static_feed) + return unless static_data + + GTFS::Realtime::Model.transaction do + GTFS::Realtime::CalendarDate.delete_all + GTFS::Realtime::CalendarDate.bulk_insert(values: + static_data.calendar_dates.collect do |calendar_date| + { + service_id: calendar_date.service_id.strip, + date: Date.strptime(calendar_date.date, "%Y%m%d"), + exception_type: calendar_date.exception_type + } + end + ) + + GTFS::Realtime::Route.delete_all + GTFS::Realtime::Route.bulk_insert(:id, :short_name, :long_name, :url, values: + static_data.routes.collect do |route| + { + id: route.id.strip, + short_name: route.short_name, + long_name: route.long_name, + url: route.url + } + end + ) + + GTFS::Realtime::Shape.delete_all + GTFS::Realtime::Shape.bulk_insert(:id, :sequence, :latitude, :longitude, values: + static_data.shapes.collect do |shape| + { + id: shape.id.strip, + sequence: shape.pt_sequence, + latitude: shape.pt_lat.to_f, + longitude: shape.pt_lon.to_f + } + end + ) + + GTFS::Realtime::Stop.delete_all + GTFS::Realtime::Stop.bulk_insert(:id, :name, :latitude, :longitude, values: + static_data.stops.collect do |stop| + { + id: stop.id.strip, + name: stop.name.strip, + latitude: stop.lat.to_f, + longitude: stop.lon.to_f + } + end + ) + + GTFS::Realtime::StopTime.delete_all + GTFS::Realtime::StopTime.bulk_insert(values: + static_data.stop_times.collect do |stop_time| + { + stop_id: stop_time.stop_id.strip, + trip_id: stop_time.trip_id.strip, + arrival_time: stop_time.arrival_time, + departure_time: stop_time.departure_time, + stop_sequence: stop_time.stop_sequence.to_i + } + end + ) + + GTFS::Realtime::Trip.delete_all + GTFS::Realtime::Trip.bulk_insert(:id, :headsign, :route_id, :service_id, :shape_id, :direction_id, values: + static_data.trips.collect do |trip| + { + id: trip.id.strip, + headsign: trip.headsign.strip, + route_id: trip.route_id.strip, + service_id: trip.service_id.strip, + shape_id: trip.shape_id.strip, + direction_id: trip.direction_id + } + end + ) + end + end + + def refresh_realtime_feed! + trip_updates = get_entities(@configuration.trip_updates_feed) + vehicle_positions = get_entities(@configuration.vehicle_positions_feed) + service_alerts = get_entities(@configuration.service_alerts_feed) + + GTFS::Realtime::Model.transaction do + GTFS::Realtime::TripUpdate.delete_all + GTFS::Realtime::TripUpdate.bulk_insert(:id, :trip_id, :route_id, values: + trip_updates.collect do |trip_update| + { + id: trip_update.id.strip, + trip_id: trip_update.trip_update.trip.trip_id.strip, + route_id: trip_update.trip_update.trip.route_id.strip + } + end + ) + + GTFS::Realtime::StopTimeUpdate.delete_all + GTFS::Realtime::StopTimeUpdate.bulk_insert(values: + trip_updates.collect do |trip_update| + trip_update.trip_update.stop_time_update.collect do |stop_time_update| + { + trip_update_id: trip_update.id.strip, + stop_id: stop_time_update.stop_id.strip, + arrival_delay: stop_time_update.arrival ? stop_time_update.arrival.delay : nil, + arrival_time: stop_time_update.arrival ? Time.at(stop_time_update.arrival.time) : nil, + departure_delay: stop_time_update.departure ? stop_time_update.departure.delay : nil, + departure_time: stop_time_update.departure ? Time.at(stop_time_update.departure.time) : nil, + } + end + end.flatten + ) + + GTFS::Realtime::VehiclePosition.delete_all + GTFS::Realtime::VehiclePosition.bulk_insert(values: + vehicle_positions.collect do |vehicle| + { + trip_id: vehicle.vehicle.trip.trip_id.strip, + stop_id: vehicle.vehicle.stop_id.strip, + latitude: vehicle.vehicle.position.latitude.to_f, + longitude: vehicle.vehicle.position.longitude.to_f, + bearing: vehicle.vehicle.position.bearing.to_f, + timestamp: Time.at(vehicle.vehicle.timestamp) + } + end + ) + + GTFS::Realtime::ServiceAlert.delete_all + GTFS::Realtime::ServiceAlert.bulk_insert(values: + service_alerts.collect do |service_alert| + { + stop_id: service_alert.alert.informed_entity.first.stop_id.strip, + header_text: service_alert.alert.header_text.translation.first.text, + description_text: service_alert.alert.description_text.translation.first.text, + start_time: Time.at(service_alert.alert.active_period.first.start), + end_time: Time.at(service_alert.alert.active_period.first.end) + } + end + ) + end + end + + private + + def get_entities(path) + return [] if path.nil? + + if File.exists?(path) + data = File.open(path, 'r'){|f| f.read} + else + data = Net::HTTP.get(URI.parse(path)) + end + feed = Transit_realtime::FeedMessage.decode(data) + feed.entity # array of entities + end + + def run_migrations + ActiveRecord::Migration.verbose = false + ActiveRecord::Migrator.migrate(File.expand_path("../realtime/migrations", __FILE__)) end end end end