Skip to content

Commit

Permalink
Merge pull request #59 from openplannerteam/feature/error-classes
Browse files Browse the repository at this point in the history
Error classes
  • Loading branch information
maximtmartin authored Jan 10, 2019
2 parents 59ed454 + 71167f7 commit ef371d1
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 92 deletions.
5 changes: 5 additions & 0 deletions src/Context.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @ts-ignore
import { EventEmitter, Listener } from "events";
import { Container, injectable } from "inversify";
import EventType from "./EventType";

/**
* The Context serves as event pass through and holder of the inversify container object.
Expand Down Expand Up @@ -35,6 +36,10 @@ export default class Context implements EventEmitter {
return this.emitter.emit(type, ...args);
}

public emitWarning(...args: any[]): boolean {
return this.emit(EventType.Warning, ...args);
}

public listenerCount(type: string | symbol): number {
return this.emitter.listenerCount(type);
}
Expand Down
9 changes: 7 additions & 2 deletions src/EventType.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
enum EventType {
Query = "query",
QueryExponential = "query-exponential",
QueryAbort = "query-abort",
AbortQuery = "abort-query",
InvalidQuery = "invalid-query",

LDFetchGet = "ldfetch-get",

Warning = "warning",

ConnectionScan = "connection-scan",
FinalReachableStops = "final-reachable-stops",
InitialReachableStops = "initial-reachable-stops",
FinalReachableStops = "final-reachable-stops",
AddedNewTransferProfile = "added-new-transfer-profile",
}

Expand Down
18 changes: 13 additions & 5 deletions src/Planner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,21 @@ export default class Planner implements EventEmitter {
public async query(query: IQuery): Promise<AsyncIterator<IPath>> {
this.emit(EventType.Query, query);

const iterator = await this.queryRunner.run(query);
try {
const iterator = await this.queryRunner.run(query);

this.once(EventType.QueryAbort, () => {
iterator.close();
});
this.once(EventType.AbortQuery, () => {
iterator.close();
});

return iterator;
return iterator;
} catch (e) {
if (e.eventType) {
this.context.emit(e.eventType, e.message);
}

return Promise.reject();
}
}

public addListener(type: string | symbol, listener: Listener): this {
Expand Down
74 changes: 45 additions & 29 deletions src/demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@ export default async (logResults) => {
let scannedConnections = 0;

planner
.on(EventType.Query, (query) => {
console.log("Query", query);
.on(EventType.InvalidQuery, (error) => {
console.log("InvalidQuery", error);
})
.on(EventType.AbortQuery, (reason) => {
console.log("AbortQuery", reason);
})
.on(EventType.Query, () => {
console.log("Query");
})
.on(EventType.QueryExponential, (query) => {
const { minimumDepartureTime, maximumArrivalTime } = query;
Expand All @@ -28,42 +34,52 @@ export default async (logResults) => {
})
.on(EventType.ConnectionScan, (connection) => {
scannedConnections++;
})
.on(EventType.Warning, (e) => {
console.warn(e);
});
}

const publicTransportResult = await planner.query({
publicTransportOnly: true,
// from: "https://data.delijn.be/stops/201657",
// to: "https://data.delijn.be/stops/205910",
// from: "https://data.delijn.be/stops/200455", // Deinze weg op Grammene +456
// to: "https://data.delijn.be/stops/502481", // Tielt Metaalconstructie Goossens
// from: "https://data.delijn.be/stops/509927", // Tield Rameplein perron 1
// to: "https://data.delijn.be/stops/200455", // Deinze weg op Grammene +456
from: "http://irail.be/stations/NMBS/008896925", // Ingelmunster
to: "http://irail.be/stations/NMBS/008892007", // Ghent-Sint-Pieters
minimumDepartureTime: new Date(),
maximumTransferDuration: Units.fromHours(0.5),
});

return new Promise((resolve, reject) => {
let i = 0;
planner.query({
publicTransportOnly: true,
// from: "https://data.delijn.be/stops/201657",
// to: "https://data.delijn.be/stops/205910",
// from: "https://data.delijn.be/stops/200455", // Deinze weg op Grammene +456
// to: "https://data.delijn.be/stops/502481", // Tielt Metaalconstructie Goossens
// from: "https://data.delijn.be/stops/509927", // Tield Rameplein perron 1
// to: "https://data.delijn.be/stops/200455", // Deinze weg op Grammene +456
from: "http://irail.be/stations/NMBS/008896925", // Ingelmunster
to: "http://irail.be/stations/NMBS/008892007", // Ghent-Sint-Pieters
minimumDepartureTime: new Date("2019-01-10T08:13:20.530Z"),
maximumTransferDuration: Units.fromHours(0.5),
})
.then((publicTransportResult) => {

let i = 0;

publicTransportResult.take(3)
.on("data", (path: IPath) => {
++i;
publicTransportResult.take(3)
.on("data", (path: IPath) => {
++i;

if (logResults) {
console.log(i);
console.log(JSON.stringify(path, null, " "));
console.log("\n");
}
if (logResults) {
console.log(i);
console.log(JSON.stringify(path, null, " "));
console.log("\n");
}

if (i === 3) {
resolve(true);
}
})
.on("end", () => {
resolve(false);
});

if (i === 3) {
resolve(true);
}
})
.on("end", () => {
.catch(() => {
resolve(false);
});
});

};
5 changes: 5 additions & 0 deletions src/errors/InvalidQueryError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import EventType from "../EventType";

export default class InvalidQueryError extends Error {
public eventType = EventType.InvalidQuery;
}
3 changes: 3 additions & 0 deletions src/errors/LocationResolverError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default class LocationResolverError extends Error {

}
20 changes: 13 additions & 7 deletions src/planner/public-transport/JourneyExtractorDefault.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ArrayIterator, AsyncIterator } from "asynciterator";
import { inject, injectable } from "inversify";
import Context from "../../Context";
import IConnection from "../../fetcher/connections/IConnection";
import ILocation from "../../interfaces/ILocation";
import IPath from "../../interfaces/IPath";
Expand Down Expand Up @@ -28,9 +29,14 @@ export default class JourneyExtractorDefault implements IJourneyExtractor {
private readonly locationResolver: ILocationResolver;

private bestArrivalTime: number[][] = [];
private context: Context;

constructor(@inject(TYPES.LocationResolver) locationResolver: ILocationResolver) {
constructor(
@inject(TYPES.LocationResolver) locationResolver: ILocationResolver,
@inject(TYPES.Context)context?: Context,
) {
this.locationResolver = locationResolver;
this.context = context;
}

public async extractJourneys(
Expand Down Expand Up @@ -72,7 +78,7 @@ export default class JourneyExtractorDefault implements IJourneyExtractor {
transferProfile.arrivalTime,
);
} catch (e) {
console.warn(e);
this.context.emitWarning(e);
}
}
}
Expand Down Expand Up @@ -173,17 +179,17 @@ export default class JourneyExtractorDefault implements IJourneyExtractor {
// Get next profile based on the arrival time at the current location.
if (remainingTransfers >= 0) {
const currentProfiles: IProfile[] = profilesByStop[currentLocation.id];
let i: number = currentProfiles.length - 1;
let profileIndex: number = currentProfiles.length - 1;

currentTransferProfile = currentProfiles[i].transferProfiles[remainingTransfers];
currentTransferProfile = currentProfiles[profileIndex].transferProfiles[remainingTransfers];
departureTime = new Date(currentTransferProfile.departureTime);

while (i >= 0 && departureTime < exitConnection.arrivalTime) {
currentTransferProfile = currentProfiles[--i].transferProfiles[remainingTransfers];
while (profileIndex >= 0 && departureTime < exitConnection.arrivalTime) {
currentTransferProfile = currentProfiles[--profileIndex].transferProfiles[remainingTransfers];
departureTime = new Date(currentTransferProfile.departureTime);
}

if (i === -1) {
if (profileIndex === -1) {
// This should never happen.
return Promise.reject("Can't find next connection");
}
Expand Down
98 changes: 59 additions & 39 deletions src/planner/public-transport/PublicTransportPlannerCSAProfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,18 +88,6 @@ export default class PublicTransportPlannerCSAProfile implements IPublicTranspor
public async plan(query: IResolvedQuery): Promise<AsyncIterator<IPath>> {
this.query = query;

const departureLocation = this.query.from[0];
if (!departureLocation.id) {
departureLocation.id = "geo:" + departureLocation.latitude + "," + departureLocation.longitude;
departureLocation.name = "Departure location";
}

const arrivalLocation = this.query.to[0];
if (!arrivalLocation.id) {
arrivalLocation.id = "geo:" + arrivalLocation.latitude + "," + arrivalLocation.longitude;
arrivalLocation.name = "Arrival location";
}

this.setBounds();

return this.calculateJourneys();
Expand Down Expand Up @@ -224,7 +212,7 @@ export default class PublicTransportPlannerCSAProfile implements IPublicTranspor

private calculateEarliestArrivalTime(connection: IConnection): IArrivalTimeByTransfers {
const remainSeatedTime = this.remainSeated(connection);
if (connection["gtfs:dropOffType"] === "gtfs:NotAvailable") {
if (connection["gtfs:dropOffType"] === DropOffType.NotAvailable) {
return remainSeatedTime;
}

Expand All @@ -246,7 +234,7 @@ export default class PublicTransportPlannerCSAProfile implements IPublicTranspor
);

if (reachableStops.length === 0 && this.context) {
this.context.emit(EventType.QueryAbort);
this.context.emit(EventType.AbortQuery, "No reachable stops at arrival location");

return false;
}
Expand All @@ -256,9 +244,18 @@ export default class PublicTransportPlannerCSAProfile implements IPublicTranspor
}

for (const reachableStop of reachableStops) {
if (!this.query.to[0].id && reachableStop.duration === 0) {
this.query.to[0] = reachableStop.stop;
}

this.durationToTargetByStop[reachableStop.stop.id] = reachableStop.duration;
}

if (!this.query.to[0].id) {
this.query.to[0].id = "geo:" + this.query.to[0].latitude + "," + this.query.to[0].longitude;
this.query.to[0].name = "Arrival location";
}

return true;
}

Expand All @@ -272,8 +269,21 @@ export default class PublicTransportPlannerCSAProfile implements IPublicTranspor
this.query.minimumWalkingSpeed,
);

const stopIndex = 0;
while (stopIndex < this.initialReachableStops.length && !this.query.from[0].id) {
const reachableStop = this.initialReachableStops[stopIndex];
if (reachableStop.duration === 0) {
this.query.from[0] = reachableStop.stop;
}
}

if (!this.query.from[0].id) {
this.query.from[0].id = "geo:" + this.query.from[0].latitude + "," + this.query.from[0].longitude;
this.query.from[0].name = "Departure location";
}

if (this.initialReachableStops.length === 0 && this.context) {
this.context.emit(EventType.QueryAbort);
this.context.emit(EventType.AbortQuery, "No reachable stops at departure location");

return false;
}
Expand Down Expand Up @@ -402,35 +412,45 @@ export default class PublicTransportPlannerCSAProfile implements IPublicTranspor
);
}

const departureStop: ILocation = await this.locationResolver.resolve(connection.departureStop);
const reachableStops: IReachableStop[] = await this.transferReachableStopsFinder.findReachableStops(
departureStop as IStop,
ReachableStopsFinderMode.Source,
this.query.maximumWalkingDuration,
this.query.minimumWalkingSpeed,
);
try {
const departureStop: ILocation = await this.locationResolver.resolve(connection.departureStop);
const reachableStops: IReachableStop[] = await this.transferReachableStopsFinder.findReachableStops(
departureStop as IStop,
ReachableStopsFinderMode.Source,
this.query.maximumWalkingDuration,
this.query.minimumWalkingSpeed,
);

reachableStops.forEach((reachableStop: IReachableStop) => {
if (reachableStop.stop.id !== departureLocation.id) {
this.incorporateInProfile(
connection,
reachableStop.duration,
reachableStop.stop,
earliestArrivalTimeByTransfers,
);
}
});
reachableStops.forEach((reachableStop: IReachableStop) => {
if (reachableStop.stop.id !== departureLocation.id) {
this.incorporateInProfile(
connection,
reachableStop.duration,
reachableStop.stop,
earliestArrivalTimeByTransfers,
);
}
});

} catch (e) {
this.context.emitWarning(e);
}
}

private async emitTransferProfile(transferProfile: ITransferProfile, amountOfTransfers: number): Promise<void> {
const departureStop = await this.locationResolver.resolve(transferProfile.enterConnection.departureStop);
const arrivalStop = await this.locationResolver.resolve(transferProfile.exitConnection.arrivalStop);
try {
const departureStop = await this.locationResolver.resolve(transferProfile.enterConnection.departureStop);
const arrivalStop = await this.locationResolver.resolve(transferProfile.exitConnection.arrivalStop);

this.context.emit(EventType.AddedNewTransferProfile, {
departureStop,
arrivalStop,
amountOfTransfers,
});
this.context.emit(EventType.AddedNewTransferProfile, {
departureStop,
arrivalStop,
amountOfTransfers,
});

} catch (e) {
this.context.emitWarning(e);
}
}

private incorporateInProfile(
Expand Down
Loading

0 comments on commit ef371d1

Please sign in to comment.