Я новичок в NodeJs.Я пытаюсь опубликовать некоторые данные в реальном времени из OpenWeather API через socket.io.Мой код выглядит так:
App.ts
import {createSocketServer} from "socket-controllers";
import {SWeatherController} from "./modules/Weather/controller/SWeatherController";
import {config, ISchedule} from './config/schedules.config';
import {Container} from "typedi";
import {createConnection, getCustomRepository} from "typeorm";
import {WeatherRepository} from "./modules/Weather/repository/WeatherRepository";
const scheduler = require('node-schedule');
class App {
private constructor() {
createConnection().then(async () => {
const repo = getCustomRepository(WeatherRepository);
const socket = createSocketServer(3000, {
controllers: [
SWeatherController
],
});
this.initSchedule();
}) .catch(error => {
console.log(error);
});
}
private initSchedule() {
config.schedules.forEach((schedule: ISchedule) => {
scheduler.scheduleJob(schedule.date, function(fireDate){
const service = Container.get(schedule.class);
service[schedule.function]();
});
});
}
public static init() {
return new App();
}
}
export default App;
Один из контроллеров сокетов:
import {SocketController, OnConnect, OnMessage, ConnectedSocket, MessageBody} from 'socket-controllers';
import {Container, Inject, Service} from 'typedi';
import {WeatherService} from '../service/WeatherService';
import {SEventType} from "../type/SEventType";
import {WeatherScheduleType} from "../type/WeatherScheduleType";
import {Weather} from "../entity/Weather";
import {ILocalizationMethod} from "../message/ILocalizationMethod";
import {ILocation} from "../message/ILocation";
const schedule = require('node-schedule');
@Service()
@SocketController()
export class SWeatherController {
currentWeather: Weather;
weatherService: WeatherService;
constructor(
@ConnectedSocket() socket,
) {
this.connectedSocket = socket;
this.weatherService = Container.get(WeatherService);
}
@OnConnect()
async connect(
@ConnectedSocket() socket
) {
this.weatherService.getLastWeather().then((weather) => {
this.currentWeather = weather;
socket.emit(SEventType.SEND_WEATHER_DATA, this.currentWeather);
});
schedule.scheduleJob(WeatherScheduleType.CHECK_WEATHER_CHANGES, async () => {
const lastWeather = await this.weatherService.getLastWeather();
if (lastWeather.temp !== this.currentWeather.temp) {
socket.emit(SEventType.SEND_WEATHER_DATA, lastWeather)
console.log('old: ' + this.currentWeather);
this.currentWeather = lastWeather;
console.log('emitted: ' + this.currentWeather);
}
});
}
@OnMessage(SEventType.TOGGLE_LOCALIZATION_METHOD)
toggleLocalizationMethod(
@ConnectedSocket() socket: any,
@MessageBody() message: ILocalizationMethod
) {
console.log(message);
try {
this.weatherService.toggleLocalizationMethod(message).then(() => {
this.weatherService.getLastWeather().then((weather) => {
this.currentWeather = weather;
socket.emit(SEventType.SEND_WEATHER_DATA, this.currentWeather);
});
});
} catch (e) {
console.log(e);
} finally {
}
}
@OnMessage(SEventType.UPDATE_LOCATION)
changeLocation(
@ConnectedSocket() socket: any,
@MessageBody() message: ILocation
) {
this.weatherService.updateLocation(message);
}
test() {
}
}
А это сервис для извлечения данных из API:
import {Service} from 'typedi';
import {helper} from '../../Utils/Service/OpenWeatherMapHelper';
import {Connection, getConnectionManager, getCustomRepository, Repository} from "typeorm";
import {Weather} from "../entity/Weather";
import {WeatherLocalizationMethod} from "../entity/WeatherLocalizationMethod";
import {WeatherLocation} from "../entity/WeatherLocation";
import {LocalizationMethodType} from "../type/LocalizationMethodType";
import {WeatherRepository} from "../repository/WeatherRepository";
import {ILocalizationMethod} from "../message/ILocalizationMethod";
import {ILocation} from "../message/ILocation";
@Service()
export class WeatherService {
connectionManager: Connection;
weatherRepository: WeatherRepository;
localizationMethodRepository: Repository<WeatherLocalizationMethod>;
locationRepository: Repository<WeatherLocation>;
constructor(
) {
this.connectionManager = getConnectionManager().get();
this.weatherRepository = getCustomRepository(WeatherRepository);
this.localizationMethodRepository = this.connectionManager.manager.getRepository(WeatherLocalizationMethod);
this.locationRepository = this.connectionManager.manager.getRepository(WeatherLocation);
}
async getCurrentAPIWeather() {
const locationMethod = await this.localizationMethodRepository
.createQueryBuilder('lm')
.where("active = :active", {active: true})
.getOne();
const locationQb = await this.locationRepository.createQueryBuilder('l');
const location: WeatherLocation = await locationQb
.where("created_at = " + locationQb.subQuery().select('MAX(sl.created_at)').from(WeatherLocation, 'sl').getQuery())
.getOne();
switch (locationMethod.name) {
case LocalizationMethodType.COORDS:
helper.getCurrentWeatherByGeoCoordinates(location.longitude, location.latitude, (err, currentWeather) => {
const weather = this.mapWeatherEntity(currentWeather);
this.connectionManager.manager.save(weather);
});
break;
case LocalizationMethodType.NAME:
helper.getCurrentWeatherByCityName(location.locationName, (err, currentWeather) => {
const weather = this.mapWeatherEntity(currentWeather);
this.connectionManager.manager.save(weather);
});
break;
}
}
public getLastWeather() {
return this.weatherRepository.findCurrentWeather();
}
public async toggleLocalizationMethod(method: ILocalizationMethod) {
const foundMethod = await this.localizationMethodRepository.findOne({name: method.name});
if (!foundMethod) {
throw new Error("Method with name: " + method.name + " not found");
}
foundMethod.active = true;
this.localizationMethodRepository.save(foundMethod);
}
public async updateLocation(location: ILocation) {
const weatherLocation = new WeatherLocation();
weatherLocation.locationName = location.name;
weatherLocation.longitude = location.long;
weatherLocation.latitude = location.lat;
this.locationRepository.save(weatherLocation);
}
public mapWeatherEntity(currentWeather) {
const weather = new Weather();
weather.temp = currentWeather.main.temp
weather.tempMin = currentWeather.main.temp_min
weather.tempMax = currentWeather.main.temp_max
weather.humidity = currentWeather.main.humidity;
weather.icon = currentWeather.weather[0].icon;
weather.description = currentWeather.weather[0].description;
weather.longitude = currentWeather.coord.lon;
weather.latitude = currentWeather.coord.lat;
weather.locationName = currentWeather.name;
return weather;
}
}
Как видите, я использую библиотеку сокет-контроллеров.В настоящее время я запускаю отдельный процесс для доступа к данным из API и другой (в контроллере) для проверки обновлений и выдачи.Можно ли получить доступ к подключенному сокету в сервисе и отправить сообщение непосредственно с него?
PS.Я знаю, что код выглядит не очень хорошо, но это мое первое приложение для больших узлов, и я не знаю соглашений и решений по разработке js, я, как правило, PHP-разработчик, и у меня могут быть некоторые привычки, поэтому я получу любую критику,