import { Inject, Injectable } from '@nestjs/common'; import { readFileSync } from 'fs'; import { WINSTON_MODULE_PROVIDER } from 'nest-winston'; import { join } from 'path'; import { CityAndStateResult, CountyResult, GeoResult, IpInfo } from 'src/models/main.model'; import { Logger } from 'winston'; import { City, CountyData, Geo, State } from '../models/server.model'; import { RealIpInfo } from './geo.controller'; // const __filename = fileURLToPath(import.meta.url); // const __dirname = path.dirname(__filename); @Injectable() export class GeoService { geo: Geo; counties: CountyData[]; constructor(@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger) { this.loadGeo(); } private loadGeo(): void { const filePath = join(__dirname, '../..', 'assets', 'geo.json'); const rawData = readFileSync(filePath, 'utf8'); this.geo = JSON.parse(rawData); const countiesFilePath = join(__dirname, '../..', 'assets', 'counties.json'); const rawCountiesData = readFileSync(countiesFilePath, 'utf8'); this.counties = JSON.parse(rawCountiesData); } findCountiesStartingWith(prefix: string, states?: string[]) { const results: CountyResult[] = []; let idCounter = 1; this.counties.forEach(stateData => { if (!states || states.includes(stateData.state)) { stateData.counties.forEach(county => { if (county.startsWith(prefix.toUpperCase())) { results.push({ id: idCounter++, name: county, state: stateData.state_full, state_code: stateData.state, }); } }); } }); return results; } findCitiesStartingWith(prefix: string, state?: string): GeoResult[] { const result: GeoResult[] = []; this.geo.states.forEach((state: State) => { state.cities.forEach((city: City) => { if (city.name.toLowerCase().startsWith(prefix.toLowerCase())) { result.push({ id: city.id, name: city.name, state: state.state_code, //state_code: state.state_code, latitude: city.latitude, longitude: city.longitude, }); } }); }); return state ? result.filter(e => e.state.toLowerCase() === state.toLowerCase()) : result; } findCitiesAndStatesStartingWith(prefix: string): Array { const results: Array = []; const lowercasePrefix = prefix.toLowerCase(); //for (const country of this.geo) { // Suche nach passenden Staaten for (const state of this.geo.states) { if (state.name.toLowerCase().startsWith(lowercasePrefix)) { results.push({ id: state.id, type: 'state', content: state, }); } // Suche nach passenden Städten for (const city of state.cities) { if (city.name.toLowerCase().startsWith(lowercasePrefix)) { results.push({ id: city.id, type: 'city', content: { state: state.state_code, ...city }, }); } } //} } return results.sort((a, b) => { if (a.type === 'state' && b.type === 'city') return -1; if (a.type === 'city' && b.type === 'state') return 1; return a.content.name.localeCompare(b.content.name); }); } getCityWithCoords(state: string, city: string): City { return this.geo.states.find(s => s.state_code === state).cities.find(c => c.name === city); } async fetchIpAndGeoLocation(ipInfo: RealIpInfo): Promise { this.logger.info(`IP:${ipInfo.ip} - CountryCode:${ipInfo.countryCode}`); const response = await fetch(`${process.env.IP_INFO_URL}/${ipInfo.ip}/geo?token=${process.env.IP_INFO_TOKEN}`, { method: 'GET', }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); // Fügen Sie den Ländercode aus Cloudflare hinzu, falls verfügbar if (ipInfo.countryCode) { data.cloudflareCountry = ipInfo.countryCode; } return data; } }