From e4353fced0e4121d59899bce1944d6b1ba7e602a Mon Sep 17 00:00:00 2001 From: Tristan van Triest Date: Thu, 21 Nov 2024 11:48:46 +0100 Subject: [PATCH 1/5] Update project to run on InfoPlaza infrastructure --- .github/workflows/deploy.yml | 20 +- .github/workflows/main_test.yml | 77 +++-- .github/workflows/test.yml | 40 ++- README.md | Bin 2096 -> 2410 bytes docker-compose.test.yml | 6 +- package.json | 15 +- yarn.lock | 518 ++++++++++---------------------- 7 files changed, 259 insertions(+), 417 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 49ac1aa..888b958 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -8,13 +8,13 @@ on: workflow_dispatch: jobs: - build: - runs-on: ["self-hosted", "main"] - steps: - - name: Run compose script in Deployment repository. - uses: benc-uk/workflow-dispatch@v1 - with: - workflow: Deploy Docker Images of R-OV - repo: R-OV-NL/Deploy - token: ${{ secrets.SHARED_PAT }} - ref: main \ No newline at end of file +# build: +# runs-on: ["self-hosted", "main"] +# steps: +# - name: Run compose script in Deployment repository. +# uses: benc-uk/workflow-dispatch@v1 +# with: +# workflow: Deploy Docker Images of R-OV +# repo: R-OV-NL/Deploy +# token: ${{ secrets.SHARED_PAT }} +# ref: main \ No newline at end of file diff --git a/.github/workflows/main_test.yml b/.github/workflows/main_test.yml index 4c2a24e..ede431e 100644 --- a/.github/workflows/main_test.yml +++ b/.github/workflows/main_test.yml @@ -1,36 +1,65 @@ -name: Test service on main +name: Test service and push on: + push: + branches: + - 'main' pull_request: branches: - 'main' - workflow_dispatch: - jobs: - build: - runs-on: ["self-hosted", "main"] + build_and_test: + name: Build and test + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - name: Checkout code + uses: actions/checkout@v3 with: token: ${{ secrets.SHARED_PAT }} submodules: recursive - - name: Rebuild Compose Images - run: docker compose -f docker-compose.test.yml build --no-cache - - name: Test image with Docker Compose - run: docker compose -f docker-compose.test.yml up --force-recreate --abort-on-container-exit --exit-code-from app - - name: Build and Push Docker Image - uses: mr-smithers-excellent/docker-build-push@v5 - with: - image: arilith/r_ov - registry: docker.io - tags: gtfsrt - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - compose-down: - runs-on: ["self-hosted", "main"] - if: ${{ always() }} - needs: [build] + + - name: Build and start services + run: | + docker compose -f docker-compose.test.yml up -d database + sleep 10 # Adjust sleep time as needed to allow services to start + + - name: Wait for database to be ready + run: | + until docker compose -f docker-compose.test.yml exec -T database pg_isready -U postgres; do + >&2 echo "Postgres is unavailable - sleeping" + sleep 1 + done + - name: Start app service + run: docker compose -f docker-compose.test.yml up --force-recreate --build --exit-code-from app app --remove-orphans + + - name: Clean up + if: always() + run: docker compose -f docker-compose.test.yml down + build_and_push: + needs: build_and_test + name: Build and push to ACR + runs-on: ubuntu-latest steps: - - name: Docker compose down - run: docker compose -f docker-compose.test.yml down \ No newline at end of file + - name: Checkout code + uses: actions/checkout@v3 + with: + token: ${{ secrets.SHARED_PAT }} + submodules: recursive + - name: Log in to Azure Container Registry + run: | + echo "${{ secrets.AZURE_PASSWORD }}" | docker login "${{ secrets.ACR_REGISTRY }}" --username "${{ secrets.AZURE_APP_ID }}" --password-stdin + + - name: Set version + run: echo "VERSION=${{ github.run_number }}" >> $GITHUB_ENV + + - name: Build Docker Image with both tags + run: | + docker build -t ${{ secrets.ACR_REGISTRY }}/tristanvantriest/gtfs-rt:latest \ + -t ${{ secrets.ACR_REGISTRY }}/tristanvantriest/gtfs-rt:${{ env.VERSION }} \ + -f Dockerfile . + + - name: Push Docker Image to ACR with both tags + run: | + docker push ${{ secrets.ACR_REGISTRY }}/tristanvantriest/gtfs-rt:latest + docker push ${{ secrets.ACR_REGISTRY }}/tristanvantriest/gtfs-rt:${{ env.VERSION }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2b06d7e..dea8235 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,4 @@ -name: Test service no push. +name: Test service on: push: @@ -10,24 +10,32 @@ on: - '**' - '!main' - workflow_dispatch: - jobs: - build: - runs-on: ["self-hosted", "main"] + build_and_test: + runs-on: ubuntu-latest + steps: - - uses: actions/checkout@v2 + - name: Checkout code + uses: actions/checkout@v3 with: token: ${{ secrets.SHARED_PAT }} submodules: recursive - - name: Rebuild Compose Images - run: docker compose -f docker-compose.test.yml build --no-cache - - name: Test image with Docker Compose - run: docker compose -f docker-compose.test.yml up --force-recreate --abort-on-container-exit --exit-code-from app - compose-down: - runs-on: ["self-hosted", "main"] - if: ${{ always() }} - needs: [build] - steps: - - name: Docker compose down + + - name: Build and start services + run: | + docker compose -f docker-compose.test.yml up -d database + sleep 10 # Adjust sleep time as needed to allow services to start + + - name: Wait for database to be ready + run: | + until docker compose -f docker-compose.test.yml exec -T database pg_isready -U postgres; do + >&2 echo "Postgres is unavailable - sleeping" + sleep 1 + done + + - name: Start app service + run: docker compose -f docker-compose.test.yml up --force-recreate --build --exit-code-from app app + + - name: Clean up + if: always() run: docker compose -f docker-compose.test.yml down \ No newline at end of file diff --git a/README.md b/README.md index 315c5bb9044a390f74b76068ae622f8444109a62..05196a48b20de1c735d0b027031112fbf401141f 100644 GIT binary patch delta 285 zcmdlW@JdMh|37601qM%sJccxee1-sq9EL=ODu%>~8-*t-h^Z2pyG0~mN2xF&uS-fYDv#q6lSPy*DXz>o~qTELJA zv?dkEFJZ_4(*= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -4122,10 +3971,10 @@ semver@^7.1.2: dependencies: lru-cache "^6.0.0" -send@0.18.0: - version "0.18.0" - resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== dependencies: debug "2.6.9" depd "2.0.0" @@ -4141,15 +3990,27 @@ send@0.18.0: range-parser "~1.2.1" statuses "2.0.1" -serve-static@1.15.0: - version "1.15.0" - resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== dependencies: - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" parseurl "~1.3.3" - send "0.18.0" + send "0.19.0" + +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" set-function-name@^2.0.0: version "2.0.1" @@ -4165,14 +4026,15 @@ setprototypeof@1.2.0: resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== +side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" skmeans@0.9.7: version "0.9.7" @@ -4199,21 +4061,6 @@ split2@^4.1.0: resolved "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz" integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== -sshpk@^1.7.0: - version "1.17.0" - resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz" - integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - statuses@2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" @@ -4296,14 +4143,6 @@ topojson-server@3.x: dependencies: commander "2" -tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - ts-poet@^6.5.0: version "6.6.0" resolved "https://registry.npmjs.org/ts-poet/-/ts-poet-6.6.0.tgz" @@ -4336,23 +4175,11 @@ ts-protoc-gen@^0.15.1-pre.a71b34e: dependencies: google-protobuf "^3.15.5" -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz" - integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== - dependencies: - safe-buffer "^5.0.1" - turf-jsts@*: version "1.2.3" resolved "https://registry.npmjs.org/turf-jsts/-/turf-jsts-1.2.3.tgz" integrity sha512-Ja03QIJlPuHt4IQ2FfGex4F4JAr8m3jpaHbFbQrgwr7s7L6U8ocrHiF3J1+wf9jzhGKxvDeaCAnGDot8OjGFyA== -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz" - integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== - type-check@~0.3.2: version "0.3.2" resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" @@ -4429,37 +4256,16 @@ update-browserslist-db@^1.0.13: escalade "^3.1.1" picocolors "^1.0.0" -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - utils-merge@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -uuid@^3.3.2: - version "3.4.0" - resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - vary@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== -verror@1.10.0: - version "1.10.0" - resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz" - integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - web-streams-polyfill@^3.0.3: version "3.2.1" resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz" From 181806c61117614bc1b6c1f5c07fc1186974a570 Mon Sep 17 00:00:00 2001 From: Tristan van Triest Date: Mon, 25 Nov 2024 15:19:34 +0100 Subject: [PATCH 2/5] Bugfixes for GTFS-RT Infoplus feed --- src/Database/Database.ts | 2 +- src/Interfaces/DatabaseRitInfoUpdate.ts | 1 + src/Models/RitInfoUpdate.ts | 29 ++- src/Models/StopUpdateCollection.ts | 20 +- src/Models/StopUpdates/RitinfoStopUpdate.ts | 5 + src/Repositories/InfoplusRepository.ts | 192 ++++++++++---------- 6 files changed, 145 insertions(+), 104 deletions(-) diff --git a/src/Database/Database.ts b/src/Database/Database.ts index ff632f8..7aea479 100644 --- a/src/Database/Database.ts +++ b/src/Database/Database.ts @@ -7,7 +7,7 @@ export const Knex = knex({ user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, - port: 5432 + port: process.env.DB_PORT ? parseInt(process.env.DB_PORT) : 5432 }, pool: { min: 0, diff --git a/src/Interfaces/DatabaseRitInfoUpdate.ts b/src/Interfaces/DatabaseRitInfoUpdate.ts index d3615be..9646d7b 100644 --- a/src/Interfaces/DatabaseRitInfoUpdate.ts +++ b/src/Interfaces/DatabaseRitInfoUpdate.ts @@ -44,4 +44,5 @@ export interface IRitInfoStopUpdate extends IDatabaseStopUpdate { plannedTrack: string | null; actualTrack: string | null; stationCode: string; + name: string; } \ No newline at end of file diff --git a/src/Models/RitInfoUpdate.ts b/src/Models/RitInfoUpdate.ts index eed91a4..07ddb51 100644 --- a/src/Models/RitInfoUpdate.ts +++ b/src/Models/RitInfoUpdate.ts @@ -4,13 +4,14 @@ * Questions? Email: tristantriest@gmail.com */ -import {IDatabaseRitInfoUpdate} from '../Interfaces/DatabaseRitInfoUpdate' +import {IDatabaseRitInfoUpdate, IRitInfoStopUpdate} from '../Interfaces/DatabaseRitInfoUpdate' import {ExtendedStopTimeUpdate} from "./GTFS/StopTimeUpdate"; import {RitInfoStopUpdate} from "./StopUpdates/RitinfoStopUpdate"; import {StopUpdateCollection} from "./StopUpdateCollection"; import {InternationalAgencys, InternationalTrainSeries} from '../Utilities/InternationalAgencys'; import {IJourneyChange} from "../Shared/src/Types/Infoplus/V2/JourneyChange"; import {LogicalJourneyChangeType} from "../Shared/src/Types/Infoplus/V2/Changes/LogicalJourneyChangeType"; +import {TrainType} from "../Shared/src/Types/API/V2/InfoPlus/TrainType"; export class RitInfoUpdate { private readonly _agency: string; @@ -50,12 +51,36 @@ export class RitInfoUpdate { this._timestamp = update.timestamp; this._routeType = update.routeType; - this._routeLongName = update.routeLongName; + this._routeLongName = this.getRouteLongName(update); this._agencyId = update.agencyId; this._isInternationalTrain = this.setInternationalTrain(); } + private getRouteLongName(update: IDatabaseRitInfoUpdate): string { + if(update.routeLongName) + return update.routeLongName; + + const firstStop = this.stops.first(); + const lastStop = this.stops.last(); + + //The trainseries of e.g. 1234 is 1200, 570 is 500, 29290 is 29000 + const trainSeries = update.trainNumber - (update.trainNumber % 100); + const trainType = update.trainType; + const longTrainType = TrainType.shortToLong(TrainType.fromStringToShort(trainType)); + + //Haarlem <-> Amsterdam Sloterdijk BST26000 + //Nachtnettrein Amsterdam Bijlmer ArenA <-> Leiden Centraal + + //Rotterdam Centraal <-> Amsterdam Centraal ICD1100 + if(firstStop.name && lastStop.name) { + return `${firstStop.name} <-> ${lastStop.name} ${trainType}${trainSeries}`; + } + + return `${longTrainType} ${trainSeries}`; + + } + private setInternationalTrain(): boolean { let isInternationalTrain = false; diff --git a/src/Models/StopUpdateCollection.ts b/src/Models/StopUpdateCollection.ts index c54218c..8b1e4c6 100644 --- a/src/Models/StopUpdateCollection.ts +++ b/src/Models/StopUpdateCollection.ts @@ -24,6 +24,12 @@ export class StopUpdateCollection extends Collection { //Make sure all times are increasing this.checkIncreasingTimes(); + + /* + @InfoPlaza - Specific to Infoplaza IFF GTFS + Set all stop sequences sequentually irrespective of the sequence in InfoPlus + */ + this.setSequenceNumbers(); } private setFirstStop() { @@ -101,6 +107,18 @@ export class StopUpdateCollection extends Collection { } } + /** + * Set the sequence number of each stop to its index in the array + 1 + * @private + */ + private setSequenceNumbers() { + for (let i = 0; i < this.length; i++) { + const stop = this.get(i); + stop.sequence = i + 1; + this.set(i, stop); + } + } + /** * Fix the current stop time by setting the arrival time to the planned arrival time + min(delay at previous stop, delay at next stop) * @param previousStop The previous stop in the sequence @@ -136,7 +154,7 @@ export class StopUpdateCollection extends Collection { if (stopToFix.plannedArrivalTime === null) return; // Calculate the new arrival time by adding the departure delay at the previous stop to the planned arrival time at the current stop - const newArrivalTime = stopToFix.plannedArrivalTime.getTime() + previousStop.departureDelay; + const newArrivalTime = (stopToFix.plannedArrivalTime.getTime() / 1000) + previousStop.departureDelay; // If the new arrival time is not increasing, we can't fix the arrival time if (newArrivalTime < previousStop.departureTime) { diff --git a/src/Models/StopUpdates/RitinfoStopUpdate.ts b/src/Models/StopUpdates/RitinfoStopUpdate.ts index c9fd76c..60ce688 100644 --- a/src/Models/StopUpdates/RitinfoStopUpdate.ts +++ b/src/Models/StopUpdates/RitinfoStopUpdate.ts @@ -25,6 +25,8 @@ export class RitInfoStopUpdate extends StopUpdate { public readonly stationCode: string; + public readonly name: string; + constructor(update: IRitInfoStopUpdate) { super(update); @@ -40,6 +42,9 @@ export class RitInfoStopUpdate extends StopUpdate { this.platform = update.platform; this.track = update.track; + + this.name = update.name; + if(this.platform !== this.track) console.log(`[RitInfoStopUpdate] Platform and Track are not the same for stop ${this.stationCode}! Platform: ${this.platform}, Track: ${this.track}`) } diff --git a/src/Repositories/InfoplusRepository.ts b/src/Repositories/InfoplusRepository.ts index e41dc36..d582c80 100644 --- a/src/Repositories/InfoplusRepository.ts +++ b/src/Repositories/InfoplusRepository.ts @@ -15,114 +15,106 @@ export class InfoplusRepository extends Repository implements IInfoPlusRepositor console.time('getCurrentRealtimeTripUpdates'); return this.database.raw(` WITH cal_dates AS (SELECT DISTINCT "serviceId", "date" - FROM "StaticData-NL".calendar_dates - WHERE "date" >= ?::date - AND date <= ?::date), - trips AS (SELECT "tripId", "routeId", "directionId", "tripShortName", "shapeId", "serviceId" - FROM "StaticData-NL".trips - WHERE agency = 'IFF' - AND "serviceId" IN (SELECT DISTINCT "serviceId" - FROM cal_dates)), - stops AS (SELECT "stopId", "stationCode", "platformCode" - FROM "StaticData-NL".stops - WHERE "stationCode" IS NOT NULL) - SELECT jpjl."journeyPartNumber" AS "trainNumber", - jpjl."shortJourneyPartNumber" AS "shortTrainNumber", - r."trainType"->>'code' AS "trainType", - r.agency, - r."operationDate", - r."showsInTravelPlanner" AS "showsInTripPlanner", - r."timestamp", - coalesce(lj."journeyChanges", jpjl."journeyPartChanges") AS "changes", - t."tripId" AS "tripId", - coalesce(t."routeId", t_short."routeId") AS "routeId", - rt."routeType" AS "routeType", - rt."agencyId" AS "agencyId", - rt."routeLongName" AS "routeLongName", - coalesce(t."directionId", t_short."directionId") AS "directionId", - coalesce(t."shapeId", t_short."shapeId") AS "shapeId", - jsonb_agg( - jsonb_build_object( - 'stationCode', - si."stationCode", - 'plannedWillStop', - si."plannedWillStop", - 'actualWillStop', - si."actualWillStop", - 'plannedArrivalTime', - si."plannedArrivalTime", - 'plannedDepartureTime', - si."plannedDepartureTime", - 'departureTime', - coalesce(si."actualDepartureTime", si."plannedDepartureTime"), - 'arrivalTime', - coalesce(si."actualArrivalTime", si."plannedArrivalTime"), - 'departureDelay', - si."actualDepartureTime" - si."plannedDepartureTime", - 'arrivalDelay', - si."actualArrivalTime" - si."plannedArrivalTime", - 'changes', - si.changes, - 'stopId', - COALESCE(s."stopId", lateral_stop."stopId", si."stationCode"), - 'platform', - s."platformCode", - 'plannedTrack', - coalesce(si."plannedArrivalTracks", si."plannedDepartureTracks"), - 'actualTrack', - coalesce(si."actualArrivalTracks", si."actualDepartureTracks"), - 'track', - coalesce(si."actualArrivalTracks", si."actualDepartureTracks", si."plannedArrivalTracks", - si."plannedDepartureTracks"), - 'sequence', - si."stopOrder" - ) ORDER BY si."stopOrder") stops - FROM "InfoPlus-new".ritinfo r - JOIN "InfoPlus-new".logical_journeys lj - ON r."trainNumber" = lj."trainNumber" AND r."operationDate" = lj."operationDate" - JOIN "InfoPlus-new".logical_journey_parts jpjl - ON lj."journeyNumber" = jpjl."journeyNumber" AND - r."operationDate" = jpjl."operationDate" - JOIN "InfoPlus-new".stop_information si - ON jpjl."journeyPartNumber" = si."journeyPartNumber" AND - jpjl."operationDate" = si."operationDate" AND - ("plannedWillStop" = true OR "actualWillStop" = true) AND - (coalesce("plannedDepartureTime", "actualArrivalTime") IS NOT NULL OR - coalesce("plannedArrivalTime", "actualArrivalTime") IS NOT NULL) - LEFT JOIN trips t - ON jpjl."journeyPartNumber" = t."tripShortName"::int + FROM "StaticData-NL".calendar_dates + WHERE "date" >= ?::date + AND date <= ?::date), + trips AS (SELECT "tripId", "routeId", "directionId", "tripShortName", "shapeId", "serviceId" + FROM "StaticData-NL".trips + WHERE agency = 'IFF' + AND "serviceId" IN (SELECT DISTINCT "serviceId" + FROM cal_dates)), + stops AS (SELECT "stopId", "stationCode", "platformCode", "stopName" + FROM "StaticData-NL".stops + WHERE "stationCode" IS NOT NULL) +SELECT jpjl."journeyPartNumber" AS "trainNumber", + jpjl."shortJourneyPartNumber" AS "shortTrainNumber", + r."trainType" ->> 'code' AS "trainType", + r.agency, + r."operationDate", + r."showsInTravelPlanner" AS "showsInTripPlanner", + r."timestamp", + coalesce(lj."journeyChanges", jpjl."journeyPartChanges") AS "changes", + t."tripId" AS "tripId", + coalesce(t."routeId", t_short."routeId") AS "routeId", + rt."routeType" AS "routeType", + rt."agencyId" AS "agencyId", + rt."routeLongName" AS "routeLongName", + coalesce(t."directionId", t_short."directionId") AS "directionId", + coalesce(t."shapeId", t_short."shapeId") AS "shapeId", + jsonb_agg( + CASE + WHEN s."stopId" IS NOT NULL OR lateral_stop."stopId" IS NOT NULL THEN + jsonb_build_object( + 'stationCode', si."stationCode", + 'plannedWillStop', si."plannedWillStop", + 'actualWillStop', si."actualWillStop", + 'plannedArrivalTime', si."plannedArrivalTime", + 'plannedDepartureTime', si."plannedDepartureTime", + 'departureTime', coalesce(si."actualDepartureTime", si."plannedDepartureTime"), + 'arrivalTime', coalesce(si."actualArrivalTime", si."plannedArrivalTime"), + 'departureDelay', si."actualDepartureTime" - si."plannedDepartureTime", + 'arrivalDelay', si."actualArrivalTime" - si."plannedArrivalTime", + 'changes', si.changes, + 'stopId', COALESCE(s."stopId", lateral_stop."stopId"), + 'platform', s."platformCode", + 'plannedTrack', coalesce(si."plannedArrivalTracks", si."plannedDepartureTracks"), + 'actualTrack', coalesce(si."actualArrivalTracks", si."actualDepartureTracks"), + 'track', + coalesce(si."actualArrivalTracks", si."actualDepartureTracks", si."plannedArrivalTracks", + si."plannedDepartureTracks"), + 'sequence', si."stopOrder", + 'name', COALESCE(s."stopName", lateral_stop."stopName", si."stationCode") + ) + END + ORDER BY si."stopOrder" + ) FILTER (WHERE s."stopId" IS NOT NULL OR lateral_stop."stopId" IS NOT NULL) AS stops +FROM "InfoPlus-new".ritinfo r + JOIN "InfoPlus-new".logical_journeys lj + ON r."trainNumber" = lj."trainNumber" AND r."operationDate" = lj."operationDate" + JOIN "InfoPlus-new".logical_journey_parts jpjl + ON lj."journeyNumber" = jpjl."journeyNumber" AND + r."operationDate" = jpjl."operationDate" + JOIN "InfoPlus-new".stop_information si + ON jpjl."journeyPartNumber" = si."journeyPartNumber" AND + jpjl."operationDate" = si."operationDate" AND + ("plannedWillStop" = true OR "actualWillStop" = true) AND + (coalesce("plannedDepartureTime", "actualArrivalTime") IS NOT NULL OR + coalesce("plannedArrivalTime", "actualArrivalTime") IS NOT NULL) + LEFT JOIN trips t + ON jpjl."journeyPartNumber" = t."tripShortName"::int AND EXISTS (SELECT 1 FROM cal_dates cd WHERE cd."serviceId" = t."serviceId" AND cd."date" = r."operationDate") LEFT JOIN trips t_short ON t."tripId" IS NULL AND jpjl."shortJourneyPartNumber" = t_short."tripShortName"::int - AND EXISTS (SELECT 1 + AND EXISTS (SELECT 1 FROM cal_dates cd WHERE cd."serviceId" = t_short."serviceId" - AND cd."date" = r."operationDate") - LEFT JOIN stops s ON (s."stationCode" = lower(si."stationCode") AND - s."platformCode" = - coalesce(si."actualArrivalTracks", si."actualDepartureTracks", si."plannedArrivalTracks", - si."plannedDepartureTracks")) - LEFT JOIN LATERAL ( - SELECT "stopId" - FROM stops lax - WHERE lax."stationCode" = lower(si."stationCode") - LIMIT 1 - ) AS lateral_stop ON s."stopId" IS NULL - LEFT JOIN "StaticData-NL".routes rt ON rt."routeId" = coalesce(t."routeId", t_short."routeId") - WHERE r."operationDate" >= ?::date - AND NOT ( - r."operationDate" > ?::date - AND lj."journeyChanges" IS NULL - ) - GROUP BY r."trainNumber", jpjl."journeyPartNumber", r."shortTrainNumber", jpjl."shortJourneyPartNumber", - r."trainType", r.agency, - r."showsInTravelPlanner", r.timestamp, r."operationDate", t."tripId", coalesce(t."tripId", t_short."tripId"), - coalesce(lj."journeyChanges", jpjl."journeyPartChanges"), - t."tripId", coalesce(t."routeId", t_short."routeId"), - coalesce(t."directionId", t_short."directionId"), coalesce(t."shapeId", t_short."shapeId"), rt."routeType", rt."agencyId", rt."routeLongName"; + AND cd."date" = r."operationDate") + LEFT JOIN stops s ON (s."stationCode" = lower(si."stationCode") AND + s."platformCode" = + coalesce(si."actualArrivalTracks", si."actualDepartureTracks", si."plannedArrivalTracks", + si."plannedDepartureTracks")) + LEFT JOIN LATERAL ( + SELECT "stopId", "stopName" + FROM stops lax + WHERE lax."stationCode" = lower(si."stationCode") + LIMIT 1 + ) AS lateral_stop ON s."stopId" IS NULL + LEFT JOIN "StaticData-NL".routes rt ON rt."routeId" = coalesce(t."routeId", t_short."routeId") +WHERE r."operationDate" >= ?::date + AND NOT ( + r."operationDate" > ?::date + AND lj."journeyChanges" IS NULL + ) +GROUP BY r."trainNumber", jpjl."journeyPartNumber", r."shortTrainNumber", jpjl."shortJourneyPartNumber", + r."trainType", r.agency, + r."showsInTravelPlanner", r.timestamp, r."operationDate", t."tripId", coalesce(t."tripId", t_short."tripId"), + coalesce(lj."journeyChanges", jpjl."journeyPartChanges"), + t."tripId", coalesce(t."routeId", t_short."routeId"), + coalesce(t."directionId", t_short."directionId"), coalesce(t."shapeId", t_short."shapeId"), rt."routeType", + rt."agencyId", rt."routeLongName"; `, [operationDateOfTodayOrYesterday, endOperationDate, operationDateOfTodayOrYesterday, operationDateOfTodayOrTomorrow]).then(result => { console.timeEnd('getCurrentRealtimeTripUpdates'); return result.rows; From 0dabd31f0489cf09f1825c96a0a15c31ec42221e Mon Sep 17 00:00:00 2001 From: Tristan van Triest Date: Mon, 25 Nov 2024 15:28:36 +0100 Subject: [PATCH 3/5] Use right shared tracking branch --- src/Shared | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Shared b/src/Shared index 2d549a5..4a57c51 160000 --- a/src/Shared +++ b/src/Shared @@ -1 +1 @@ -Subproject commit 2d549a56a1bc3505153ae135f60c7a32c60508b6 +Subproject commit 4a57c519c587a861c9818e58de448d0738bf4d52 From 4108eb392ea928fee7fd7961207a6c6775fbe11d Mon Sep 17 00:00:00 2001 From: Tristan van Triest Date: Mon, 25 Nov 2024 18:03:44 +0100 Subject: [PATCH 4/5] Don't include "Niet voor Reizigers" stops. Fix stop time fixing. --- src/Models/StopUpdateCollection.ts | 68 +++++++++++++++----------- src/Repositories/InfoplusRepository.ts | 1 + 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/src/Models/StopUpdateCollection.ts b/src/Models/StopUpdateCollection.ts index 8b1e4c6..1b62334 100644 --- a/src/Models/StopUpdateCollection.ts +++ b/src/Models/StopUpdateCollection.ts @@ -50,10 +50,6 @@ export class StopUpdateCollection extends Collection { * @private */ private checkIncreasingTimes() { - // Initialize variables to keep track of the last stop's arrival and departure times - let lastStopArrivalTime: number | undefined = undefined; - let lastStopDepartureTime: number | undefined = undefined; - // Loop through each stop in the collection for (let i = 0; i < this.length; i++) { // Get the current stop, as well as the previous and next stops (if they exist) @@ -73,25 +69,21 @@ export class StopUpdateCollection extends Collection { // Check if the current stop's planned arrival time is increasing if (currentStop.arrivalTime !== null) { - if (lastStopDepartureTime !== undefined && currentStop.arrivalTime && currentStop.arrivalTime < lastStopDepartureTime) { + if (currentStop.arrivalTime && currentStop.arrivalTime < previousStop.departureTime) { // If the current stop's planned arrival time is not increasing, log a warning message // console.warn(`[StopUpdateCollection ${this.tripId}] Non-increasing arrival time detected for stop ${currentStop.stationCode} [${currentStop.sequence}]`, new Date(currentStop.arrivalTime * 1000), new Date(lastStopDepartureTime * 1000)) arrivalTimeIsIncreasing = false; } - - lastStopArrivalTime = currentStop.arrivalTime; } // Check if the current stop's planned departure time is increasing if (currentStop.departureTime !== null) { - if (lastStopDepartureTime !== undefined && currentStop.departureTime && currentStop.departureTime < lastStopDepartureTime) { + if (currentStop.departureTime && currentStop.departureTime < previousStop.departureTime) { // If the current stop's planned departure time is not increasing, log a warning message // console.warn(`[StopUpdateCollection ${this.tripId}] Non-increasing departure time detected for stop ${currentStop.stationCode} [${currentStop.sequence}]`, new Date(currentStop.departureTime * 1000), new Date(lastStopDepartureTime * 1000)) departureTimeIsIncreasing = false; } - // Update the last stop's departure time to the current stop's planned departure time - lastStopDepartureTime = currentStop.departureTime; } // If both the arrival and departure times are increasing, we don't need to fix anything @@ -99,6 +91,7 @@ export class StopUpdateCollection extends Collection { continue; } + // If there is a previous and next stop, we can fix both times this.fixStopTime(previousStop, currentStop, !arrivalTimeIsIncreasing, !departureTimeIsIncreasing); @@ -127,7 +120,7 @@ export class StopUpdateCollection extends Collection { * @param fixDeparture Whether the departure time should be fixed */ private fixStopTime(previousStop: RitInfoStopUpdate, currentStop: RitInfoStopUpdate, fixArrival: boolean, fixDeparture: boolean) { - // console.info(`[StopUpdateCollection] Fixing stop times for stop ${currentStop.stopId} [${currentStop.sequence}]`) + console.info(`[StopUpdateCollection] Fixing stop times for stop ${currentStop.stopId}: ${currentStop.name} [${currentStop.sequence}]`) if(fixArrival) this.fixArrivalTime(previousStop, currentStop); @@ -153,19 +146,39 @@ export class StopUpdateCollection extends Collection { // If the current stop has no planned arrival time, we can't fix the arrival time if (stopToFix.plannedArrivalTime === null) return; - // Calculate the new arrival time by adding the departure delay at the previous stop to the planned arrival time at the current stop - const newArrivalTime = (stopToFix.plannedArrivalTime.getTime() / 1000) + previousStop.departureDelay; + const orignalStopTime = (stopToFix.departureTime - stopToFix.arrivalTime) / 1000; - // If the new arrival time is not increasing, we can't fix the arrival time - if (newArrivalTime < previousStop.departureTime) { - console.error(`[StopUpdateCollection ${this.tripId}] Tried fixing arrival time for stop ${stopToFix.stationCode} [${stopToFix.sequence}], but the new arrival time is not increasing. New arrival time: ${new Date(newArrivalTime * 1000)}`); - } + // Calculate the base new arrival time + let newArrivalTime = (stopToFix.plannedArrivalTime.getTime() / 1000) + previousStop.departureDelay; - // Update the arrival time of the current stop - stopToFix.arrivalTime = newArrivalTime; + // Ensure the arrival time is strictly greater than the previous stop's departure time + newArrivalTime = Math.max(newArrivalTime, previousStop.departureTime + 1); - // Update the arrival delay of the current stop + stopToFix.arrivalTime = newArrivalTime; stopToFix.arrivalDelay = previousStop.departureDelay; + + //We always stay at the station about 60 seconds, so we cannot run in all delay during the stop. + if(orignalStopTime > 60) + stopToFix.departureDelay = stopToFix.arrivalDelay - (orignalStopTime - 60); + //If we weren't planned to stop for longer than a minute, we don't have to adjust the delay. + else + stopToFix.departureDelay = stopToFix.arrivalDelay; + + //If there is still a departure delay after the stop, we have to adjust the departure time. + if(stopToFix.departureDelay > 0) { + //The departure time will be the delay + the arrival time. + stopToFix.departureTime = stopToFix.arrivalTime + stopToFix.departureDelay; + + //Log what was fixed, the original stop time, the new arrival time, the new departure time and the delay. + console.info(`[StopUpdateCollection] Fixed stop ${stopToFix.stopId}: ${stopToFix.name} [${stopToFix.sequence}] Arrival time: ${new Date(stopToFix.arrivalTime * 1000)} Departure time: ${new Date(stopToFix.departureTime * 1000)} Original stop time: ${orignalStopTime} seconds. Arrival delay: ${stopToFix.arrivalDelay} seconds. Departure delay: ${stopToFix.departureDelay} seconds.`); + } + //If there is no delay, we can just set the departure time to the planned departure time. + else { + stopToFix.departureTime = stopToFix.plannedDepartureTime.getTime() / 1000; + //Log what was fixed, the original stop time, the new arrival time, the new departure time and the delay. + console.info(`[StopUpdateCollection] Fixed stop ${stopToFix.stopId}: ${stopToFix.name} [${stopToFix.sequence}] Arrival time: ${new Date(stopToFix.arrivalTime * 1000)} Departure time: ${new Date(stopToFix.departureTime * 1000)} Original stop time: ${orignalStopTime} seconds. Arrival delay: ${stopToFix.arrivalDelay} seconds. Departure delay: ${stopToFix.departureDelay} seconds.`); + } + } /** @@ -184,21 +197,18 @@ export class StopUpdateCollection extends Collection { // If the current stop has no actual arrival time, we can't fix the departure time if (stopToFix.arrivalTime === null) return; - // Calculate the new departure time by adding the difference between the planned arrival and departure times to the actual arrival time - const newDepartureTime = stopToFix.arrivalTime + ((stopToFix.plannedDepartureTime.getTime() - stopToFix.plannedArrivalTime.getTime()) / 1000); + // Calculate the base new departure time + let newDepartureTime = stopToFix.arrivalTime + ((stopToFix.plannedDepartureTime.getTime() - stopToFix.plannedArrivalTime.getTime()) / 1000); - // If the new departure time is not increasing, we can't fix the departure time - if (newDepartureTime < stopToFix.arrivalTime) { - console.error(`[StopUpdateCollection ${this.tripId}] Tried fixing departure time for stop ${stopToFix.stationCode} [${stopToFix.sequence}], but the new departure time is not increasing. New departure time: ${new Date(newDepartureTime * 1000)}`); - } + // Ensure the departure time is strictly greater than the arrival time + newDepartureTime = Math.max(newDepartureTime, stopToFix.arrivalTime + 1); - // Update the departure time of the current stop stopToFix.departureTime = newDepartureTime; - - // Update the departure delay of the current stop stopToFix.departureDelay = stopToFix.arrivalDelay; } + + /** * Finds the last stop that is still served before only cancelled stops happen. * Updates it so that it does not have a departure time, as it will never depart because it is the last stop now. diff --git a/src/Repositories/InfoplusRepository.ts b/src/Repositories/InfoplusRepository.ts index d582c80..1753d95 100644 --- a/src/Repositories/InfoplusRepository.ts +++ b/src/Repositories/InfoplusRepository.ts @@ -77,6 +77,7 @@ FROM "InfoPlus-new".ritinfo r JOIN "InfoPlus-new".stop_information si ON jpjl."journeyPartNumber" = si."journeyPartNumber" AND jpjl."operationDate" = si."operationDate" AND + si."stopType" != 'N' AND ("plannedWillStop" = true OR "actualWillStop" = true) AND (coalesce("plannedDepartureTime", "actualArrivalTime") IS NOT NULL OR coalesce("plannedArrivalTime", "actualArrivalTime") IS NOT NULL) From c8fa07bd7216f769eccb1ceac16f4b0a6b24b626 Mon Sep 17 00:00:00 2001 From: Tristan van Triest Date: Thu, 28 Nov 2024 10:37:10 +0100 Subject: [PATCH 5/5] Disable excessive logging --- src/Models/StopUpdateCollection.ts | 6 +++--- src/Models/TrainUpdateCollection.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Models/StopUpdateCollection.ts b/src/Models/StopUpdateCollection.ts index 1b62334..399e6d9 100644 --- a/src/Models/StopUpdateCollection.ts +++ b/src/Models/StopUpdateCollection.ts @@ -120,7 +120,7 @@ export class StopUpdateCollection extends Collection { * @param fixDeparture Whether the departure time should be fixed */ private fixStopTime(previousStop: RitInfoStopUpdate, currentStop: RitInfoStopUpdate, fixArrival: boolean, fixDeparture: boolean) { - console.info(`[StopUpdateCollection] Fixing stop times for stop ${currentStop.stopId}: ${currentStop.name} [${currentStop.sequence}]`) + //console.info(`[StopUpdateCollection] Fixing stop times for stop ${currentStop.stopId}: ${currentStop.name} [${currentStop.sequence}]`) if(fixArrival) this.fixArrivalTime(previousStop, currentStop); @@ -170,13 +170,13 @@ export class StopUpdateCollection extends Collection { stopToFix.departureTime = stopToFix.arrivalTime + stopToFix.departureDelay; //Log what was fixed, the original stop time, the new arrival time, the new departure time and the delay. - console.info(`[StopUpdateCollection] Fixed stop ${stopToFix.stopId}: ${stopToFix.name} [${stopToFix.sequence}] Arrival time: ${new Date(stopToFix.arrivalTime * 1000)} Departure time: ${new Date(stopToFix.departureTime * 1000)} Original stop time: ${orignalStopTime} seconds. Arrival delay: ${stopToFix.arrivalDelay} seconds. Departure delay: ${stopToFix.departureDelay} seconds.`); + //console.info(`[StopUpdateCollection] Fixed stop ${stopToFix.stopId}: ${stopToFix.name} [${stopToFix.sequence}] Arrival time: ${new Date(stopToFix.arrivalTime * 1000)} Departure time: ${new Date(stopToFix.departureTime * 1000)} Original stop time: ${orignalStopTime} seconds. Arrival delay: ${stopToFix.arrivalDelay} seconds. Departure delay: ${stopToFix.departureDelay} seconds.`); } //If there is no delay, we can just set the departure time to the planned departure time. else { stopToFix.departureTime = stopToFix.plannedDepartureTime.getTime() / 1000; //Log what was fixed, the original stop time, the new arrival time, the new departure time and the delay. - console.info(`[StopUpdateCollection] Fixed stop ${stopToFix.stopId}: ${stopToFix.name} [${stopToFix.sequence}] Arrival time: ${new Date(stopToFix.arrivalTime * 1000)} Departure time: ${new Date(stopToFix.departureTime * 1000)} Original stop time: ${orignalStopTime} seconds. Arrival delay: ${stopToFix.arrivalDelay} seconds. Departure delay: ${stopToFix.departureDelay} seconds.`); + //console.info(`[StopUpdateCollection] Fixed stop ${stopToFix.stopId}: ${stopToFix.name} [${stopToFix.sequence}] Arrival time: ${new Date(stopToFix.arrivalTime * 1000)} Departure time: ${new Date(stopToFix.departureTime * 1000)} Original stop time: ${orignalStopTime} seconds. Arrival delay: ${stopToFix.arrivalDelay} seconds. Departure delay: ${stopToFix.departureDelay} seconds.`); } } diff --git a/src/Models/TrainUpdateCollection.ts b/src/Models/TrainUpdateCollection.ts index 53211be..5fd456a 100644 --- a/src/Models/TrainUpdateCollection.ts +++ b/src/Models/TrainUpdateCollection.ts @@ -32,7 +32,7 @@ export class TrainUpdateCollection extends Collection { //We do this so we can check if this update is there the next iteration as well, if not, we add a new stop time update //that cancels the trip. if(trainUpdate.hasCustomTripId && !this.TrainUpdatesWithCustomTripId.find(u => u.trip.tripId == trainUpdate.trip.tripId)) { - console.log(`[TrainUpdateCollection] Adding ${trainUpdate.trip.tripId} to TrainUpdatesWithCustomTripId array.`) + // console.log(`[TrainUpdateCollection] Adding ${trainUpdate.trip.tripId} to TrainUpdatesWithCustomTripId array.`) this.TrainUpdatesWithCustomTripId.push(trainUpdate); }