237 lines
13 KiB
JavaScript
237 lines
13 KiB
JavaScript
"use strict";
|
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
};
|
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
};
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
var WeatherService_1;
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.WeatherService = exports.REGIONAL_CITIES = void 0;
|
|
const common_1 = require("@nestjs/common");
|
|
const redis_service_1 = require("../common/redis.service");
|
|
const axios_1 = __importDefault(require("axios"));
|
|
exports.REGIONAL_CITIES = [
|
|
{ name: 'Amman', name_ar: 'عمان', lat: 31.95, lng: 35.93, country: 'Jordan' },
|
|
{ name: 'Irbid', name_ar: 'إربد', lat: 32.55, lng: 35.85, country: 'Jordan' },
|
|
{ name: 'Zarqa', name_ar: 'الزرقاء', lat: 32.06, lng: 36.10, country: 'Jordan' },
|
|
{ name: 'Aqaba', name_ar: 'العقبة', lat: 29.53, lng: 35.00, country: 'Jordan' },
|
|
{ name: 'Karak', name_ar: 'الكرك', lat: 31.18, lng: 35.70, country: 'Jordan' },
|
|
{ name: 'Madaba', name_ar: 'مادبا', lat: 31.72, lng: 35.79, country: 'Jordan' },
|
|
{ name: 'Jerash', name_ar: 'جرش', lat: 32.28, lng: 35.90, country: 'Jordan' },
|
|
{ name: 'Ajloun', name_ar: 'عجلون', lat: 32.33, lng: 35.75, country: 'Jordan' },
|
|
{ name: 'Salt', name_ar: 'السلط', lat: 32.04, lng: 35.73, country: 'Jordan' },
|
|
{ name: "Ma'an", name_ar: 'معان', lat: 30.19, lng: 35.73, country: 'Jordan' },
|
|
{ name: 'Tafilah', name_ar: 'الطفيلة', lat: 30.84, lng: 35.60, country: 'Jordan' },
|
|
{ name: 'Mafraq', name_ar: 'المفرق', lat: 32.34, lng: 36.21, country: 'Jordan' },
|
|
{ name: 'Damascus', name_ar: 'دمشق', lat: 33.5138, lng: 36.2765, country: 'Syria' },
|
|
{ name: 'Aleppo', name_ar: 'حلب', lat: 36.2021, lng: 37.1343, country: 'Syria' },
|
|
{ name: 'Homs', name_ar: 'حمص', lat: 34.7324, lng: 36.7137, country: 'Syria' },
|
|
{ name: 'Latakia', name_ar: 'اللاذقية', lat: 35.5317, lng: 35.7917, country: 'Syria' },
|
|
{ name: 'Hama', name_ar: 'حماة', lat: 35.1318, lng: 36.7578, country: 'Syria' },
|
|
{ name: 'Tartus', name_ar: 'طرطوس', lat: 34.8890, lng: 35.8866, country: 'Syria' },
|
|
{ name: 'Deir ez-Zor', name_ar: 'دير الزور', lat: 35.3370, lng: 40.1444, country: 'Syria' },
|
|
{ name: 'Raqqa', name_ar: 'الرقة', lat: 35.9594, lng: 39.0089, country: 'Syria' },
|
|
{ name: 'Daraa', name_ar: 'درعا', lat: 32.6184, lng: 36.1023, country: 'Syria' },
|
|
{ name: 'As-Suwayda', name_ar: 'السويداء', lat: 32.7090, lng: 36.5695, country: 'Syria' },
|
|
{ name: 'Idlib', name_ar: 'إدلب', lat: 35.9306, lng: 36.6339, country: 'Syria' },
|
|
{ name: 'Qamishli', name_ar: 'القامشلي', lat: 37.0522, lng: 41.2228, country: 'Syria' },
|
|
{ name: 'Cairo', name_ar: 'القاهرة', lat: 30.0444, lng: 31.2357, country: 'Egypt' },
|
|
{ name: 'Alexandria', name_ar: 'الإسكندرية', lat: 31.2001, lng: 29.9187, country: 'Egypt' },
|
|
{ name: 'Giza', name_ar: 'الجيزة', lat: 30.0131, lng: 31.2089, country: 'Egypt' },
|
|
{ name: 'Port Said', name_ar: 'بورسعيد', lat: 31.2653, lng: 32.3019, country: 'Egypt' },
|
|
{ name: 'Suez', name_ar: 'السويس', lat: 29.9668, lng: 32.5498, country: 'Egypt' },
|
|
{ name: 'Luxor', name_ar: 'الأقصر', lat: 25.6872, lng: 32.6396, country: 'Egypt' },
|
|
{ name: 'Aswan', name_ar: 'أسوان', lat: 24.0889, lng: 32.8998, country: 'Egypt' },
|
|
{ name: 'Sharm El Sheikh', name_ar: 'شرم الشيخ', lat: 27.9158, lng: 34.3299, country: 'Egypt' },
|
|
{ name: 'Hurghada', name_ar: 'الغردقة', lat: 27.2579, lng: 33.8116, country: 'Egypt' },
|
|
{ name: 'Mansoura', name_ar: 'المنصورة', lat: 31.0409, lng: 31.3785, country: 'Egypt' },
|
|
{ name: 'Tanta', name_ar: 'طنطا', lat: 30.7865, lng: 31.0004, country: 'Egypt' },
|
|
{ name: 'Ismailia', name_ar: 'الإسماعيلية', lat: 30.5965, lng: 32.2715, country: 'Egypt' },
|
|
{ name: 'Marsa Matruh', name_ar: 'مرسى مطروح', lat: 31.3543, lng: 27.2373, country: 'Egypt' },
|
|
{ name: 'Asyut', name_ar: 'أسيوط', lat: 27.1783, lng: 31.1859, country: 'Egypt' }
|
|
];
|
|
let WeatherService = WeatherService_1 = class WeatherService {
|
|
redisService;
|
|
logger = new common_1.Logger(WeatherService_1.name);
|
|
constructor(redisService) {
|
|
this.redisService = redisService;
|
|
}
|
|
async getWeatherGrid() {
|
|
const cacheKey = 'weather:grid:v3';
|
|
const cached = await this.redisService.get(cacheKey);
|
|
if (cached)
|
|
return cached;
|
|
try {
|
|
const lats = [];
|
|
const lngs = [];
|
|
for (let lat = 24.0; lat <= 37.0; lat += 0.8) {
|
|
for (let lng = 26.0; lng <= 42.0; lng += 0.8) {
|
|
lats.push(Number(lat.toFixed(1)));
|
|
lngs.push(Number(lng.toFixed(1)));
|
|
}
|
|
}
|
|
const response = await axios_1.default.get('https://api.open-meteo.com/v1/forecast', {
|
|
params: {
|
|
latitude: lats.join(','),
|
|
longitude: lngs.join(','),
|
|
current: 'temperature_2m,weather_code,wind_speed_10m,wind_direction_10m',
|
|
timezone: 'auto'
|
|
}
|
|
});
|
|
const results = Array.isArray(response.data) ? response.data : [response.data];
|
|
const features = results.map((result, index) => ({
|
|
type: 'Feature',
|
|
geometry: {
|
|
type: 'Point',
|
|
coordinates: [lngs[index], lats[index]]
|
|
},
|
|
properties: {
|
|
temperature: result.current?.temperature_2m,
|
|
weatherCode: result.current?.weather_code,
|
|
windSpeed: result.current?.wind_speed_10m,
|
|
windDirection: result.current?.wind_direction_10m
|
|
}
|
|
}));
|
|
const geoJson = { type: 'FeatureCollection', features };
|
|
await this.redisService.set(cacheKey, JSON.stringify(geoJson), 900);
|
|
return geoJson;
|
|
}
|
|
catch (error) {
|
|
this.logger.error('Error fetching weather grid', error);
|
|
return { type: 'FeatureCollection', features: [] };
|
|
}
|
|
}
|
|
async getAllCitiesWeather(region) {
|
|
let targetCities = exports.REGIONAL_CITIES;
|
|
const normRegion = region ? region.trim().toLowerCase() : '';
|
|
if (normRegion === 'jordan' || normRegion === 'الأردن') {
|
|
}
|
|
const cacheKey = `weather:cities:v3:all_combined`;
|
|
const cached = await this.redisService.get(cacheKey);
|
|
if (cached)
|
|
return cached;
|
|
try {
|
|
const lats = targetCities.map(c => c.lat).join(',');
|
|
const lngs = targetCities.map(c => c.lng).join(',');
|
|
const response = await axios_1.default.get('https://api.open-meteo.com/v1/forecast', {
|
|
params: {
|
|
latitude: lats,
|
|
longitude: lngs,
|
|
current: 'temperature_2m,apparent_temperature,relative_humidity_2m,weather_code,wind_speed_10m,wind_direction_10m,cloud_cover,precipitation,is_day',
|
|
daily: 'weather_code,temperature_2m_max,temperature_2m_min,sunrise,sunset,precipitation_sum,precipitation_probability_max,wind_speed_10m_max,wind_direction_10m_dominant',
|
|
forecast_days: 7,
|
|
timezone: 'auto'
|
|
}
|
|
});
|
|
const results = Array.isArray(response.data) ? response.data : [response.data];
|
|
const citiesWeather = targetCities.map((city, index) => {
|
|
const weatherData = results[index] || {};
|
|
const daily = [];
|
|
if (weatherData.daily && weatherData.daily.time) {
|
|
for (let i = 0; i < weatherData.daily.time.length; i++) {
|
|
daily.push({
|
|
date: weatherData.daily.time[i],
|
|
weatherCode: weatherData.daily.weather_code?.[i] ?? 0,
|
|
tempMax: weatherData.daily.temperature_2m_max?.[i] ?? 25,
|
|
tempMin: weatherData.daily.temperature_2m_min?.[i] ?? 15,
|
|
precipSum: weatherData.daily.precipitation_sum?.[i] ?? 0,
|
|
precipProb: weatherData.daily.precipitation_probability_max?.[i] ?? 0,
|
|
windMax: weatherData.daily.wind_speed_10m_max?.[i] ?? 10,
|
|
windDir: weatherData.daily.wind_direction_10m_dominant?.[i] ?? 0
|
|
});
|
|
}
|
|
}
|
|
return {
|
|
name: city.name,
|
|
name_ar: city.name_ar,
|
|
lat: city.lat,
|
|
lng: city.lng,
|
|
country: city.country,
|
|
current: {
|
|
temp: weatherData.current?.temperature_2m ?? 22,
|
|
feelsLike: weatherData.current?.apparent_temperature ?? 22,
|
|
humidity: weatherData.current?.relative_humidity_2m ?? 50,
|
|
weatherCode: weatherData.current?.weather_code ?? 0,
|
|
windSpeed: weatherData.current?.wind_speed_10m ?? 12,
|
|
windDirection: weatherData.current?.wind_direction_10m ?? 0,
|
|
cloudCover: weatherData.current?.cloud_cover ?? 0,
|
|
precipitation: weatherData.current?.precipitation ?? 0,
|
|
isDay: weatherData.current?.is_day ?? 1
|
|
},
|
|
daily
|
|
};
|
|
});
|
|
await this.redisService.set(cacheKey, JSON.stringify(citiesWeather), 900);
|
|
return citiesWeather;
|
|
}
|
|
catch (error) {
|
|
this.logger.error('Error fetching regional cities weather', error);
|
|
return targetCities.map(c => ({
|
|
name: c.name,
|
|
name_ar: c.name_ar,
|
|
lat: c.lat,
|
|
lng: c.lng,
|
|
country: c.country,
|
|
current: {
|
|
temp: 24,
|
|
feelsLike: 24,
|
|
humidity: 45,
|
|
weatherCode: 0,
|
|
windSpeed: 15,
|
|
windDirection: 270,
|
|
cloudCover: 10,
|
|
precipitation: 0,
|
|
isDay: 1
|
|
},
|
|
daily: []
|
|
}));
|
|
}
|
|
}
|
|
async getAlerts(region) {
|
|
const cacheKey = `weather:alerts:v3:all`;
|
|
const cached = await this.redisService.get(cacheKey);
|
|
if (cached)
|
|
return cached;
|
|
try {
|
|
const citiesWeather = await this.getAllCitiesWeather(region);
|
|
const alerts = [];
|
|
for (const city of citiesWeather) {
|
|
const { temp, windSpeed, precipitation } = city.current;
|
|
if (temp > 40) {
|
|
alerts.push({ city: city.name, city_ar: city.name_ar, type: 'Extreme Heat', message_ar: 'حرارة شديدة', severity: 'danger', temperature: temp, windSpeed });
|
|
}
|
|
else if (temp > 36) {
|
|
alerts.push({ city: city.name, city_ar: city.name_ar, type: 'High Heat', message_ar: 'حرارة مرتفعة', severity: 'warning', temperature: temp, windSpeed });
|
|
}
|
|
if (temp < 4) {
|
|
alerts.push({ city: city.name, city_ar: city.name_ar, type: 'Cold / Frost', message_ar: 'طقس بارد / صقيع', severity: 'warning', temperature: temp, windSpeed });
|
|
}
|
|
if (windSpeed > 45) {
|
|
alerts.push({ city: city.name, city_ar: city.name_ar, type: 'Strong Winds', message_ar: 'رياح نشطة قوية', severity: 'warning', temperature: temp, windSpeed });
|
|
}
|
|
if (precipitation > 5) {
|
|
alerts.push({ city: city.name, city_ar: city.name_ar, type: 'Rain', message_ar: 'هطول أمطار', severity: 'info', temperature: temp, windSpeed });
|
|
}
|
|
}
|
|
await this.redisService.set(cacheKey, JSON.stringify(alerts), 900);
|
|
return alerts;
|
|
}
|
|
catch (error) {
|
|
this.logger.error('Error generating weather alerts', error);
|
|
return [];
|
|
}
|
|
}
|
|
};
|
|
exports.WeatherService = WeatherService;
|
|
exports.WeatherService = WeatherService = WeatherService_1 = __decorate([
|
|
(0, common_1.Injectable)(),
|
|
__metadata("design:paramtypes", [redis_service_1.RedisService])
|
|
], WeatherService);
|
|
//# sourceMappingURL=weather.service.js.map
|