본문 바로가기
비전공자를 위한 Flutter/Flutter 심화과정

Flutter 실시간 채팅앱 만들기 (feat. dart_amqp Docker RabbitMQ)

by 밍잔 2022. 5. 20.

 

 

오늘은 실시간 채팅앱을 만들어 보겠습니다. 직접 TCP에 연결하거나 웹소켓을 이용하는 것 외에 MQ(메시지 큐)에 연결해서 채팅을 구현해본 건 처음이었습니다. 

 

 

1. Docker 실행

2. RabbitMQ 컨테이너 실행

3. Flutter에서 MQ 연결

4. MQ에 메시지 보내고 받기

 


1. Docker 실행

 

도커는 쉽게 말하면 이미 다른 사람이 만들어 둔 환경을 복사 붙여넣기 한 것처럼 그대로 이용할 수 있는 툴입니다. 이미 누군가 RabbitMQ를 통해 채팅을 할 수 있도록 만들어둔 서버가 있어서 우리는 그걸 그대로 사용할 겁니다. 먼저 Docker를 설치해볼까요? 아래 링크에 접속하면 도커 프로그램을 다운로드할 수 있습니다.

 

 

 

Developers - Docker

Developer productivity tools and a local Kubernetes environment.

www.docker.com

 

링크를 열어 왼쪽에 있는 Docker Desktop 다운로드 버튼을 눌러 설치해주세요.

 

 

도커가 성공적으로 설치되면 아래와 같은 화면이 나옵니다. 도커를 초기화중인 화면입니다.

 

 

아래와 같이 홈 화면이 나온다면 사용할 준비가 완료됐습니다. 자주 쓰이는 컨테이너들을 바로 사용할 수 있게 추천해주네요.

 


2. RabbitMQ 컨테이너 실행

 

아래는 Golang으로 만들어진 RabbitMQ 도커 이미지 입니다. 직접 처음부터 다 구축하지 않아도 누군가 먼저 만들어 놓은 게 있어서 행복한 세상이네요. 잘 찾아서 잘 활용하는 것도 프로그래머의 소양 같습니다.

 

 

GitHub - koddr/tutorial-go-fiber-rabbitmq: 📖 Tutorial: Working with RabbitMQ in Golang by examples.

📖 Tutorial: Working with RabbitMQ in Golang by examples. - GitHub - koddr/tutorial-go-fiber-rabbitmq: 📖 Tutorial: Working with RabbitMQ in Golang by examples.

github.com

 

링크를 열고 [Code > Download ZIP] 버튼을 눌러 코드를 다운받으세요.

 

 

압축을 풀고 해당 디렉토리로 이동해서 시키는대로 make run 명령어를 실행하세요. 아래는 make run 명령어를 실행하면 나오는 컨테이너를 구동중 화면입니다.

 

 

모든 처리가 완료되고 나서 도커 클라이언트를 켜보면 아래와 같이 컨테이너가 구동중인 걸 보실 수 있습니다.

 

 

크롬 브라우저에서 http://localhost:3000/send?msg=test 로 접속하면 rabbitMQ에 test라는 메시지를 전송하도록 되어있습니다. 처음에는 '어떻게 메시지를 전달하는 거지?'라며 헤맸는데 http 통신으로 전송하고 싶은 메시지를 큐에 쌓는 구조였습니다. 

 

RabbitMQ 웹 모니터링툴 http://localhost:15672/에 접속해보면 메시지를 잘 전달 받는지 모니터링해볼 수 있습니다.

(id : guest, pw : guest)

 

 

sender.go 파일을 수정해서 큐에 연결, 연결 해제를 구현했습니다. (코드를 수정했다면 기존의 컨테이너를 지우고, make run 명령어로 도커 컨테이너를 재실행해주세요.)

 

sender.go 수정본
package main

import (
    "log"
    "os"

    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/fiber/v2/middleware/logger"
    "github.com/streadway/amqp"
)

func main() {
    // Define RabbitMQ server URL.
    amqpServerURL := os.Getenv("AMQP_SERVER_URL")

    // Create a new RabbitMQ connection.
    connectRabbitMQ, err := amqp.Dial(amqpServerURL)
    if err != nil {
        panic(err)
    }
    defer connectRabbitMQ.Close()

    // Let's start by opening a channel to our RabbitMQ
    // instance over the connection we have already
    // established.
    channelRabbitMQ, err := connectRabbitMQ.Channel()
    if err != nil {
        panic(err)
    }
    defer channelRabbitMQ.Close()

    // With the instance and declare Queues that we can
    // publish and subscribe to.
    _, err = channelRabbitMQ.QueueDeclare(
        "QueueService1", // queue name
        true,            // durable
        false,           // auto delete
        false,           // exclusive
        false,           // no wait
        nil,             // arguments
    )
    if err != nil {
        panic(err)
    }

    // Create a new Fiber instance.
    app := fiber.New()

    // Add middleware.
    app.Use(
        logger.New(), // add simple logger
    )

    // 메시지 큐 채널 열기
    app.Get("/open_queue", func(c *fiber.Ctx) error {
        _, err = channelRabbitMQ.QueueDeclare(
            c.Query("queue_name"), // queue name
            false,                 // durable
            true,                  // auto delete
            false,                 // exclusive
            false,                 // no wait
            nil,                   // arguments
        )
        if err != nil {
            return err
        }

        return nil
    })

    // 메시지 큐 채널 닫기
    app.Get("/close_queue", func(c *fiber.Ctx) error {
        _, err = channelRabbitMQ.QueueDelete(
            c.Query("queue_name"),
            false,
            false,
            true,
        )
        if err != nil {
            return err
        }

        return nil
    })

    // Add route for send message to Service 1.
    app.Get("/send_message", func(c *fiber.Ctx) error {
        // Create a message to publish.
        message := amqp.Publishing{
            ContentType: "text/plain",
            Body:        []byte(c.Query("message")),
        }

        queueName := c.Query("queue_name")

        // Attempt to publish a message to the queue.
        if err := channelRabbitMQ.Publish(
            "",        // exchange
            queueName, // queue name
            false,     // mandatory
            false,     // immediate
            message,   // message to publish
        ); err != nil {
            return err
        }

        // TODO : DB에 저장하기

        return nil
    })

    // Start Fiber API server.
    log.Fatal(app.Listen(":3000"))
}

 


4. MQ에 메시지 보내고 받기

 

아래는 미리 만들어둔 flutter 앱 예제코드입니다. 도커가 정상적으로 구동중이라면 아래 코드로 빌드한 앱에서 바로 채팅을 테스트해볼 수 있습니다. 리스너를 이용해 채팅 메시지를 추가하며 BLoC패턴으로 만들었습니다. 자세한 내용은 코드를 확인하세요!

 

 

 

GitHub - MWanKi/flutter-rabbitmq

Contribute to MWanKi/flutter-rabbitmq development by creating an account on GitHub.

github.com

 

 

 

댓글