mirror of
https://github.com/brendan-ch/project-inter-server.git
synced 2026-04-19 08:50:29 +00:00
Add support back in for external source ETA repositories, if we switch back later
This commit is contained in:
@@ -22,6 +22,7 @@ import { RedisSelfUpdatingETARepository } from "../repositories/shuttle/eta/Redi
|
|||||||
import { RedisExternalSourceETARepository } from "../repositories/shuttle/eta/RedisExternalSourceETARepository";
|
import { RedisExternalSourceETARepository } from "../repositories/shuttle/eta/RedisExternalSourceETARepository";
|
||||||
import { InMemorySelfUpdatingETARepository } from "../repositories/shuttle/eta/InMemorySelfUpdatingETARepository";
|
import { InMemorySelfUpdatingETARepository } from "../repositories/shuttle/eta/InMemorySelfUpdatingETARepository";
|
||||||
import { BaseRedisETARepository } from "../repositories/shuttle/eta/BaseRedisETARepository";
|
import { BaseRedisETARepository } from "../repositories/shuttle/eta/BaseRedisETARepository";
|
||||||
|
import { BaseInMemoryETARepository } from "../repositories/shuttle/eta/BaseInMemoryETARepository";
|
||||||
|
|
||||||
export interface InterchangeSystemBuilderArguments {
|
export interface InterchangeSystemBuilderArguments {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -99,24 +100,33 @@ export class InterchangeSystem {
|
|||||||
private static async buildRedisShuttleLoaderAndRepositories(args: InterchangeSystemBuilderArguments) {
|
private static async buildRedisShuttleLoaderAndRepositories(args: InterchangeSystemBuilderArguments) {
|
||||||
const shuttleRepository = new RedisShuttleRepository();
|
const shuttleRepository = new RedisShuttleRepository();
|
||||||
await shuttleRepository.connect();
|
await shuttleRepository.connect();
|
||||||
const shuttleDataLoader = new ApiBasedShuttleRepositoryLoader(
|
|
||||||
args.passioSystemId,
|
|
||||||
args.id,
|
|
||||||
shuttleRepository
|
|
||||||
);
|
|
||||||
const timedShuttleDataLoader = new TimedApiBasedRepositoryLoader(
|
|
||||||
shuttleDataLoader
|
|
||||||
);
|
|
||||||
|
|
||||||
let etaRepository: BaseRedisETARepository;
|
let etaRepository: BaseRedisETARepository;
|
||||||
|
let shuttleDataLoader: ApiBasedShuttleRepositoryLoader;
|
||||||
if (args.useSelfUpdatingEtas) {
|
if (args.useSelfUpdatingEtas) {
|
||||||
etaRepository = new RedisSelfUpdatingETARepository(shuttleRepository);
|
etaRepository = new RedisSelfUpdatingETARepository(shuttleRepository);
|
||||||
(etaRepository as RedisSelfUpdatingETARepository).startListeningForUpdates();
|
(etaRepository as RedisSelfUpdatingETARepository).startListeningForUpdates();
|
||||||
|
shuttleDataLoader = new ApiBasedShuttleRepositoryLoader(
|
||||||
|
args.passioSystemId,
|
||||||
|
args.id,
|
||||||
|
shuttleRepository,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
etaRepository = new RedisExternalSourceETARepository();
|
etaRepository = new RedisExternalSourceETARepository();
|
||||||
|
shuttleDataLoader = new ApiBasedShuttleRepositoryLoader(
|
||||||
|
args.passioSystemId,
|
||||||
|
args.id,
|
||||||
|
shuttleRepository,
|
||||||
|
etaRepository as RedisExternalSourceETARepository,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
await etaRepository.connect();
|
await etaRepository.connect();
|
||||||
|
|
||||||
|
const timedShuttleDataLoader = new TimedApiBasedRepositoryLoader(
|
||||||
|
shuttleDataLoader,
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
return { shuttleRepository, etaRepository, timedShuttleDataLoader };
|
return { shuttleRepository, etaRepository, timedShuttleDataLoader };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,23 +248,33 @@ export class InterchangeSystem {
|
|||||||
|
|
||||||
private static buildInMemoryShuttleLoaderAndRepositories(args: InterchangeSystemBuilderArguments) {
|
private static buildInMemoryShuttleLoaderAndRepositories(args: InterchangeSystemBuilderArguments) {
|
||||||
const shuttleRepository = new UnoptimizedInMemoryShuttleRepository();
|
const shuttleRepository = new UnoptimizedInMemoryShuttleRepository();
|
||||||
const shuttleDataLoader = new ApiBasedShuttleRepositoryLoader(
|
|
||||||
args.passioSystemId,
|
let etaRepository: BaseInMemoryETARepository;
|
||||||
args.id,
|
let shuttleDataLoader: ApiBasedShuttleRepositoryLoader;
|
||||||
shuttleRepository
|
if (args.useSelfUpdatingEtas) {
|
||||||
);
|
etaRepository = new InMemorySelfUpdatingETARepository(shuttleRepository);
|
||||||
|
(etaRepository as InMemorySelfUpdatingETARepository).startListeningForUpdates();
|
||||||
|
shuttleDataLoader = new ApiBasedShuttleRepositoryLoader(
|
||||||
|
args.passioSystemId,
|
||||||
|
args.id,
|
||||||
|
shuttleRepository,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
etaRepository = new InMemoryExternalSourceETARepository();
|
||||||
|
shuttleDataLoader = new ApiBasedShuttleRepositoryLoader(
|
||||||
|
args.passioSystemId,
|
||||||
|
args.id,
|
||||||
|
shuttleRepository,
|
||||||
|
etaRepository as InMemoryExternalSourceETARepository,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Note that this loader should not be started,
|
// Note that this loader should not be started,
|
||||||
// so the test data doesn't get overwritten
|
// so the test data doesn't get overwritten
|
||||||
const timedShuttleLoader = new TimedApiBasedRepositoryLoader(
|
const timedShuttleLoader = new TimedApiBasedRepositoryLoader(
|
||||||
shuttleDataLoader
|
shuttleDataLoader
|
||||||
);
|
);
|
||||||
|
|
||||||
let etaRepository: ETAGetterRepository;
|
|
||||||
if (args.useSelfUpdatingEtas) {
|
|
||||||
etaRepository = new InMemorySelfUpdatingETARepository(shuttleRepository);
|
|
||||||
} else {
|
|
||||||
etaRepository = new InMemoryExternalSourceETARepository();
|
|
||||||
}
|
|
||||||
|
|
||||||
return { shuttleRepository, etaRepository, timedShuttleLoader };
|
return { shuttleRepository, etaRepository, timedShuttleLoader };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { ShuttleGetterSetterRepository } from "../../repositories/shuttle/ShuttleGetterSetterRepository";
|
import { ShuttleGetterSetterRepository } from "../../repositories/shuttle/ShuttleGetterSetterRepository";
|
||||||
import { IRoute, IShuttle, IStop } from "../../entities/ShuttleRepositoryEntities";
|
import { IEta, IRoute, IShuttle, IStop } from "../../entities/ShuttleRepositoryEntities";
|
||||||
import { ShuttleRepositoryLoader } from "./ShuttleRepositoryLoader";
|
import { ShuttleRepositoryLoader } from "./ShuttleRepositoryLoader";
|
||||||
import { ICoordinates, IEntityWithId } from "../../entities/SharedEntities";
|
import { ICoordinates, IEntityWithId } from "../../entities/SharedEntities";
|
||||||
import { ApiResponseError } from "../ApiResponseError";
|
import { ApiResponseError } from "../ApiResponseError";
|
||||||
import { SHUTTLE_TO_ROUTE_COORDINATE_MAXIMUM_DISTANCE_MILES } from "../../environment";
|
import { SHUTTLE_TO_ROUTE_COORDINATE_MAXIMUM_DISTANCE_MILES } from "../../environment";
|
||||||
|
import { ExternalSourceETARepository } from "../../repositories/shuttle/eta/ExternalSourceETARepository";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class which can load data into a repository from the
|
* Class which can load data into a repository from the
|
||||||
@@ -16,7 +17,8 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader
|
|||||||
constructor(
|
constructor(
|
||||||
public passioSystemId: string,
|
public passioSystemId: string,
|
||||||
public systemIdForConstructedData: string,
|
public systemIdForConstructedData: string,
|
||||||
public repository: ShuttleGetterSetterRepository,
|
public shuttleRepository: ShuttleGetterSetterRepository,
|
||||||
|
public etaRepository?: ExternalSourceETARepository,
|
||||||
readonly shuttleToRouteCoordinateMaximumDistanceMiles = SHUTTLE_TO_ROUTE_COORDINATE_MAXIMUM_DISTANCE_MILES,
|
readonly shuttleToRouteCoordinateMaximumDistanceMiles = SHUTTLE_TO_ROUTE_COORDINATE_MAXIMUM_DISTANCE_MILES,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
@@ -34,6 +36,10 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader
|
|||||||
await this.updateRouteDataForSystem();
|
await this.updateRouteDataForSystem();
|
||||||
await this.updateStopAndPolylineDataForRoutesInSystem();
|
await this.updateStopAndPolylineDataForRoutesInSystem();
|
||||||
await this.updateShuttleDataForSystemBasedOnProximityToRoutes();
|
await this.updateShuttleDataForSystemBasedOnProximityToRoutes();
|
||||||
|
|
||||||
|
// Because ETA method doesn't support pruning yet,
|
||||||
|
// add a call to the clear method here
|
||||||
|
await this.updateEtaDataForExistingStopsForSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateRouteDataForSystem() {
|
public async updateRouteDataForSystem() {
|
||||||
@@ -52,16 +58,16 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader
|
|||||||
|
|
||||||
private async updateRouteDataInRepository(routes: IRoute[]) {
|
private async updateRouteDataInRepository(routes: IRoute[]) {
|
||||||
const routeIdsToPrune = await this.constructExistingEntityIdSet(async () => {
|
const routeIdsToPrune = await this.constructExistingEntityIdSet(async () => {
|
||||||
return await this.repository.getRoutes();
|
return await this.shuttleRepository.getRoutes();
|
||||||
});
|
});
|
||||||
|
|
||||||
await Promise.all(routes.map(async (route) => {
|
await Promise.all(routes.map(async (route) => {
|
||||||
await this.repository.addOrUpdateRoute(route);
|
await this.shuttleRepository.addOrUpdateRoute(route);
|
||||||
routeIdsToPrune.delete(route.id);
|
routeIdsToPrune.delete(route.id);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await Promise.all(Array.from(routeIdsToPrune).map(async (routeId) => {
|
await Promise.all(Array.from(routeIdsToPrune).map(async (routeId) => {
|
||||||
await this.repository.removeRouteIfExists(routeId);
|
await this.shuttleRepository.removeRouteIfExists(routeId);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +123,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader
|
|||||||
|
|
||||||
private async updateStopAndPolylineDataInRepository(json: any) {
|
private async updateStopAndPolylineDataInRepository(json: any) {
|
||||||
const stopIdsToPrune = await this.constructExistingEntityIdSet(async () => {
|
const stopIdsToPrune = await this.constructExistingEntityIdSet(async () => {
|
||||||
return await this.repository.getStops();
|
return await this.shuttleRepository.getStops();
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.updateStopDataForSystemAndApiResponse(json, stopIdsToPrune);
|
await this.updateStopDataForSystemAndApiResponse(json, stopIdsToPrune);
|
||||||
@@ -125,7 +131,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader
|
|||||||
await this.updatePolylineDataForExistingRoutesAndApiResponse(json);
|
await this.updatePolylineDataForExistingRoutesAndApiResponse(json);
|
||||||
|
|
||||||
await Promise.all(Array.from(stopIdsToPrune).map(async (stopId) => {
|
await Promise.all(Array.from(stopIdsToPrune).map(async (stopId) => {
|
||||||
await this.repository.removeStopIfExists(stopId);
|
await this.shuttleRepository.removeStopIfExists(stopId);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,16 +175,16 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader
|
|||||||
|
|
||||||
private async updateShuttleDataInRepository(shuttles: IShuttle[]) {
|
private async updateShuttleDataInRepository(shuttles: IShuttle[]) {
|
||||||
const shuttleIdsToPrune = await this.constructExistingEntityIdSet(async () => {
|
const shuttleIdsToPrune = await this.constructExistingEntityIdSet(async () => {
|
||||||
return await this.repository.getShuttles();
|
return await this.shuttleRepository.getShuttles();
|
||||||
});
|
});
|
||||||
|
|
||||||
await Promise.all(shuttles.map(async (shuttle) => {
|
await Promise.all(shuttles.map(async (shuttle) => {
|
||||||
await this.repository.addOrUpdateShuttle(shuttle);
|
await this.shuttleRepository.addOrUpdateShuttle(shuttle);
|
||||||
shuttleIdsToPrune.delete(shuttle.id);
|
shuttleIdsToPrune.delete(shuttle.id);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await Promise.all(Array.from(shuttleIdsToPrune).map(async (shuttleId) => {
|
await Promise.all(Array.from(shuttleIdsToPrune).map(async (shuttleId) => {
|
||||||
await this.repository.removeShuttleIfExists(shuttleId);
|
await this.shuttleRepository.removeShuttleIfExists(shuttleId);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,6 +239,66 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async updateEtaDataForExistingStopsForSystem() {
|
||||||
|
const stops = await this.shuttleRepository.getStops();
|
||||||
|
await Promise.all(stops.map(async (stop) => {
|
||||||
|
let stopId = stop.id;
|
||||||
|
await this.updateEtaDataForStopId(stopId);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updateEtaDataForStopId(stopId: string) {
|
||||||
|
try {
|
||||||
|
const json = await this.fetchEtaDataJson(stopId);
|
||||||
|
const etas = this.constructEtasFromJson(json, stopId);
|
||||||
|
if (etas !== null) {
|
||||||
|
await this.updateEtaDataInRepository(etas);
|
||||||
|
} else {
|
||||||
|
console.warn(`ETA update failed for stop ${stopId} with the following JSON: ${JSON.stringify(json)}`);
|
||||||
|
}
|
||||||
|
} catch(e: any) {
|
||||||
|
throw new ApiResponseError(e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async updateEtaDataInRepository(etas: IEta[]) {
|
||||||
|
await Promise.all(etas.map(async (eta) => {
|
||||||
|
await this.etaRepository?.addOrUpdateEtaFromExternalSource(eta);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async fetchEtaDataJson(stopId: string) {
|
||||||
|
const params = {
|
||||||
|
eta: "3",
|
||||||
|
stopIds: stopId,
|
||||||
|
};
|
||||||
|
|
||||||
|
const query = new URLSearchParams(params).toString();
|
||||||
|
|
||||||
|
const response = await fetch(`${this.baseUrl}?${query}`, {
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
return await response.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
private constructEtasFromJson(json: any, stopId: string): IEta[] | null {
|
||||||
|
if (json.ETAs && json.ETAs[stopId]) {
|
||||||
|
return json.ETAs[stopId].map((jsonEta: any) => {
|
||||||
|
const shuttleId: string = jsonEta.busId;
|
||||||
|
const eta: IEta = {
|
||||||
|
secondsRemaining: jsonEta.secondsSpent,
|
||||||
|
shuttleId: `${shuttleId}`,
|
||||||
|
stopId: stopId,
|
||||||
|
updatedTime: new Date(),
|
||||||
|
systemId: this.systemIdForConstructedData,
|
||||||
|
};
|
||||||
|
return eta;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
protected async updateStopDataForSystemAndApiResponse(
|
protected async updateStopDataForSystemAndApiResponse(
|
||||||
json: any,
|
json: any,
|
||||||
setOfIdsToPrune: Set<string> = new Set(),
|
setOfIdsToPrune: Set<string> = new Set(),
|
||||||
@@ -252,7 +318,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader
|
|||||||
updatedTime: new Date(),
|
updatedTime: new Date(),
|
||||||
};
|
};
|
||||||
|
|
||||||
await this.repository.addOrUpdateStop(constructedStop);
|
await this.shuttleRepository.addOrUpdateStop(constructedStop);
|
||||||
|
|
||||||
setOfIdsToPrune.delete(constructedStop.id);
|
setOfIdsToPrune.delete(constructedStop.id);
|
||||||
}));
|
}));
|
||||||
@@ -274,7 +340,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader
|
|||||||
const orderedStopDataArray = jsonOrderedStopData[index];
|
const orderedStopDataArray = jsonOrderedStopData[index];
|
||||||
|
|
||||||
const stopId = orderedStopDataArray[1];
|
const stopId = orderedStopDataArray[1];
|
||||||
let constructedOrderedStop = await this.repository.getOrderedStopByRouteAndStopId(routeId, stopId)
|
let constructedOrderedStop = await this.shuttleRepository.getOrderedStopByRouteAndStopId(routeId, stopId)
|
||||||
if (constructedOrderedStop === null) {
|
if (constructedOrderedStop === null) {
|
||||||
constructedOrderedStop = {
|
constructedOrderedStop = {
|
||||||
routeId,
|
routeId,
|
||||||
@@ -304,7 +370,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.repository.addOrUpdateOrderedStop(constructedOrderedStop);
|
await this.shuttleRepository.addOrUpdateOrderedStop(constructedOrderedStop);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -315,7 +381,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader
|
|||||||
await Promise.all(Object.keys(json.routePoints).map(async (routeId) => {
|
await Promise.all(Object.keys(json.routePoints).map(async (routeId) => {
|
||||||
const routePoints = json.routePoints[routeId][0];
|
const routePoints = json.routePoints[routeId][0];
|
||||||
|
|
||||||
const existingRoute = await this.repository.getRouteById(routeId);
|
const existingRoute = await this.shuttleRepository.getRouteById(routeId);
|
||||||
if (!existingRoute) return;
|
if (!existingRoute) return;
|
||||||
|
|
||||||
existingRoute.polylineCoordinates = routePoints.map((point: any) => {
|
existingRoute.polylineCoordinates = routePoints.map((point: any) => {
|
||||||
@@ -325,7 +391,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.repository.addOrUpdateRoute(existingRoute);
|
await this.shuttleRepository.addOrUpdateRoute(existingRoute);
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -334,7 +400,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader
|
|||||||
let filteredShuttles: IShuttle[] = [];
|
let filteredShuttles: IShuttle[] = [];
|
||||||
|
|
||||||
await Promise.all(shuttles.map(async (shuttle) => {
|
await Promise.all(shuttles.map(async (shuttle) => {
|
||||||
const route = await this.repository.getRouteById(shuttle.routeId);
|
const route = await this.shuttleRepository.getRouteById(shuttle.routeId);
|
||||||
if (route != null) {
|
if (route != null) {
|
||||||
let closestDistanceMiles = Number.MAX_VALUE;
|
let closestDistanceMiles = Number.MAX_VALUE;
|
||||||
|
|
||||||
|
|||||||
@@ -4,4 +4,6 @@ export interface ShuttleRepositoryLoader extends RepositoryLoader {
|
|||||||
updateRouteDataForSystem(): Promise<void>;
|
updateRouteDataForSystem(): Promise<void>;
|
||||||
updateStopAndPolylineDataForRoutesInSystem(): Promise<void>;
|
updateStopAndPolylineDataForRoutesInSystem(): Promise<void>;
|
||||||
updateShuttleDataForSystemBasedOnProximityToRoutes(): Promise<void>;
|
updateShuttleDataForSystemBasedOnProximityToRoutes(): Promise<void>;
|
||||||
|
updateEtaDataForExistingStopsForSystem(): Promise<void>;
|
||||||
|
updateEtaDataForStopId(stopId: string): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user