본문 바로가기
블로그 이미지

방문해 주셔서 감사합니다! 항상 행복하세요!

  
   - 문의사항은 메일 또는 댓글로 언제든 연락주세요.
   - "해줘","답 내놔" 같은 질문은 답변드리지 않습니다.
   - 메일주소 : lts06069@naver.com


Node.js/Nestjs (Nest.js)

Nestjs 프레임워크 서버(microservices, mqtt) -17

야근없는 행복한 삶을 위해 ~
by 마샤와 곰 2022. 10. 11.

nestjs 프레임워크에서는 소규모의 독립적인 서비스(microservices)의 기능 구현을 위해 마이크로서비스(microservices)라는 모듈을 제공하고 있습니다.
해당 마이크로서비스(microservices) 모듈을 활용하여 사용 할 수 있는 대표적인 기능이 mqtt 기능입니다.
물론 mqtt 기능을 사용하기 위해서는 mqtt 서버가 갖추어져 있어야 합니다. : - )
* mqtt서버는 래빗mq, 모스키토, eclipse-mosquitto 같은 서버를 사용하면 됩니다.

역시나 처음 서비스 사용을 위해서는 모듈을 설치하여 줍니다.

//마이크로서비스
npm install @nestjs/microservices

//mqtt서버
npm install mqtt


nestjs에서 사용할 수 있는 마이크로서비스(microservice)는 mqtt 말고도 레디스(redis), kafka, NATS같은 서비스 연동도 가능 합니다.
아무튼..이렇게 라이브러리를 설치한 다음에 맨 처음 메인파일을 변경 해 줍니다!
기본 메인파일은 HTTP서버로서의 역할을 하기 때 문 입니다.

* 파일이름 : main.ts

import { NestFactory } from '@nestjs/core';

import { MicroserviceOptions } from '@nestjs/microservices';
import { Transport } from '@nestjs/microservices/enums';
import { AppModule } from './app.module';


async function bootstrap() {
  //NestFactory에서 사용하는 함수가 createMicroservice입니다! 기존의 create 아닙니다!
  //제네릭도 잘 보셔야 합니다! MicroserviceOptions 입니다!
  const app = await NestFactory.createMicroservice<MicroserviceOptions>(AppModule,{ 
    transport: Transport.MQTT,
    options: {
      host: 'localhost',
      port: 1883,
    }
  });
  app.listen();
}
bootstrap();

 

메인 파일을 이렇게 변경하게 되면 해당 어플리케이션은 서버의 역할이 아니라 클라이언트의 역할을 하게 됩니다.
즉 해당 어플리케이션은 mqtt서버에 접속해서 메시지를 읽고 전달하는 역할을 하게 됩니다.

 

다음으로 모듈부분을 수정 합니다.
모듈은 mqtt서버의 기본 접속정보를 등록 할 수 있습니다.
가령 아이디, 비밀번호가 존재 한 다면 해당파트에서 등록을 해 줍니다.
* 파일이름 : app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ClientsModule, Transport } from '@nestjs/microservices';

@Module({
  imports: [
    ClientsModule.register([
      {
        name: 'MY_MQTT_SERVICE',  //* MY_MQTT_SERVICE : 의존성 이름
        transport: Transport.MQTT,
        options: {
          host: 'localhost',
          port: 1883,
          clientId : 'id',
          password : 'password'
        }
      }
    ]),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {
  constructor() {}
}

 

이제 실제 연동하는 부분 입니다.
연동은 메시지를 수신하고 전송하는 기능으로 구현 하였습니다.
* 파일이름 : app.controller.ts

import { Controller, Inject } from '@nestjs/common';
import { MessagePattern, Payload as pd, ClientProxy } from '@nestjs/microservices';
import {take} from 'rxjs';

@Controller()
export class AppController {

  constructor(@Inject('MY_MQTT_SERVICE') private client : ClientProxy) { //* MY_MQTT_SERVICE : 의존성 이름
    setTimeout(() => {  //3초뒤에 메시지를 발송하게 하였습니다.
      const data = {number : Math.random(), text : AppController.name};
      this.client.send('Korean',data).pipe(take(1)).subscribe();      
    }, 3000);
  }


  @MessagePattern('World')  //구독하는 주제1
  모두받기(@pd() data){
    console.log(data);
  }


  @MessagePattern('American')  //구독하는 주제2
  고유받기(@pd() data){
    console.log(data);
  }  
}

 

이를 동작시킨 모습입니다.
MQTTX라는 응용프로그램을 통해서 서로 주고받는 기능을 확인 하였습니다. 

 * MQTTX : MQTT 프로토콜을 사용하는 응용 프로그램(카카오메신저같은)

오~mqtt 안녕!

 

World라는 주제에 대해서 MQTTX 프로그램으로 데이터를 전송하고, nestjs에서도 받은 모습 입니다.

해당 어플리케이션은 mqtt에 대해서 동작을 하기 때 문에 서버의 기능 보다는 클라이언트의 기능이 좀 더 강력 합니다.

 


 

우리가 사용하는 브라우저(크롬, 엣지, 파이어폭스 등)에서는 mqtt를 사용 할 수가 없습니다.

그러므로 이를 위해서 http 서버의 기능을 만들어준 다음에, http 요청 후에 mqtt로 다시 요청을하게 하고, 해당 결과를 보여주는 방식으로 개발이 되어야 합니다.

 

HTTP요청 → HTTP수신 → MQTT요청 → MQTT수신 → HTTP응답

 

위 mqtt 어플리케이션에서 http서버를 사용하려면 아래처럼 메인파일에 2개의 앱 설정을 해 주어야 합니다.

* 파일이름 : main.ts

import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions } from '@nestjs/microservices';
import { Transport } from '@nestjs/microservices/enums';
import { AppModule } from './app.module';
import { NestExpressApplication } from '@nestjs/platform-express';
import { http모듈 } from './http모듈';

async function bootstrap() {
  //#1. mqtt 어플리케이션으로 사용
  const app = await NestFactory.createMicroservice<MicroserviceOptions>(AppModule,{
    transport: Transport.MQTT,  //사용할 종류
    options: {
      host: 'localhost',
      port: 1883,
    }
  });
  app.listen();

  //#2. http서버로 사용
  const httpApp = await NestFactory.create<NestExpressApplication>(http모듈);
  await httpApp.listen(8080);
}
bootstrap();

 

nestjs에서 동작할 때 2개의 모듈을 동작하게 하였습니다.

1개는 기존에 만들어 두었던 mqtt와 관련된 모듈이며, 나머지 1개는 새로이 만들어준 http관련 모듈 입니다.

* 이름 : "http모듈" 클래스

 

http와 관련된 모듈을 새로 추가하여 줍니다.

http 모듈은 이전부터 만들어온 방식으로 구현하면 됩니다.

* 파일이름 : http모듈.ts

import { Module } from '@nestjs/common';
import { AppModule } from './app.module';
import { http컨트롤 } from './http컨트롤';


@Module({
  imports: [
    AppModule  //mqtt 모듈을 가져 옵니다.
  ],
  controllers: [http컨트롤],
  providers: [],
})
export class http모듈 {}


새로 만든 http모듈에게 응답용 컨트롤러를 새로 붙여 줍니다.

해당 컨트롤러 또한 기존 방식처럼 만들어주면 됩니다.
* 파일이름 : http컨트롤.ts

import { Request, Response } from 'express';
import { Controller, All, Res, Req, HttpStatus,Inject } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import {take} from 'rxjs';

@Controller()
export class http컨트롤 {
  constructor(@Inject('MY_MQTT_SERVICE') private client : ClientProxy) {

  }

  @All('web')
  async normal(@Req() req: Request, @Res() res: Response) {
    //get 방식으로 데이터를 받아서 data 라는 키 값으로 mqtt서버로 전송하게 하였습니다.
    console.log(req.query)
    await this.client.send('Korean',{data:req.query}).pipe(take(1)).subscribe();
    res.status(HttpStatus.OK).send({ yourRequest: req.query });
  }
}

 

web이라는 get방식의 요청이 오면, mqtt 서버에게 내용을 전달하게 하였습니다.
하지만 해당 코드를 동작하면 오류가나는데, "MY_MQTT_SERVICE" 라는 의존성을 받지 못한 오류가 발생하게 됩니다.
해당 객체는  AppModule클래스(app.module.ts 파일) 에만 존재하기 때문 입니다.
그러므로 기존의 AppModule클래스(app.module.ts 파일) 에 존재하는 mqtt 설정을 가져오기 위해서 AppModule을 아래와 같이 수정 해 줍니다.

* 파일이름 : app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ClientsModule, Transport } from '@nestjs/microservices';

const clients = ClientsModule.register([
  {
    name: 'MY_MQTT_SERVICE', //* MY_MQTT_SERVICE : 의존성 이름
    transport: Transport.MQTT,
    options: {
      host: 'localhost',
      port: 1883
    }
  }
]);

@Module({
  imports: [
    clients
  ],
  controllers: [AppController],
  providers: [AppService],
  exports : [clients]   //다른 모듈에서 쓸 수 있게 출력!
})
export class AppModule {
  constructor() {}
}

 

위 코드는 간단하게 export를 활용한 예제 이므로 본인 프로젝트의 구성에 맞게 모듈을 다시 구성하는 것이 좋습니다.
이제 GET방식으로 접속하여 봅니다!

toast~

 

http의 요청을 받아서 mqtt 서버에게 데이터를 다시 전달하는 것을 확인 할 수 있습니다!

이처럼 nestjs에서는 기능을 모듈 단위로 분리할 수 있기 때 문에 나중에 해당 기능에 대해서 유지보수할 때 매우 편리하게 할 수 있습니다.

위 내용에 사용된 소스코드는 아래 제 깃허브에서 받아볼 수 있습니다.

https://github.com/TaeSeungRyu/NestProject/tree/main/step16

 

GitHub - TaeSeungRyu/NestProject: Nestjs 프로젝트

Nestjs 프로젝트. Contribute to TaeSeungRyu/NestProject development by creating an account on GitHub.

github.com

 

공부하면 할 수록 재미있고 즐거운 nestjs!!!
궁금한점 또는 틀린부분은 언제든 연락 주세요!

 

 

반응형
* 위 에니메이션은 Html의 캔버스(canvas)기반으로 동작하는 기능 입니다. Html 캔버스 튜토리얼 도 한번 살펴보세요~ :)
* 직접 만든 Html 캔버스 애니메이션 도 한번 살펴보세요~ :)

댓글