실시간 message chat

realtime은 안해봣으므로 간단한 메세지 보내는 샘플을 먼저 해본다.

architecture

clean up

기존코드를 backend라는 폴더로 전부 이동 frontend폴더를 만들어서 사용할 예정

plan

  1. postman으로 websocket 테스트 (public echo websocket server : ws.kraken.com)

  2. websocket api 서버 만들기

  3. websocket api 서버 테스트하기(postman)

  4. frontend 기본프로젝트 만들기

  5. websocket으로 메세지 보내고 받기

대충 이런 과정으로 해보면 될듯

postman으로 websocket 테스트하기

open postman

click new

click websocket request

ws://ws.kraken.com

click connect

it works

fastapi에 websocket 만들기

Dockerfile에 다음 추가

RUN pip install fastapi[all]==0.95.1
RUN pip install uvicorn[standard]==0.21.1
RUN pip install webservices # 이거 추가

main.py

from fastapi import ... , WebSocket, WebSocketDisconnect
from datetime import datetime
import logging
import asyncio

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("FastAPI app")

app = FastAPI()

...


@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()

    while True:
        try:
            # Receive the JSON data sent by a client.
            data = await websocket.receive_json()
            # Some (fake) heavey data processing logic.
            logger.info("received data: "+data.get("message", ""))
            message_processed = await heavy_data_processing(data)
            # Send JSON data to the client.
            await websocket.send_json(
                {
                    "message": message_processed,
                    "time": datetime.now().strftime("%H:%M:%S"),
                }
            )
        except WebSocketDisconnect:
            logger.info("The connection is closed.")
            break

async def heavy_data_processing(data: dict):
    """Some (fake) heavy data processing logic."""
    await asyncio.sleep(2)
    message_processed = data.get("message", "").upper()
    return message_processed

간단히 설명하면 웹소켓으로 대기중이다가 연결이 되고 메세지가 오면 2초를 슬립햇다가 메세지를 대문자로 바꾸고 그걸 리턴해서 시간을 추가해서 브라우저로 보내준다.

webserver실행후 포스트맨으로 Test

ws://whisper/ws

click connect

메세지를 보내면 잘 돌아온다.

{
  "message": "aaa",
  "time": "aaa"
}

click send

double qoute을 주의하자.

backend에서 websocket은 준비가 된거같다. frontend에서 보내야할듯.

frontend default project 만들기

ng new frontend
cd frontend
npm i
ng serve -o

angular 15 installed

tag: v0.10를 확인

message를 websocket으로 server와 주고 받기

service 생성

cd src/app
ng g service service/WebSocket

파일이 생성되었다.

다음 코드를 확인해 보자.

web-socket.service.ts

import { Injectable } from '@angular/core';
import { webSocket, WebSocketSubject } from 'rxjs/webSocket';
import { environment } from '../../environments/environment';

interface MessageData {
  message: string;
  time?: string;
}

@Injectable({
  providedIn: 'root',
})
export class WebSocketService {
  private socket$!: WebSocketSubject<any>;
  public receivedData: MessageData[] = [];

  constructor() {}

  public connect(): void {
    if (!this.socket$ || this.socket$.closed) {
      this.socket$ = webSocket(environment.ws_url);

      this.socket$.subscribe((data: MessageData) => {
        this.receivedData.push(data);
      });
    }
  }

  sendMessage(message: string) {
    this.socket$.next({ message });
  }

  close() {
    this.socket$.complete();
  }
}

app.component.html

<!-- frontend/src/app/app.component.html -->
<h2>Send a message to the server:</h2>
<form (ngSubmit)="sendMessage(message); message = ''">
  <input [(ngModel)]="message" name="message" type="text" autocomplete="off" />
  <button type="submit" style="margin-left: 10px">Send</button>
</form>

<h2>Received messages from the server:</h2>
<ul>
  <li *ngFor="let data of wsService.receivedData">{{ data.time }}: {{ data.message }}</li>
</ul>
<router-outlet></router-outlet>

app.component.ts

//src\app\app.component.ts
import { Component, OnDestroy } from '@angular/core';
import { WebSocketService } from './services/web-socket.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
})
export class AppComponent implements OnDestroy {
  message = '';

  constructor(public wsService: WebSocketService) {
    this.wsService.connect();
  }

  sendMessage(message: string) {
    this.wsService.sendMessage(message);
  }

  ngOnDestroy() {
    this.wsService.close();
  }
}

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { FormsModule } from '@angular/forms';
import { WebSocketService } from './services/web-socket.service';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, AppRoutingModule, FormsModule],
  providers: [WebSocketService],
  bootstrap: [AppComponent],
})
export class AppModule {}

실행 확인

cd frontend
ng serve -o

소문자가 대문자로 바귀어서 시간과 함께 오는것을 알수 잇다.

서버에서 2초를 강제로 기다리므로 조금 느리게 온다.

todo

이제 마이크 소리를 보내보자.

Last updated

Was this helpful?