diff --git a/docker-compose.yml b/docker-compose.yml index c6b8e0e..e4c9782 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,6 +16,7 @@ services: - DURATION=240 - DELETE_AFTER_MINUTES=30 - UPDATE_INTERVAL_MINUTES=1 + - TRANSFER_TIME=17:00 # Hildesheim HBF, Braunschweig HBF, Hannover HBF - STATION_IDS=8000169,8000049,8000152 restart: always diff --git a/init.sql b/init.sql index 0e0360a..e8ca333 100644 --- a/init.sql +++ b/init.sql @@ -1,3 +1,4 @@ +-- Tabelle für Zugfahrten CREATE TABLE IF NOT EXISTS trips ( id VARCHAR(36) PRIMARY KEY, latitude DOUBLE, @@ -7,14 +8,27 @@ CREATE TABLE IF NOT EXISTS trips ( fahrt_nr VARCHAR(20), trip_id VARCHAR(255), planned_timestamp DATETIME, - delay INT + delay INT, + INDEX idx_fahrt_nr_timestamp (fahrt_nr, timestamp) ); +-- Tabelle für tägliche Verspätungsstatistiken +CREATE TABLE IF NOT EXISTS today_delay_stats ( + id VARCHAR(36) PRIMARY KEY, + fahrt_nr VARCHAR(255), + train_name VARCHAR(255), + delay INT, + timestamp DATETIME, + UNIQUE KEY uk_fahrt_nr_date (fahrt_nr, timestamp) +); + +-- Tabelle für aggregierte Verspätungsstatistiken CREATE TABLE IF NOT EXISTS delay_stats ( id VARCHAR(36) PRIMARY KEY, fahrt_nr VARCHAR(255), total_trips INT, delayed_trips INT, avg_delay FLOAT, - last_updated DATETIME + last_updated DATETIME, + INDEX idx_fahrt_nr (fahrt_nr) ); diff --git a/main.go b/main.go index df1bad2..4b673b5 100644 --- a/main.go +++ b/main.go @@ -86,6 +86,16 @@ func main() { updateInterval = 1 } + transferTimeStr := os.Getenv("TRANSFER_TIME") + transferTime, err := time.Parse("15:04", transferTimeStr) + if err != nil { + log.Printf("Ungültiger Wert für TRANSFER_TIME, verwende Standardwert 23:00") + transferTime = time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 23, 0, 0, 0, time.Local) + } else { + now := time.Now() + transferTime = time.Date(now.Year(), now.Month(), now.Day(), transferTime.Hour(), transferTime.Minute(), 0, 0, time.Local) + } + db, err := sql.Open("mysql", dbDSN) if err != nil { log.Fatal("Fehler beim Verbinden mit der Datenbank: ", err) @@ -109,12 +119,19 @@ func main() { deleteOldEntries(db, deleteAfter) case <-ticker.C: logDatabaseStats(db) + default: + now := time.Now() + if now.After(transferTime) { + transferDailyDelayStats(db) + transferTime = time.Date(now.Year(), now.Month(), now.Day()+1, transferTime.Hour(), transferTime.Minute(), 0, 0, time.Local) + } + time.Sleep(1 * time.Minute) } } } func fetchDepartures(apiBaseURL, stationID string, duration int) []Departure { - url := fmt.Sprintf("%s/stops/%s/departures?duration=%d&linesOfStops=false&remarks=true&language=en&nationalExpress=true&national=true®ionalExpress=true®ional=true&suburban=true&bus=false&ferry=false&subway=false&tram=false&taxi=false&pretty=true", + url := fmt.Sprintf("%s/stops/%s/departures?duration=%d&linesOfStops=false&remarks=true&language=en&nationalExpress=true&national=true®ionalExpress=true®ional=true&suburban=true&bus=false&ferry=false&subway=false&tram=false&taxi=false&pretty=false", apiBaseURL, stationID, duration) resp, err := http.Get(url) if err != nil { @@ -147,7 +164,7 @@ func fetchDepartures(apiBaseURL, stationID string, duration int) []Departure { func fetchTripDetails(apiBaseURL, tripID string) (*TripDetails, error) { escapedTripID := url.QueryEscape(tripID) - url := fmt.Sprintf("%s/trips/%s?stopovers=true&remarks=true&polyline=true&language=en", apiBaseURL, escapedTripID) + url := fmt.Sprintf("%s/trips/%s?stopovers=true&remarks=true&polyline=true&language=en&pretty=false", apiBaseURL, escapedTripID) resp, err := http.Get(url) if err != nil { return nil, fmt.Errorf("Fehler beim Abrufen der Zugdetails: %v", err) @@ -225,24 +242,87 @@ func savePosition(db *sql.DB, dep Departure, apiBaseURL string) { log.Printf("Fehler bei der Überprüfung des existierenden Eintrags für TripID %s: %v\n", dep.TripId, err) } - updateDelayStats(db, dep.Line.FahrtNr, dep.Delay) + updateTodayDelayStats(db, dep.Line.FahrtNr, dep.Line.Name, dep.Delay, whenTime) } -func updateDelayStats(db *sql.DB, fahrtNr string, delay int) { - var id string - err := db.QueryRow("SELECT id FROM delay_stats WHERE fahrt_nr = ?", fahrtNr).Scan(&id) +func updateTodayDelayStats(db *sql.DB, fahrtNr, trainName string, delay int, timestamp time.Time) { + var existingID string + err := db.QueryRow("SELECT id FROM today_delay_stats WHERE fahrt_nr = ? AND DATE(timestamp) = CURDATE()", fahrtNr).Scan(&existingID) if err == sql.ErrNoRows { - id = uuid.New().String() - _, err = db.Exec("INSERT INTO delay_stats (id, fahrt_nr, total_trips, delayed_trips, avg_delay, last_updated) VALUES (?, ?, 1, ?, ?, NOW())", - id, fahrtNr, delay > 300, delay) + // Kein existierender Eintrag, führe INSERT aus + _, err = db.Exec(` + INSERT INTO today_delay_stats (id, fahrt_nr, train_name, delay, timestamp) + VALUES (UUID(), ?, ?, ?, ?) + `, fahrtNr, trainName, delay, timestamp) + if err != nil { + log.Printf("Fehler beim Einfügen der heutigen Verspätungsstatistiken für FahrtNr %s: %v\n", fahrtNr, err) + } } else if err == nil { - _, err = db.Exec("UPDATE delay_stats SET total_trips = total_trips + 1, delayed_trips = delayed_trips + ?, avg_delay = ((avg_delay * total_trips) + ?) / (total_trips + 1), last_updated = NOW() WHERE id = ?", - delay > 300, delay, id) + // Existierender Eintrag gefunden, führe UPDATE aus + _, err = db.Exec(` + UPDATE today_delay_stats + SET train_name = ?, delay = ?, timestamp = ? + WHERE id = ? + `, trainName, delay, timestamp, existingID) + if err != nil { + log.Printf("Fehler beim Aktualisieren der heutigen Verspätungsstatistiken für FahrtNr %s: %v\n", fahrtNr, err) + } + } else { + log.Printf("Fehler beim Überprüfen der heutigen Verspätungsstatistiken für FahrtNr %s: %v\n", fahrtNr, err) + } +} + +func transferDailyDelayStats(db *sql.DB) { + rows, err := db.Query("SELECT fahrt_nr, train_name, delay FROM today_delay_stats WHERE DATE(timestamp) = CURDATE()") + if err != nil { + log.Printf("Fehler beim Abrufen der heutigen Verspätungsstatistiken: %v\n", err) + return + } + defer rows.Close() + + for rows.Next() { + var fahrtNr, trainName string + var delay int + if err := rows.Scan(&fahrtNr, &trainName, &delay); err != nil { + log.Printf("Fehler beim Scannen der Verspätungsdaten: %v\n", err) + continue + } + + var existingID string + err := db.QueryRow("SELECT id FROM delay_stats WHERE fahrt_nr = ?", fahrtNr).Scan(&existingID) + + if err == sql.ErrNoRows { + // Kein existierender Eintrag, führe INSERT aus + _, err = db.Exec(` + INSERT INTO delay_stats (id, fahrt_nr, total_trips, delayed_trips, avg_delay, last_updated) + VALUES (UUID(), ?, 1, ?, ?, NOW()) + `, fahrtNr, delay > 300, delay) + if err != nil { + log.Printf("Fehler beim Einfügen der Verspätungsstatistiken für FahrtNr %s: %v\n", fahrtNr, err) + } + } else if err == nil { + // Existierender Eintrag gefunden, führe UPDATE aus + _, err = db.Exec(` + UPDATE delay_stats + SET total_trips = total_trips + 1, + delayed_trips = delayed_trips + ?, + avg_delay = ((avg_delay * total_trips) + ?) / (total_trips + 1), + last_updated = NOW() + WHERE id = ? + `, delay > 300, delay, existingID) + if err != nil { + log.Printf("Fehler beim Aktualisieren der Verspätungsstatistiken für FahrtNr %s: %v\n", fahrtNr, err) + } + } else { + log.Printf("Fehler beim Überprüfen der Verspätungsstatistiken für FahrtNr %s: %v\n", fahrtNr, err) + } } + // Löschen Sie die heutigen Statistiken nach der Übertragung + _, err = db.Exec("DELETE FROM today_delay_stats WHERE DATE(timestamp) = CURDATE()") if err != nil { - log.Printf("Fehler beim Aktualisieren der Verspätungsstatistiken für FahrtNr %s: %v\n", fahrtNr, err) + log.Printf("Fehler beim Löschen der heutigen Verspätungsstatistiken: %v\n", err) } }