use configuration package for georouter

This commit is contained in:
Sylvain Briat 2023-10-31 16:11:56 +01:00
parent c5bf6102e6
commit 8befcc3c80
17 changed files with 96 additions and 177 deletions

View File

@ -21,43 +21,3 @@ REDIS_MATCHING_TTL=900
# CACHE
CACHE_TTL=5000
# DEFAULT CONFIGURATION
# algorithm type
ALGORITHM=PASSENGER_ORIENTED
# max distance in metres between driver
# route and passenger pick-up / drop-off
REMOTENESS=15000
# use passenger proportion
USE_PROPORTION=true
# minimal driver proportion
PROPORTION=0.3
# use azimuth calculation
USE_AZIMUTH=true
# azimuth margin
AZIMUTH_MARGIN=10
# margin duration in seconds
MARGIN_DURATION=900
# default validity duration (in days) for recurrent proposals
VALIDITY_DURATION=365
# max detour ratio
MAX_DETOUR_DISTANCE_RATIO=0.3
MAX_DETOUR_DURATION_RATIO=0.3
# gerouter type
GEOROUTER_TYPE=graphhopper
# georouter url
GEOROUTER_URL=http://localhost:8989
# default carpool departure time margin (in seconds)
DEPARTURE_TIME_MARGIN=900
# default role
ROLE=passenger
# seats proposes as driver / requested as passenger
SEATS_PROPOSED=3
SEATS_REQUESTED=1
# accept only same frequency requests
STRICT_FREQUENCY=false
# default timezone
TIMEZONE=Europe/Paris
# number of matching results per page
PER_PAGE=10

8
package-lock.json generated
View File

@ -11,7 +11,7 @@
"dependencies": {
"@grpc/grpc-js": "^1.9.9",
"@grpc/proto-loader": "^0.7.10",
"@mobicoop/configuration-module": "^7.1.0",
"@mobicoop/configuration-module": "^7.2.1",
"@mobicoop/ddd-library": "^2.1.1",
"@mobicoop/health-module": "^2.3.1",
"@mobicoop/message-broker-module": "^2.1.1",
@ -1573,9 +1573,9 @@
}
},
"node_modules/@mobicoop/configuration-module": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@mobicoop/configuration-module/-/configuration-module-7.1.0.tgz",
"integrity": "sha512-7AlfiTEntt1ZTqzCONMJ3hauaXaDpt44hUhKVkZNR6/54JfJCBb29nlEuZFXOwrVjuuoqjmaozRw/txlPmIbaA==",
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/@mobicoop/configuration-module/-/configuration-module-7.2.1.tgz",
"integrity": "sha512-PGY80+uN33yKSxvqcR2CPlAbhEY67xYfVDqkphIoqGb5qAwioVZH5a8InJw4Zg0Q5bx0ZQG5pcK0jha7kSxqzQ==",
"dependencies": {
"@songkeys/nestjs-redis": "^10.0.0",
"ioredis": "^5.3.2"

View File

@ -33,7 +33,7 @@
"@grpc/grpc-js": "^1.9.9",
"@grpc/proto-loader": "^0.7.10",
"@songkeys/nestjs-redis": "^10.0.0",
"@mobicoop/configuration-module": "^7.1.0",
"@mobicoop/configuration-module": "^7.2.1",
"@mobicoop/ddd-library": "^2.1.1",
"@mobicoop/health-module": "^2.3.1",
"@mobicoop/message-broker-module": "^2.1.1",

View File

@ -1,6 +1,5 @@
import {
ConfigurationDomain,
ConfigurationKey,
ConfigurationDomainGet,
ConfigurationType,
} from '@mobicoop/configuration-module';
@ -10,33 +9,24 @@ export const CARPOOL_CONFIG_SEATS_REQUESTED = 'seatsRequested';
export const CARPOOL_CONFIG_DEPARTURE_TIME_MARGIN = 'departureTimeMargin';
export const CARPOOL_CONFIG_STRICT_FREQUENCY = 'strictFrequency';
export const CarpoolConfig: {
domain: ConfigurationDomain;
key: ConfigurationKey;
type: ConfigurationType;
}[] = [
export const CarpoolConfig: ConfigurationDomainGet[] = [
{
domain: ConfigurationDomain.CARPOOL,
key: CARPOOL_CONFIG_ROLE,
type: ConfigurationType.STRING,
},
{
domain: ConfigurationDomain.CARPOOL,
key: CARPOOL_CONFIG_SEATS_PROPOSED,
type: ConfigurationType.INT,
},
{
domain: ConfigurationDomain.CARPOOL,
key: CARPOOL_CONFIG_SEATS_REQUESTED,
type: ConfigurationType.INT,
},
{
domain: ConfigurationDomain.CARPOOL,
key: CARPOOL_CONFIG_DEPARTURE_TIME_MARGIN,
type: ConfigurationType.INT,
},
{
domain: ConfigurationDomain.CARPOOL,
key: CARPOOL_CONFIG_STRICT_FREQUENCY,
type: ConfigurationType.BOOLEAN,
},

View File

@ -39,7 +39,7 @@ import {
MATCH_CONFIG_USE_AZIMUTH,
MATCH_CONFIG_USE_PROPORTION,
MatchConfig,
PAGINATION_CONFG_PER_PAGE,
PAGINATION_CONFIG_PER_PAGE,
PaginationConfig,
} from '@modules/ad/match.constants';
@ -112,7 +112,7 @@ export class MatchQueryHandler implements IQueryHandler {
})
.setDefaultPagination({
page: 1,
perPage: paginationConfigurator.get<number>(PAGINATION_CONFG_PER_PAGE),
perPage: paginationConfigurator.get<number>(PAGINATION_CONFIG_PER_PAGE),
})
.setDatesAndSchedule(this.datetimeTransformer);
let matchingEntity: MatchingEntity | undefined = await this._cachedMatching(

View File

@ -30,6 +30,8 @@ export class AdCreatedMessageHandler {
waypoints: createdAd.waypoints,
}),
);
} catch (e: any) {}
} catch (e: any) {
console.log(e);
}
}
}

View File

@ -1,6 +1,5 @@
import {
ConfigurationDomain,
ConfigurationKey,
ConfigurationDomainGet,
ConfigurationType,
} from '@mobicoop/configuration-module';
@ -12,63 +11,46 @@ export const MATCH_CONFIG_USE_AZIMUTH = 'useAzimuth';
export const MATCH_CONFIG_AZIMUTH_MARGIN = 'azimuthMargin';
export const MATCH_CONFIG_MAX_DETOUR_DISTANCE_RATIO = 'maxDetourDistanceRatio';
export const MATCH_CONFIG_MAX_DETOUR_DURATION_RATIO = 'maxDetourDurationRatio';
export const PAGINATION_CONFG_PER_PAGE = 'perPage';
export const PAGINATION_CONFIG_PER_PAGE = 'perPage';
export const MatchConfig: {
domain: ConfigurationDomain;
key: ConfigurationKey;
type: ConfigurationType;
}[] = [
export const MatchConfig: ConfigurationDomainGet[] = [
{
domain: ConfigurationDomain.MATCH,
key: MATCH_CONFIG_ALGORITHM,
type: ConfigurationType.STRING,
},
{
domain: ConfigurationDomain.MATCH,
key: MATCH_CONFIG_REMOTENESS,
type: ConfigurationType.INT,
},
{
domain: ConfigurationDomain.MATCH,
key: MATCH_CONFIG_USE_PROPORTION,
type: ConfigurationType.BOOLEAN,
},
{
domain: ConfigurationDomain.MATCH,
key: MATCH_CONFIG_PROPORTION,
type: ConfigurationType.FLOAT,
},
{
domain: ConfigurationDomain.MATCH,
key: MATCH_CONFIG_USE_AZIMUTH,
type: ConfigurationType.BOOLEAN,
},
{
domain: ConfigurationDomain.MATCH,
key: MATCH_CONFIG_AZIMUTH_MARGIN,
type: ConfigurationType.INT,
},
{
domain: ConfigurationDomain.MATCH,
key: MATCH_CONFIG_MAX_DETOUR_DISTANCE_RATIO,
type: ConfigurationType.FLOAT,
},
{
domain: ConfigurationDomain.MATCH,
key: MATCH_CONFIG_MAX_DETOUR_DURATION_RATIO,
type: ConfigurationType.FLOAT,
},
];
export const PaginationConfig: {
domain: ConfigurationDomain;
key: ConfigurationKey;
type: ConfigurationType;
}[] = [
export const PaginationConfig: ConfigurationDomainGet[] = [
{
domain: ConfigurationDomain.PAGINATION,
key: PAGINATION_CONFG_PER_PAGE,
key: PAGINATION_CONFIG_PER_PAGE,
type: ConfigurationType.INT,
},
];

View File

@ -40,7 +40,7 @@ import {
MATCH_CONFIG_REMOTENESS,
MATCH_CONFIG_USE_AZIMUTH,
MATCH_CONFIG_USE_PROPORTION,
PAGINATION_CONFG_PER_PAGE,
PAGINATION_CONFIG_PER_PAGE,
} from '@modules/ad/match.constants';
import { Test, TestingModule } from '@nestjs/testing';
@ -335,7 +335,7 @@ const mockConfigurationRepository: GetConfigurationRepositoryPort = {
return new Configurator(ConfigurationDomain.PAGINATION, [
{
domain: ConfigurationDomain.PAGINATION,
key: PAGINATION_CONFG_PER_PAGE,
key: PAGINATION_CONFIG_PER_PAGE,
value: 10,
},
]);

View File

@ -1,5 +0,0 @@
import { DefaultParams } from '../types/default-params.type';
export interface DefaultParamsProviderPort {
getParams(): DefaultParams;
}

View File

@ -1,4 +0,0 @@
export type DefaultParams = {
GEOROUTER_TYPE?: string;
GEOROUTER_URL?: string;
};

View File

@ -0,0 +1,18 @@
import {
ConfigurationDomainGet,
ConfigurationType,
} from '@mobicoop/configuration-module';
export const GEOGRAPHY_CONFIG_GEOROUTER_TYPE = 'georouterType';
export const GEOGRAPHY_CONFIG_GEOROUTER_URL = 'georouterUrl';
export const GeographyConfig: ConfigurationDomainGet[] = [
{
key: GEOGRAPHY_CONFIG_GEOROUTER_TYPE,
type: ConfigurationType.STRING,
},
{
key: GEOGRAPHY_CONFIG_GEOROUTER_URL,
type: ConfigurationType.STRING,
},
];

View File

@ -2,3 +2,6 @@ export const PARAMS_PROVIDER = Symbol('PARAMS_PROVIDER');
export const DIRECTION_ENCODER = Symbol('DIRECTION_ENCODER');
export const GEOROUTER = Symbol('GEOROUTER');
export const GEODESIC = Symbol('GEODESIC');
export const GEOGRAPHY_CONFIGURATION_REPOSITORY = Symbol(
'GEOGRAPHY_CONFIGURATION_REPOSITORY',
);

View File

@ -3,10 +3,9 @@ import { CqrsModule } from '@nestjs/cqrs';
import {
DIRECTION_ENCODER,
GEODESIC,
GEOGRAPHY_CONFIGURATION_REPOSITORY,
GEOROUTER,
PARAMS_PROVIDER,
} from './geography.di-tokens';
import { DefaultParamsProvider } from './infrastructure/default-params-provider';
import { PostgresDirectionEncoder } from './infrastructure/postgres-direction-encoder';
import { GetBasicRouteController } from './interface/controllers/get-basic-route.controller';
import { RouteMapper } from './route.mapper';
@ -15,6 +14,7 @@ import { GraphhopperGeorouter } from './infrastructure/graphhopper-georouter';
import { HttpModule } from '@nestjs/axios';
import { GetRouteQueryHandler } from './core/application/queries/get-route/get-route.query-handler';
import { GetDetailedRouteController } from './interface/controllers/get-detailed-route.controller';
import { ConfigurationRepository } from '@mobicoop/configuration-module';
const queryHandlers: Provider[] = [GetRouteQueryHandler];
@ -22,8 +22,8 @@ const mappers: Provider[] = [RouteMapper];
const adapters: Provider[] = [
{
provide: PARAMS_PROVIDER,
useClass: DefaultParamsProvider,
provide: GEOGRAPHY_CONFIGURATION_REPOSITORY,
useClass: ConfigurationRepository,
},
{
provide: DIRECTION_ENCODER,

View File

@ -1,13 +0,0 @@
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { DefaultParamsProviderPort } from '../core/application/ports/default-params-provider.port';
import { DefaultParams } from '../core/application/types/default-params.type';
@Injectable()
export class DefaultParamsProvider implements DefaultParamsProviderPort {
constructor(private readonly configService: ConfigService) {}
getParams = (): DefaultParams => ({
GEOROUTER_TYPE: this.configService.get('GEOROUTER_TYPE'),
GEOROUTER_URL: this.configService.get('GEOROUTER_URL'),
});
}

View File

@ -3,8 +3,10 @@ import { HttpService } from '@nestjs/axios';
import { GeorouterPort } from '../core/application/ports/georouter.port';
import { GeorouterSettings } from '../core/application/types/georouter-settings.type';
import { Route, Step, Point } from '../core/domain/route.types';
import { DefaultParamsProviderPort } from '../core/application/ports/default-params-provider.port';
import { GEODESIC, PARAMS_PROVIDER } from '../geography.di-tokens';
import {
GEODESIC,
GEOGRAPHY_CONFIGURATION_REPOSITORY,
} from '../geography.di-tokens';
import { catchError, lastValueFrom, map } from 'rxjs';
import { AxiosError, AxiosResponse } from 'axios';
import {
@ -12,6 +14,15 @@ import {
RouteNotFoundException,
} from '../core/domain/route.errors';
import { GeodesicPort } from '../core/application/ports/geodesic.port';
import {
ConfigurationDomain,
Configurator,
GetConfigurationRepositoryPort,
} from '@mobicoop/configuration-module';
import {
GEOGRAPHY_CONFIG_GEOROUTER_URL,
GeographyConfig,
} from '../geography.constants';
@Injectable()
export class GraphhopperGeorouter implements GeorouterPort {
@ -20,20 +31,24 @@ export class GraphhopperGeorouter implements GeorouterPort {
constructor(
private readonly httpService: HttpService,
@Inject(PARAMS_PROVIDER)
private readonly defaultParamsProvider: DefaultParamsProviderPort,
@Inject(GEOGRAPHY_CONFIGURATION_REPOSITORY)
private readonly configurationRepository: GetConfigurationRepositoryPort,
@Inject(GEODESIC) private readonly geodesic: GeodesicPort,
) {
this.url = [
defaultParamsProvider.getParams().GEOROUTER_URL,
'/route?',
].join('');
}
) {}
route = async (
waypoints: Point[],
settings: GeorouterSettings,
): Promise<Route> => {
const geographyConfigurator: Configurator =
await this.configurationRepository.mget(
ConfigurationDomain.GEOGRAPHY,
GeographyConfig,
);
this.url = [
geographyConfigurator.get<string>(GEOGRAPHY_CONFIG_GEOROUTER_URL),
'/route?',
].join('');
this._setDefaultUrlArgs();
this._setSettings(settings);
return this._getRoute(waypoints);

View File

@ -1,48 +0,0 @@
import { DefaultParams } from '@modules/geography/core/application/types/default-params.type';
import { DefaultParamsProvider } from '@modules/geography/infrastructure/default-params-provider';
import { ConfigService } from '@nestjs/config';
import { Test, TestingModule } from '@nestjs/testing';
const mockConfigService = {
get: jest.fn().mockImplementation((value: string) => {
switch (value) {
case 'GEOROUTER_TYPE':
return 'graphhopper';
case 'GEOROUTER_URL':
return 'http://localhost:8989';
default:
return 'some_default_value';
}
}),
};
describe('DefaultParamsProvider', () => {
let defaultParamsProvider: DefaultParamsProvider;
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [],
providers: [
DefaultParamsProvider,
{
provide: ConfigService,
useValue: mockConfigService,
},
],
}).compile();
defaultParamsProvider = module.get<DefaultParamsProvider>(
DefaultParamsProvider,
);
});
it('should be defined', () => {
expect(defaultParamsProvider).toBeDefined();
});
it('should provide default params', async () => {
const params: DefaultParams = defaultParamsProvider.getParams();
expect(params.GEOROUTER_TYPE).toBe('graphhopper');
expect(params.GEOROUTER_URL).toBe('http://localhost:8989');
});
});

View File

@ -1,13 +1,19 @@
import { DefaultParamsProviderPort } from '@modules/geography/core/application/ports/default-params-provider.port';
import {
ConfigurationDomain,
ConfigurationDomainGet,
Configurator,
GetConfigurationRepositoryPort,
} from '@mobicoop/configuration-module';
import { GeodesicPort } from '@modules/geography/core/application/ports/geodesic.port';
import {
GeorouterUnavailableException,
RouteNotFoundException,
} from '@modules/geography/core/domain/route.errors';
import { Route, Step } from '@modules/geography/core/domain/route.types';
import { GEOGRAPHY_CONFIG_GEOROUTER_URL } from '@modules/geography/geography.constants';
import {
GEODESIC,
PARAMS_PROVIDER,
GEOGRAPHY_CONFIGURATION_REPOSITORY,
} from '@modules/geography/geography.di-tokens';
import { GraphhopperGeorouter } from '@modules/geography/infrastructure/graphhopper-georouter';
import { HttpService } from '@nestjs/axios';
@ -262,10 +268,23 @@ const mockGeodesic: GeodesicPort = {
distance: jest.fn().mockImplementation(() => 50000),
};
const mockDefaultParamsProvider: DefaultParamsProviderPort = {
getParams: jest.fn().mockImplementation(() => ({
GEOROUTER_URL: 'http://localhost:8989',
})),
const mockConfigurationRepository: GetConfigurationRepositoryPort = {
get: jest.fn(),
mget: jest.fn().mockImplementation(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
(domain: ConfigurationDomain, configs: ConfigurationDomainGet[]) => {
switch (domain) {
case ConfigurationDomain.GEOGRAPHY:
return new Configurator(ConfigurationDomain.GEOGRAPHY, [
{
domain: ConfigurationDomain.GEOGRAPHY,
key: GEOGRAPHY_CONFIG_GEOROUTER_URL,
value: 'http://localhost:8989',
},
]);
}
},
),
};
describe('Graphhopper Georouter', () => {
@ -281,8 +300,8 @@ describe('Graphhopper Georouter', () => {
useValue: mockHttpService,
},
{
provide: PARAMS_PROVIDER,
useValue: mockDefaultParamsProvider,
provide: GEOGRAPHY_CONFIGURATION_REPOSITORY,
useValue: mockConfigurationRepository,
},
{
provide: GEODESIC,