4 Commits 270c1a0f7f ... 809e434d5f

Author SHA1 Message Date
  Adam 809e434d5f convert vehicle dictionary in ZTM Poznań feed 2 months ago
  Adam 336436b2b8 fix not finding schedule for dates before timetable validity 2 months ago
  Adam 3e2f93af6b consider timezone when checking timetable validity 2 months ago
  Adam a1af1b9c3d when unpacking mkdir with x permission 2 months ago
5 changed files with 74 additions and 25 deletions
  1. 3 3
      file/file.go
  2. 18 5
      traffic/access.go
  3. 3 3
      traffic/feeds/feeds.go
  4. 39 14
      traffic/feeds/poznan_ztm.go
  5. 11 0
      traffic/structs/structs.go

+ 3 - 3
file/file.go

@@ -156,7 +156,7 @@ func ListVersions(path string, location *time.Location) ([]feeds.Version, error)
 	for _, txtFile := range trafficFiles {
 		if strings.Contains(txtFile.Name(), ".txz") {
 			versionString := strings.Replace(txtFile.Name(), ".txz", "", 1)
-			version, err := feeds.MakeVersion(versionString)
+			version, err := feeds.MakeVersion(versionString, location)
 			if err != nil {
 				return nil, err
 			}
@@ -186,7 +186,7 @@ func unpackTraffic(dataHome, feedName string) error {
 		if !unpacked[version] {
 			trafficPath := filepath.Join(path, version) + ".txz"
 			versionPath := filepath.Join(path, version)
-			os.Mkdir(versionPath, 0644)
+			os.Mkdir(versionPath, 0755)
 			trafficFile, err := os.Open(trafficPath)
 			if err != nil {
 				return err
@@ -232,7 +232,7 @@ func cleanOldVersions(dataHome, feedName string, location *time.Location) error
 	for _, file := range files {
 		name := file.Name()
 		versionString := strings.Replace(name, ".txz", "", 1)
-		versionsMap[versionString], err = feeds.MakeVersion(versionString)
+		versionsMap[versionString], err = feeds.MakeVersion(versionString, location)
 		if err != nil {
 			return err
 		}

+ 18 - 5
traffic/access.go

@@ -124,22 +124,34 @@ func loadTime(input ...interface{}) interface{} {
 func loadTodaySchedule(input ...interface{}) (interface{}, error) {
 	result := input[0].(getDeparturesResult)
 
-	yesterday := result.Date.AddDate(0, 0, -1)
-	yesterdaySchedule, err := findSchedule(result.TimetableHome, yesterday,
+	todaySchedule, err := findSchedule(result.TimetableHome, result.Date,
 		result.Calendar)
-	result.YesterdaySchedule = yesterdaySchedule
+	result.TodaySchedule = todaySchedule
 	return result, err
 }
 
 func loadYesterdaySchedule(input ...interface{}) (interface{}, error) {
 	result := input[0].(getDeparturesResult)
 
-	todaySchedule, err := findSchedule(result.TimetableHome, result.Date,
+	yesterday := result.Date.AddDate(0, 0, -1)
+	yesterdaySchedule, err := findSchedule(result.TimetableHome, yesterday,
 		result.Calendar)
-	result.TodaySchedule = todaySchedule
+	result.YesterdaySchedule = yesterdaySchedule
 	return result, err
 }
 
+func recoverYesterdaySchedule(input ...interface{}) (interface{}, error) {
+	result := input[0].(getDeparturesResult)
+	err := input[1].(error)
+
+	dayBefore := result.Date.AddDate(0, 0, -1).Format(traffic_structs.DateFormat)
+	if err, ok := err.(traffic_errors.NoSchedule); ok && err.Date == dayBefore {
+		result.YesterdaySchedule = ""
+		return gott.Tuple{result}, nil
+	}
+	return gott.Tuple{result}, err
+}
+
 func openStopsFile(input ...interface{}) (interface{}, error) {
 	result := input[0].(getDeparturesResult)
 
@@ -331,6 +343,7 @@ func GetDepartures(stopCode traffic_structs.ID, dataHome, feedName string,
 		Map(loadTime).
 		Bind(loadTodaySchedule).
 		Bind(loadYesterdaySchedule).
+		Recover(recoverYesterdaySchedule).
 		Bind(openStopsFile).
 		Bind(seekStops).
 		Bind(unmarshalStop).

+ 3 - 3
traffic/feeds/feeds.go

@@ -29,17 +29,17 @@ func RegisterFeeds() map[string]Feed {
 	}
 }
 
-func MakeVersion(s string) (Version, error) {
+func MakeVersion(s string, location *time.Location) (Version, error) {
 	version := Version{}
 	versionDates := strings.Split(s, "_")
 	if len(versionDates) != 2 {
 		return version, fmt.Errorf("invalid version string %s, not /.*_.*/", s)
 	}
-	validFrom, err := time.Parse("20060102", versionDates[0])
+	validFrom, err := time.ParseInLocation("20060102", versionDates[0], location)
 	if err != nil {
 		return version, fmt.Errorf("invalid first part in %s: %w", s, err)
 	}
-	validTill, err := time.Parse("20060102", versionDates[1])
+	validTill, err := time.ParseInLocation("20060102", versionDates[1], location)
 	if err != nil {
 		return version, fmt.Errorf("invalid second part in %s: %w", s, err)
 	}

+ 39 - 14
traffic/feeds/poznan_ztm.go

@@ -3,7 +3,6 @@ package feeds
 import (
 	"notabug.org/apiote/bimba_server/traffic/structs"
 
-	"bufio"
 	"encoding/csv"
 	"fmt"
 	"golang.org/x/net/html"
@@ -27,17 +26,46 @@ type HtmlSelector struct {
 type ZtmPoznan struct{}
 
 func (z ZtmPoznan) ConvertVehicles(path string) error {
-	// todo check update and download vehicle_dictionary from https://ztm.poznan.pl/en/dla-deweloperow/gtfsRtFiles
+	url := "https://ztm.poznan.pl/en/dla-deweloperow/getGtfsRtFile/?file=vehicle_dictionary.csv"
+	response, err := http.Get(url)
+	if err != nil {
+		return fmt.Errorf("ConvertVehicles: cannot GET ‘%s’: %w", url, err)
+	}
 
-	file, _ := os.Open(filepath.Join(path, "vehicle_dictionary.csv"))
+	/*file, err := os.Create(filepath.Join(path, "vehicle_dictionary.csv"))
+	if err != nil {
+		return fmt.Errorf("ConvertVehicles: cannot create csv file: %w", err)
+	}
 	defer file.Close()
 
-	result, _ := os.Create(filepath.Join(path, "vehicles.bare"))
+	_, err = io.Copy(file, response.Body)
+	if err != nil {
+		return fmt.Errorf("while downloading vehicles %w\n", err)
+	}*/
+
+	result, err := os.Create(filepath.Join(path, "vehicles.bare"))
+	if err != nil {
+		return fmt.Errorf("ConvertVehicles: cannot create bare file: %w", err)
+	}
 	defer result.Close()
 
-	r := csv.NewReader(bufio.NewReader(file))
-	r.Comma = ';'
-	r.Read()
+	r := csv.NewReader(response.Body)
+	r.Comma = ','
+	header, err := r.Read()
+	if err != nil {
+		fmt.Println("Header read error")
+		return err
+	}
+	fieldsNum := len(header)
+	if fieldsNum != 9 {
+		return VersionError{
+			Msg: fmt.Sprintf("number of fields %d != 9", fieldsNum),
+		}
+	}
+	fields := map[string]int{}
+	for i, headerField := range header {
+		fields[headerField] = i
+	}
 
 	for {
 		record, err := r.Read()
@@ -49,12 +77,9 @@ func (z ZtmPoznan) ConvertVehicles(path string) error {
 		}
 
 		var capabilites uint8 = 0
-		for i := 1; i < 9; i++ {
-			// todo record[2], record[6]
-			// record[2] in {0,1,2} meaningful
-			// record[6] in {0,1,2} meaningless
-			if record[i] != "0" {
-				capabilites = capabilites | (1 << (i - 1))
+		for field, position := range fields {
+			if field != "vehicle" && record[position] != "0" {
+				capabilites = capabilites | (1 << (position - 1))
 			}
 		}
 
@@ -113,7 +138,7 @@ func (z ZtmPoznan) GetVersions(date time.Time) ([]Version, error) {
 			}
 		}
 		if validityString != "" && link != "" {
-			version, err := MakeVersion(validityString)
+			version, err := MakeVersion(validityString, z.GetLocation())
 			if err != nil {
 				return nil, err
 			}

+ 11 - 0
traffic/structs/structs.go

@@ -1,5 +1,9 @@
 package structs
 
+import (
+	"strings"
+)
+
 type DeparturesType uint8
 
 const (
@@ -101,6 +105,12 @@ type TrieIndexSegment struct {
 
 type ID string
 type Validity string // 20060102_20060102
+func (v Validity) Start() string {
+	return strings.Split(string(v), "_")[0]
+}
+func (v Validity) End() string {
+	return strings.Split(string(v), "_")[1]
+}
 
 type PresentCode struct {
 	Present bool
@@ -114,3 +124,4 @@ type FeedCalendar map[Validity][]Schedule
 type GlobalCalendar map[string]FeedCalendar
 
 var DateFormat string = "2006-01-02"
+var ValidityFormat string = "20060102"