rockhill_myride.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // SPDX-FileCopyrightText: Adam Evyčędo
  2. //
  3. // SPDX-License-Identifier: AGPL-3.0-or-later
  4. package traffic
  5. import (
  6. "bufio"
  7. "encoding/csv"
  8. "fmt"
  9. "io"
  10. "net/http"
  11. "os"
  12. "path/filepath"
  13. "time"
  14. "golang.org/x/text/transform"
  15. )
  16. type RockHillMyRide struct {
  17. client http.Client
  18. }
  19. func (RockHillMyRide) getTimezone() *time.Location {
  20. l, _ := time.LoadLocation("America/New_York")
  21. return l
  22. }
  23. func (g RockHillMyRide) ConvertVehicles() ([]Vehicle, error) {
  24. return []Vehicle{}, nil
  25. }
  26. func (z RockHillMyRide) GetVersions(_ time.Time, timezone *time.Location) ([]Version, error) {
  27. version, err := MakeVersionTimezone("00000101_99991231", timezone)
  28. if err != nil {
  29. return nil, err
  30. }
  31. version.Link = "https://rapid.nationalrtap.org/GTFSFileManagement/UserUploadFiles/11718/myriderockhill-sc-us.zip"
  32. return []Version{version}, nil
  33. }
  34. func (RockHillMyRide) String() string {
  35. return "rockhill_myride"
  36. }
  37. func (RockHillMyRide) RealtimeFeeds() map[RealtimeFeedType]string {
  38. return map[RealtimeFeedType]string{}
  39. }
  40. func (RockHillMyRide) Transformer() transform.Transformer {
  41. return transform.Nop
  42. }
  43. func (RockHillMyRide) Name() string {
  44. return "Rock Hill, SC My Ride"
  45. }
  46. func (RockHillMyRide) Flags() FeedFlags {
  47. return FeedFlags{
  48. Headsign: HeadsignTripHeadsing,
  49. StopIdFormat: "{{stop_code}}",
  50. StopName: "{{stop_name}} [{{stop_code}}]",
  51. LineName: "{{route_short_name}} {{route_long_name}}",
  52. }
  53. }
  54. func (RockHillMyRide) FeedPrepareZip(path string) error {
  55. // NOTE interpolate stop_times AND add timepoint
  56. stopTimesFile, err := os.Open(filepath.Join(path, "stop_times.txt"))
  57. if err != nil {
  58. return fmt.Errorf("while opening stop_times file: %w", err)
  59. }
  60. defer stopTimesFile.Close()
  61. stopTimes2File, err := os.OpenFile(filepath.Join(path, "stop_times2.txt"), os.O_RDWR|os.O_CREATE, 0644)
  62. if err != nil {
  63. return fmt.Errorf("while opening stop_times2 file: %w", err)
  64. }
  65. defer stopTimes2File.Close()
  66. r := csv.NewReader(bufio.NewReader(stopTimesFile))
  67. w := csv.NewWriter(stopTimes2File)
  68. header, err := r.Read()
  69. if err != nil {
  70. return fmt.Errorf("while reading stop_times header: %w", err)
  71. }
  72. fields := map[string]int{}
  73. for i, headerField := range header {
  74. fields[headerField] = i
  75. }
  76. header = append(header, "timepoint")
  77. err = w.Write(header)
  78. if err != nil {
  79. return fmt.Errorf("while writing stop_times header: %w", err)
  80. }
  81. lastTripID := ""
  82. lastKnownTime := 0
  83. collectedRecords := [][]string{}
  84. for {
  85. record, err := r.Read()
  86. if err == io.EOF {
  87. break
  88. }
  89. if err != nil {
  90. return fmt.Errorf("while reading a stop_times record: %w", err)
  91. }
  92. tripID := record[fields["trip_id"]]
  93. arrivalTime := record[fields["arrival_time"]]
  94. if tripID != lastTripID && arrivalTime == "" {
  95. return fmt.Errorf("no arrival time at the beginning of the trip ‘%s’", tripID)
  96. }
  97. if arrivalTime != "" {
  98. dT, err := parseDepartureTime(arrivalTime)
  99. if err != nil {
  100. return fmt.Errorf("incorrect end departure time %s: %w", arrivalTime, err)
  101. }
  102. if len(collectedRecords) > 0 {
  103. if tripID != lastTripID && lastTripID != "" {
  104. return fmt.Errorf("no arrival time at the end of the trip ‘%s’", lastTripID)
  105. }
  106. singleDuration := (dT - lastKnownTime) / (len(collectedRecords) + 1)
  107. for i, collectedRecord := range collectedRecords {
  108. collectedRecord[fields["arrival_time"]] = formatDepartureTime(lastKnownTime + ((i + 1) * singleDuration))
  109. collectedRecord = append(collectedRecord, "0")
  110. err = w.Write(collectedRecord)
  111. if err != nil {
  112. return fmt.Errorf("while writing a stop_times collected record %d: %w", i, err)
  113. }
  114. }
  115. }
  116. record = append(record, "1")
  117. err = w.Write(record)
  118. if err != nil {
  119. return fmt.Errorf("while writing a stop_times record: %w", err)
  120. }
  121. collectedRecords = [][]string{}
  122. lastKnownTime = dT
  123. lastTripID = tripID
  124. } else {
  125. collectedRecords = append(collectedRecords, record)
  126. }
  127. }
  128. w.Flush()
  129. err = os.Remove(filepath.Join(path, "stop_times.txt"))
  130. if err != nil {
  131. return fmt.Errorf("while removing stop_times: %w", err)
  132. }
  133. err = os.Rename(filepath.Join(path, "stop_times2.txt"), filepath.Join(path, "stop_times.txt"))
  134. if err != nil {
  135. return fmt.Errorf("while renaming stop_times: %w", err)
  136. }
  137. return nil
  138. }
  139. func (RockHillMyRide) QRInfo() (string, QRLocation, string) {
  140. return "", QRLocationNone, ""
  141. }