NodeJs, Socket.IO, Typescript - доступ к сокету в сервисе и отправка сообщения - PullRequest
0 голосов
/ 09 мая 2019

Я новичок в 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-разработчик, и у меня могут быть некоторые привычки, поэтому я получу любую критику,

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...