Skip to content

Commit

Permalink
refactor: get rid of useless sorting
Browse files Browse the repository at this point in the history
  • Loading branch information
alexey-yarmosh committed Jul 10, 2023
1 parent 2b9ff73 commit 57f89e8
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 25 deletions.
24 changes: 3 additions & 21 deletions src/lib/geoip/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export default class GeoipClient {
.then(([ ip2location, ipmap, maxmind, ipinfo, fastly ]) => {
const fulfilled: (LocationInfoWithProvider | null)[] = [];

// Providers here are pushed in a desc prioritized order
fulfilled.push(
ip2location.status === 'fulfilled' ? { ...ip2location.value, provider: 'ip2location' } : null,
ipmap.status === 'fulfilled' ? { ...ipmap.value, provider: 'ipmap' } : null,
Expand Down Expand Up @@ -147,29 +148,10 @@ export default class GeoipClient {
}

private bestMatch (field: keyof LocationInfo, sources: LocationInfoWithProvider[]): [LocationInfo, LocationInfoWithProvider[]] {
const DESC_PRIORITY_OF_PROVIDERS: Provider[] = [ 'ip2location', 'ipmap', 'maxmind', 'ipinfo', 'fastly' ];
const filtered = sources.filter(s => s[field]);
// Initially sort sources so they are sorted inside groups
const sorted = filtered.sort((sourceA, sourceB) => {
const indexSourceA = DESC_PRIORITY_OF_PROVIDERS.indexOf(sourceA.provider);
const indexSourceB = DESC_PRIORITY_OF_PROVIDERS.indexOf(sourceB.provider);
return indexSourceA - indexSourceB;
});
// Group sources by the same field value
const grouped = Object.values(_.groupBy(sorted, field));
const ranked = grouped.sort((sourcesA, sourcesB) => {
// Move bigger groups to the beginning
const groupsSizeDiff = sourcesB.length - sourcesA.length;

if (groupsSizeDiff === 0) {
// If group sizes are equal move the group with the prioritized item to the beginning
const smallestIndexSourceA = DESC_PRIORITY_OF_PROVIDERS.indexOf((sourcesA[0] as LocationInfoWithProvider).provider);
const smallestIndexSourceB = DESC_PRIORITY_OF_PROVIDERS.indexOf((sourcesA[0] as LocationInfoWithProvider).provider);
return smallestIndexSourceA - smallestIndexSourceB;
}

return groupsSizeDiff;
}).flat();
const grouped = Object.values(_.groupBy(filtered, field));
const ranked = grouped.sort((a, b) => b.length - a.length).flat();

const best = ranked[0];

Expand Down
29 changes: 25 additions & 4 deletions test/tests/unit/geoip.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,31 @@ describe('geoip service', () => {
});
});

it('should choose top prioritized provider when there is a draw in returned results', async () => {
nockGeoIpProviders({ ipmap: 'argentina', ip2location: 'emptyCity', maxmind: 'newYork', ipinfo: 'argentina', fastly: 'newYork' });

const info = await client.lookup(MOCK_IP);

expect(info).to.deep.equal({
continent: 'SA',
country: 'AR',
state: undefined,
city: 'Buenos Aires',
region: 'South America',
normalizedRegion: 'south america',
normalizedCity: 'buenos aires',
asn: 61004,
latitude: -34.002,
longitude: -58.002,
network: 'InterBS S.R.L. (BAEHOST)',
normalizedNetwork: 'interbs s.r.l. (baehost)',
});
});

it('should choose top prioritized provider when all providers returned different cities', async () => {
nockGeoIpProviders({ ipmap: 'default', ip2location: 'argentina', maxmind: 'newYork', ipinfo: 'emptyCity', fastly: 'bangkok' });

const info = await client.lookup(MOCK_IP).catch((error: Error) => error);
const info = await client.lookup(MOCK_IP);

expect(info).to.deep.equal({
continent: 'SA',
Expand Down Expand Up @@ -359,7 +380,7 @@ describe('geoip service', () => {
it('should pass - non-vpn', async () => {
nockGeoIpProviders();

const response: LocationInfo | Error = await client.lookup(MOCK_IP).catch((error: Error) => error);
const response: LocationInfo | Error = await client.lookup(MOCK_IP);

expect(response).to.deep.equal({
continent: 'NA',
Expand All @@ -380,7 +401,7 @@ describe('geoip service', () => {
it('should pass - no client object', async () => {
nockGeoIpProviders({ fastly: 'noClient' });

const response: LocationInfo | Error = await client.lookup(MOCK_IP).catch((error: Error) => error);
const response: LocationInfo | Error = await client.lookup(MOCK_IP);

expect(response).to.deep.equal({
continent: 'NA',
Expand Down Expand Up @@ -409,7 +430,7 @@ describe('geoip service', () => {

nockGeoIpProviders({ fastly: 'proxyDescVpn' });

const response: LocationInfo | Error = await client.lookup(MOCK_IP).catch((error: Error) => error);
const response: LocationInfo | Error = await client.lookup(MOCK_IP);

expect(response).to.deep.equal({
continent: 'NA',
Expand Down

0 comments on commit 57f89e8

Please sign in to comment.