From 172169b36e695ba5b024ab84f45c837d80945c62 Mon Sep 17 00:00:00 2001 From: Victor Lopez Date: Wed, 2 Oct 2024 17:07:42 +0200 Subject: [PATCH] Fix: Fix failover in access network info The previous method was not reliable and failing when rate limit on ipinfo, changed so when it fails request the net info from ipv4. --- src/app/searchcountry/searchcountry.page.ts | 2 +- .../services/measurement-client.service.ts | 14 +- src/app/services/network.service.ts | 166 +++++++----------- src/app/services/schedule.service.ts | 18 +- 4 files changed, 77 insertions(+), 123 deletions(-) diff --git a/src/app/searchcountry/searchcountry.page.ts b/src/app/searchcountry/searchcountry.page.ts index 4b51010..17c2089 100644 --- a/src/app/searchcountry/searchcountry.page.ts +++ b/src/app/searchcountry/searchcountry.page.ts @@ -1046,7 +1046,7 @@ export class SearchcountryPage { /* Store school id and giga id inside storage */ let countryData = {}; - this.networkService.getAccessInformation().subscribe((c) => { + this.networkService.getNetInfo().then((c) => { console.log(c); this.selectedCountry = c.country; this.detectedCountry = c.country; diff --git a/src/app/services/measurement-client.service.ts b/src/app/services/measurement-client.service.ts index 272f433..cf56c8c 100644 --- a/src/app/services/measurement-client.service.ts +++ b/src/app/services/measurement-client.service.ts @@ -90,7 +90,7 @@ export class MeasurementClientService { await this.finalizeMeasurement(measurementRecord); } catch (error) { console.error('Error running ndt7 test:', error); - this.broadcastMeasurementStatus('error', { error: error.message }); + this.broadcastMeasurementStatus('onError', { error: error.message }); } } @@ -109,13 +109,13 @@ export class MeasurementClientService { }; } - private getTestInfo() { - return forkJoin({ - accessInformation: this.networkService.getAccessInformation(), - mlabInformation: this.mlabService.findServer( + private async getTestInfo() { + return { + accessInformation: await this.networkService.getNetInfo(), + mlabInformation: await this.mlabService.findServer( this.settingsService.get('metroSelection') - ), - }).toPromise(); + ).toPromise(), + }; } private getTestCallbacks(measurementRecord: any) { diff --git a/src/app/services/network.service.ts b/src/app/services/network.service.ts index e609e5d..f989212 100644 --- a/src/app/services/network.service.ts +++ b/src/app/services/network.service.ts @@ -1,22 +1,53 @@ import { Injectable } from '@angular/core'; import { map, catchError } from 'rxjs/operators'; -import { throwError } from 'rxjs'; +import { throwError } from 'rxjs'; import { Network } from '@awesome-cordova-plugins/network/ngx'; import { HttpClient, HttpHeaders } from '@angular/common/http'; + + +type Ip4Data = { + organization: string; + country: string; + asn: number; + area_code: string; + organization_name: string; + country_code: string; + country_code3: string; + continent_code: string; + latitude: string; + region: string; + city: string; + longitude: string; + accuracy: number; + ip: string; + timezone: string; +}; + +type IpInfoData = { + ip: string; + hostname: string; + city: string; + region: string; + country: string; + loc: string; + org: string; + postal: string; + timezone: string; +}; @Injectable({ providedIn: 'root' }) export class NetworkService { accessServiceUrl = 'https://ipinfo.io?token=9906baf67eda8b'; - // accessServiceUrl = 'https://ipinfo.io?token=060bdd9da6a22f'; //ONLY FOR LOCAL DEV TESTING + // accessServiceUrl = 'https://ipinfo.io?token=060bdd9da6a22f'; //ONLY FOR LOCAL DEV TESTING headers: any; options: any; currentAccessInformation: any; connectionType = { - 'icon': 'ion-help', - 'label': 'Unknown', + icon: 'ion-help', + label: 'Unknown', } - constructor( private http: HttpClient, private network: Network ) { + constructor(private http: HttpClient, private network: Network) { const headersItem = new HttpHeaders({ 'Content-Type': 'application/json' }); @@ -24,112 +55,35 @@ export class NetworkService { } /** - * Return client network information from ipinfo - * @returns current access information + * Retrieves network information. + * @returns {Promise} A promise that resolves to the network information. */ - getAccessInformation(){ - this.options = {headers: this.headers}; - // this.currentAccessInformation = this.getNetworkInfo(); - // return this.currentAccessInformation; - var response = this.http.get(this.accessServiceUrl, this.options) - .pipe( - map( - (response: any) => { - console.log('resss', response) - if(!response){ - this.currentAccessInformation = this.getNetworkInfo(); - return this.currentAccessInformation; - } - this.currentAccessInformation = response; - let asnRegex = new RegExp('^(AS[0-9]+)\\w+(.+)'); - this.currentAccessInformation.asn = this.currentAccessInformation.org.replace(asnRegex, "$1"); - this.currentAccessInformation.org = this.currentAccessInformation.org.replace(asnRegex, "$2"); - return this.currentAccessInformation; - } - ) - ); - if(response == null || response == undefined){ - console.log('errror') - } else{ - console.log('no error') - } - return response; - - - } - async getNetworkInfo() { + async getNetInfo() { + console.log('getNetInfo'); + const options = { headers: this.headers }; + let response = null; try { - const response = await fetch('https://ipv4.geojs.io/v1/ip/geo.json'); - const data = await response.json(); - - return data; + response = await this.http.get(this.accessServiceUrl, options).toPromise(); } catch (error) { - console.log('Error:', error); - return null; + console.error('Error:', error); + const ipGeoResponse = await fetch('https://ipv4.geojs.io/v1/ip/geo.json'); + const ipGeoData = await ipGeoResponse.json(); + return this.mapData(ipGeoData); } - } - /** - * - * @param connectionClass - * @returns Connection information of client - */ - getConnectionInformation(connectionClass){ - let connectSubscription = this.network.onConnect().subscribe(() => { - console.log('network connected!'); - // `unknown`, `ethernet`, `wifi`, `2g`, `3g`, `4g`, `cellular`, `none` - setTimeout(() => { - switch(connectionClass){ - case 'wifi': - this.connectionType.icon = 'ion-wifi'; - this.connectionType.label = 'Wi-Fi'; - break; - case '2g': - this.connectionType.icon = 'ion-connection-bars'; - this.connectionType.label = 'Mobile Data (2G)'; - break; - case '3g': - this.connectionType.icon = 'ion-connection-bars'; - this.connectionType.label = 'Mobile Data (3G)'; - break; - case '4g': - this.connectionType.icon = 'ion-connection-bars'; - this.connectionType.label = 'Mobile Data (4G)'; - break; - case 'cellular': - this.connectionType.icon = 'ion-connection-bars'; - this.connectionType.label = 'Mobile Data'; - break; - case 'ethernet': - this.connectionType.icon = 'ion-connection-bars'; - this.connectionType.label = 'Mobile Data'; - break; - default: - break; - } - }, 3000); - }); - - // stop connect watch - connectSubscription.unsubscribe(); - return this.connectionType; + return response; } - /** - * - * @returns current network information - */ - currentConnectionInformation(){ - let connectionClass = undefined; - connectionClass = this.network.type; - return this.getConnectionInformation(connectionClass); - } - - /** - * Private function to handle error - * @param error - * @returns Error - */ - private handleError(error: Response) { - return throwError(error); + private mapData(source: Ip4Data): IpInfoData { + return { + ip: source.ip, + hostname: source.ip, + city: source.city || "", + region: source.region || "", + country: source.country_code, + loc: `${source.latitude},${source.longitude}`, + org: source.organization || source.organization_name, + postal: "", + timezone: source.timezone, + }; } } diff --git a/src/app/services/schedule.service.ts b/src/app/services/schedule.service.ts index fd19392..9f4fd2f 100644 --- a/src/app/services/schedule.service.ts +++ b/src/app/services/schedule.service.ts @@ -17,7 +17,7 @@ export class ScheduleService { private sharedService: SharedService, private networkService: NetworkService, private customScheduleService: CustomScheduleService - ) {} + ) { } initiate() { this.watch(); @@ -72,7 +72,7 @@ export class ScheduleService { scheduleSemaphore.choice !== undefined && currentTime > scheduleSemaphore.choice ) { - const networkInfo = await this.networkService.getNetworkInfo(); + const networkInfo = await this.networkService.getNetInfo(); if (networkInfo === null) { console.log('Network not available, skipping schedule check.'); this.storageService.set('measurementOfReconnect', true); @@ -81,13 +81,13 @@ export class ScheduleService { } console.log( 'On ' + - new Date(currentTime).toUTCString() + - ' found scheduled test covering ' + - new Date(scheduleSemaphore.start).toUTCString() + - ' and ' + - new Date(scheduleSemaphore.end).toUTCString() + - ' scheduled to run near ' + - new Date(scheduleSemaphore.choice).toUTCString() + new Date(currentTime).toUTCString() + + ' found scheduled test covering ' + + new Date(scheduleSemaphore.start).toUTCString() + + ' and ' + + new Date(scheduleSemaphore.end).toUTCString() + + ' scheduled to run near ' + + new Date(scheduleSemaphore.choice).toUTCString() ); console.log('Found scheduled measurement ready, triggering.'); this.storageService.set('lastMeasurement', currentTime);