diff --git a/src/hvvclient.ts b/src/hvvclient.ts index 9d9a17a..b7dcc36 100644 --- a/src/hvvclient.ts +++ b/src/hvvclient.ts @@ -1,15 +1,16 @@ import { CoordinateType, SDType } from './enums'; -import { checkName } from './requests/checkname'; -import { init } from './requests/init'; -import { listStations } from './requests/liststations'; -import { AnnouncementRequest, CNRequest, LSRequest } from './requests/requesttypes'; +import { checkName, CNRequest } from './requests/checkname'; +import { init, InitRequest } from './requests/init'; +import { listStations, LSRequest } from './requests/liststations'; import { AnnouncementResponse, CNResponse, InitResponse, LSResponse } from './responses/responsetypes'; -import { getAnnouncements } from './requests/getannouncements'; +import { getAnnouncements, AnnouncementRequest } from './requests/getannouncements'; +import { GRRequest, getRoute, GRResponse } from './requests/getroute'; +import { generateHeaders } from './request'; export interface HVVClientInterface { - init(): Promise; + init(req: InitRequest): Promise; checkName(req: CNRequest): Promise; - getRoute(): void; + getRoute(req: GRRequest): Promise; departureList(): void; getTariff(): void; departureCourse(): void; @@ -87,22 +88,25 @@ export default class HVVClient implements HVVClientInterface { /** * Returns some server status informations (schedule validity, data version, program version, ...) */ - public init() { - return init({}, this.options); + public init(req: InitRequest) { + const headers = generateHeaders(this.options, req); + return init(headers, this.options, req); } /** * Verifies the user input and returns a list of possible unique places for that input */ public checkName(req: CNRequest): Promise { - return checkName(this.options, req); + const headers = generateHeaders(this.options, req); + return checkName(headers, this.options, req); } /** * Calculates a route for the given parameters */ - public getRoute() { - console.log('I am not implemented yet'); + public getRoute(req: GRRequest): Promise { + const headers = generateHeaders(this.options, req); + return getRoute(headers, this.options, req); } /** @@ -130,7 +134,9 @@ export default class HVVClient implements HVVClientInterface { * Returns a list of stations */ public listStations(req?: LSRequest): Promise { - return listStations(this.options, req); + const reqObj = req || {}; + const headers = generateHeaders(this.options, reqObj); + return listStations(headers, this.options, reqObj); } /** @@ -144,7 +150,8 @@ export default class HVVClient implements HVVClientInterface { * Returns a list schedule variance announcements */ public getAnnouncements(req: AnnouncementRequest) { - return getAnnouncements(req, this.options); + const headers = generateHeaders(this.options, req); + return getAnnouncements(headers, this.options, req); } /** diff --git a/src/request.ts b/src/request.ts index 487143b..2e46f19 100644 --- a/src/request.ts +++ b/src/request.ts @@ -7,15 +7,15 @@ import { CoordinateType, FilterType, RealtimeType, SimpleServiceType } from './e import { HVVClientOptions } from './hvvclient'; import { ContSearchByServiceId, GTITime, SDName, TariffInfoSelector } from './othertypes'; import { PenaltyInterface } from './penalties'; -import { BaseRequestType, RequestHeaders } from './requests/requesttypes'; +import { RequestHeaders, BaseRequest } from './requests/requesttypes'; /** * Encrypts the payload via an RFC2104 HMAC (SHA1) and base64 encoding - * @param {BaseRequestType} payload The request body to encrypt - * @param {string} key The (private) key to encrypt with - * @return {string} The encrypted message + * @param payload The request body to encrypt + * @param key The (private) key to encrypt with + * @return The encrypted message */ -export const signRequest = (payload: BaseRequestType, key: string): string => { +const signRequest = (payload: BaseRequest, key: string): string => { const hmac = crypto.createHmac('sha1', key); hmac.update(JSON.stringify(payload)); @@ -24,12 +24,13 @@ export const signRequest = (payload: BaseRequestType, key: string): string => { }; /** - * Generates all HTTP headers for a request - * @param {HVVClientOptions} options - * @param {string} signature - * @return {RequestHeaders} + * Generates all HTTP headers for a given request + * @param options The options containing the `key`, `Content-Type`, etc + * @param payload The request body + * @return */ -export const generateHeaders = (options: HVVClientOptions, signature: string): RequestHeaders => { +export const generateHeaders = (options: HVVClientOptions, payload: BaseRequest): RequestHeaders => { + const signature = signRequest(payload, options.key); const headers: RequestHeaders = { 'Content-Type': `${options.contentType};charset=UTF-8`, Accept: options.accept, diff --git a/src/requests/checkname.ts b/src/requests/checkname.ts index 3316045..cefd95e 100644 --- a/src/requests/checkname.ts +++ b/src/requests/checkname.ts @@ -1,15 +1,22 @@ import * as request from 'request-promise'; import { RequestError, StatusCodeError } from 'request-promise/errors'; -import { ReturnCode, SDType } from '../enums'; +import { ReturnCode, SDType, CoordinateType } from '../enums'; import { HVVClientOptions } from '../hvvclient'; -import { generateHeaders, signRequest } from '../request'; +import { generateHeaders } from '../request'; import { CNResponse } from '../responses/responsetypes'; -import { CNRequest } from './requesttypes'; +import { BaseRequest, RequestHeaders } from './requesttypes'; +import { SDName } from '../othertypes'; -export const checkName = (options: HVVClientOptions, req: CNRequest): Promise => { - const signature = signRequest(req, options.key); - const headers = generateHeaders(options, signature); +export interface CNRequest extends BaseRequest { + theName: SDName; + maxList?: number; + maxDistance?: number; + coordinateType?: CoordinateType; + tariffDetails?: boolean; + allowTypeSwitch?: boolean; +} +export const checkName = (headers: RequestHeaders, options: HVVClientOptions, req: CNRequest): Promise => { return new Promise((resolve, reject) => { request({ uri: `${options.host}/gti/public/checkName`, diff --git a/src/requests/getannouncements.ts b/src/requests/getannouncements.ts index 8160c63..c8a1ed5 100644 --- a/src/requests/getannouncements.ts +++ b/src/requests/getannouncements.ts @@ -1,18 +1,24 @@ import * as request from 'request-promise'; import { RequestError, StatusCodeError } from 'request-promise/errors'; -import { ReturnCode } from '../enums'; +import { ReturnCode, AnnouncementFilterPlannedType } from '../enums'; import { HVVClientOptions } from '../hvvclient'; -import { generateHeaders, signRequest } from '../request'; +import { generateHeaders } from '../request'; import { AnnouncementResponse } from '../responses/responsetypes'; -import { AnnouncementRequest } from './requesttypes'; +import { BaseRequest, RequestHeaders } from './requesttypes'; +import { TimeRange } from '../penalties'; + +export interface AnnouncementRequest extends BaseRequest { + names?: string[]; + timeRange?: TimeRange; + full?: boolean; + filterPlanned?: AnnouncementFilterPlannedType; +} export const getAnnouncements = ( - req: AnnouncementRequest, - options: HVVClientOptions + headers: RequestHeaders, + options: HVVClientOptions, + req: AnnouncementRequest ): Promise => { - const signature = signRequest(req, options.key); - const headers = generateHeaders(options, signature); - return new Promise((resolve, reject) => { request({ uri: `${options.host}/gti/public/getAnnouncements`, diff --git a/src/requests/getroute.ts b/src/requests/getroute.ts new file mode 100644 index 0000000..f5dbcad --- /dev/null +++ b/src/requests/getroute.ts @@ -0,0 +1,77 @@ +import * as request from 'request-promise'; +import { BaseRequest, RequestHeaders } from './requesttypes'; +import { HVVClientOptions } from '../hvvclient'; +import { SDName, GTITime, ContSearchByServiceId, TariffInfoSelector } from '../othertypes'; +import { CoordinateType, RealtimeType, SimpleServiceType, ReturnCode } from '../enums'; +import { PenaltyInterface } from '../penalties'; +import { BaseResponseType } from '../responses/responsetypes'; +import { StatusCodeError, RequestError } from 'request-promise/errors'; + +export interface GRRequest extends BaseRequest { + start: SDName; + dest: SDName; + via?: SDName; + time?: GTITime; + timeIsDeparture?: boolean; + numberOfSchedules?: number; + tariffDetails?: boolean; + continousSearch?: boolean; + contSearchByServiceId?: ContSearchByServiceId; + coordinateType?: CoordinateType; + schedulesBefore?: number; + schedulesAfter?: number; + returnReduced?: boolean; + tariffInfoSelector?: TariffInfoSelector[]; + penalties?: PenaltyInterface[]; + returnPartialTickets?: boolean; + realtime?: RealtimeType; + intermediateStops?: boolean; + useStationPosition?: boolean; + forcedStart?: SDName; + forcedDest?: SDName; + toStartBy?: SimpleServiceType; + toDestBy?: SimpleServiceType; + returnContSearchData?: boolean; +} + +/** getRoute Response */ +export interface GRResponse extends BaseResponseType { + asdf: string; // TODO +} + +/** + * `/getRoute` request + * @param headers + * @param options + * @param req + */ +export const getRoute = (headers: RequestHeaders, options: HVVClientOptions, req: GRRequest) => { + return new Promise((resolve, reject) => { + request({ + uri: `${options.host}/gti/public/getRoute`, + method: 'POST', + body: req, + headers, + json: true + }) + .then(res => normalizeResponse(res, resolve, reject)) + .catch(StatusCodeError, e => reject(e)) + .catch(RequestError, e => reject(e)); + }); +}; + +const normalizeResponse = (res: any, resolve: (res: any) => void, reject: (reason: string) => void) => { + switch (res.returnCode) { + case ReturnCode.OK: + resolve(res); + break; + case ReturnCode.ERROR_CN_TOO_MANY: + case ReturnCode.ERROR_COMM: + case ReturnCode.ERROR_ROUTE: + case ReturnCode.ERROR_TEXT: + reject(res); + break; + default: + reject('unknown returnCode'); + } +}; diff --git a/src/requests/init.ts b/src/requests/init.ts index e4e538e..662c2ba 100644 --- a/src/requests/init.ts +++ b/src/requests/init.ts @@ -2,14 +2,19 @@ import * as request from 'request-promise'; import { RequestError, StatusCodeError } from 'request-promise/errors'; import { ReturnCode } from '../enums'; import { HVVClientOptions } from '../hvvclient'; -import { generateHeaders, signRequest } from '../request'; import { InitResponse } from '../responses/responsetypes'; -import { BaseRequestType, InitRequest } from './requesttypes'; +import { BaseRequest, RequestHeaders } from './requesttypes'; -export const init = (req: InitRequest, options: HVVClientOptions): Promise => { - const signature = signRequest(req, options.key); - const headers = generateHeaders(options, signature); +// tslint:disable-next-line +export interface InitRequest extends BaseRequest {} +/** + * `/init` request + * @param req + * @param headers + * @param options + */ +export const init = (headers: RequestHeaders, options: HVVClientOptions, req: InitRequest): Promise => { return new Promise((resolve, reject) => { request({ uri: `${options.host}/gti/public/init`, diff --git a/src/requests/liststations.ts b/src/requests/liststations.ts index 513679d..3542e23 100644 --- a/src/requests/liststations.ts +++ b/src/requests/liststations.ts @@ -1,16 +1,23 @@ import * as request from 'request-promise'; import { RequestError, StatusCodeError } from 'request-promise/errors'; -import { ReturnCode } from '../enums'; +import { ReturnCode, ModificationType, CoordinateType } from '../enums'; import { HVVClientOptions } from '../hvvclient'; -import { generateHeaders, signRequest } from '../request'; +import { generateHeaders } from '../request'; import { LSResponse } from '../responses/responsetypes'; -import { LSRequest } from './requesttypes'; +import { BaseRequest, RequestHeaders } from './requesttypes'; -export const listStations = (options: HVVClientOptions, req?: LSRequest): Promise => { - req = req || {}; - const signature = signRequest(req, options.key); - const headers = generateHeaders(options, signature); +export interface LSRequest extends BaseRequest { + dataReleaseID?: string; + modificationTypes?: ModificationType[]; + coordinateType?: CoordinateType; + filterEquivalent?: boolean; +} +export const listStations = ( + headers: RequestHeaders, + options: HVVClientOptions, + req: LSRequest +): Promise => { return new Promise((resolve, reject) => { request({ uri: `${options.host}/gti/public/listStations`, diff --git a/src/requests/requesttypes.ts b/src/requests/requesttypes.ts index f6d5af9..eac90aa 100644 --- a/src/requests/requesttypes.ts +++ b/src/requests/requesttypes.ts @@ -21,65 +21,8 @@ export interface RequestHeaders { 'User-Agent'?: string; } -export interface BaseRequestType { +export interface BaseRequest { version?: number; language?: 'de' | 'en'; filterType?: FilterType; } - -// tslint:disable-next-line -export interface InitRequest extends BaseRequestType {} - -/** checkName Request */ -export interface CNRequest extends BaseRequestType { - theName: SDName; - maxList?: number; - maxDistance?: number; - coordinateType?: CoordinateType; - tariffDetails?: boolean; - allowTypeSwitch?: boolean; -} - -/** getRoute Request */ -export interface GRRequest extends BaseRequestType { - start: SDName; - dest: SDName; - via?: SDName; - time?: GTITime; - timeIsDeparture?: boolean; - numberOfSchedules?: number; - tariffDetails?: boolean; - continousSearch?: boolean; - contSearchByServiceId?: ContSearchByServiceId; - coordinateType?: CoordinateType; - schedulesBefore?: number; - schedulesAfter?: number; - returnReduced?: boolean; - tariffInfoSelector?: TariffInfoSelector[]; - penalties?: PenaltyInterface[]; - returnPartialTickets?: boolean; - realtime?: RealtimeType; - intermediateStops?: boolean; - useStationPosition?: boolean; - forcedStart?: SDName; - forcedDest?: SDName; - toStartBy?: SimpleServiceType; - toDestBy?: SimpleServiceType; - returnContSearchData?: boolean; -} - -/** listStations Request */ -export interface LSRequest extends BaseRequestType { - dataReleaseID?: string; - modificationTypes?: ModificationType[]; - coordinateType?: CoordinateType; - filterEquivalent?: boolean; -} - -/** getAnnouncements Request */ -export interface AnnouncementRequest extends BaseRequestType { - names?: string[]; - timeRange?: TimeRange; - full?: boolean; - filterPlanned?: AnnouncementFilterPlannedType; -} diff --git a/tsconfig.json b/tsconfig.json index cfb9a3f..cc3d85f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,10 +12,6 @@ "forceConsistentCasingInFileNames": true, "alwaysStrict": true }, - "include": [ - "src/**/*.ts" - ], - "exclude": [ - "**/__mocks__/*" - ] -} \ No newline at end of file + "include": ["src/**/*.ts"], + "exclude": ["**/__mocks__/*"] +} diff --git a/tslint.json b/tslint.json index 673345b..30bb4e6 100644 --- a/tslint.json +++ b/tslint.json @@ -5,7 +5,6 @@ "no-console": false, "object-literal-sort-keys": false, "no-submodule-imports": false, - "no-implicit-dependencies": false, "ordered-imports": false } }