Skip to content

Commit

Permalink
refactored method of generating headers, added getRoute method
Browse files Browse the repository at this point in the history
  • Loading branch information
lionralfs committed Feb 12, 2018
1 parent bc2658c commit 7476811
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 116 deletions.
35 changes: 21 additions & 14 deletions src/hvvclient.ts
Original file line number Diff line number Diff line change
@@ -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<InitResponse>;
init(req: InitRequest): Promise<InitResponse>;
checkName(req: CNRequest): Promise<CNResponse>;
getRoute(): void;
getRoute(req: GRRequest): Promise<GRResponse>;
departureList(): void;
getTariff(): void;
departureCourse(): void;
Expand Down Expand Up @@ -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<CNResponse> {
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<GRResponse> {
const headers = generateHeaders(this.options, req);
return getRoute(headers, this.options, req);
}

/**
Expand Down Expand Up @@ -130,7 +134,9 @@ export default class HVVClient implements HVVClientInterface {
* Returns a list of stations
*/
public listStations(req?: LSRequest): Promise<LSResponse> {
return listStations(this.options, req);
const reqObj = req || {};
const headers = generateHeaders(this.options, reqObj);
return listStations(headers, this.options, reqObj);
}

/**
Expand All @@ -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);
}

/**
Expand Down
21 changes: 11 additions & 10 deletions src/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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,
Expand Down
19 changes: 13 additions & 6 deletions src/requests/checkname.ts
Original file line number Diff line number Diff line change
@@ -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<CNResponse> => {
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<CNResponse> => {
return new Promise<CNResponse>((resolve, reject) => {
request({
uri: `${options.host}/gti/public/checkName`,
Expand Down
22 changes: 14 additions & 8 deletions src/requests/getannouncements.ts
Original file line number Diff line number Diff line change
@@ -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<AnnouncementResponse> => {
const signature = signRequest(req, options.key);
const headers = generateHeaders(options, signature);

return new Promise<AnnouncementResponse>((resolve, reject) => {
request({
uri: `${options.host}/gti/public/getAnnouncements`,
Expand Down
77 changes: 77 additions & 0 deletions src/requests/getroute.ts
Original file line number Diff line number Diff line change
@@ -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<GRResponse>((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');
}
};
15 changes: 10 additions & 5 deletions src/requests/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<InitResponse> => {
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<InitResponse> => {
return new Promise<InitResponse>((resolve, reject) => {
request({
uri: `${options.host}/gti/public/init`,
Expand Down
21 changes: 14 additions & 7 deletions src/requests/liststations.ts
Original file line number Diff line number Diff line change
@@ -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<LSResponse> => {
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<LSResponse> => {
return new Promise<LSResponse>((resolve, reject) => {
request({
uri: `${options.host}/gti/public/listStations`,
Expand Down
59 changes: 1 addition & 58 deletions src/requests/requesttypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
10 changes: 3 additions & 7 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@
"forceConsistentCasingInFileNames": true,
"alwaysStrict": true
},
"include": [
"src/**/*.ts"
],
"exclude": [
"**/__mocks__/*"
]
}
"include": ["src/**/*.ts"],
"exclude": ["**/__mocks__/*"]
}
Loading

0 comments on commit 7476811

Please sign in to comment.