realtime은 안해봣으므로 간단한 메세지 보내는 샘플을 먼저 해본다.
architecture
clean up
기존코드를 backend라는 폴더로 전부 이동 frontend폴더를 만들어서 사용할 예정
plan
postman으로 websocket 테스트 (public echo websocket server : ws.kraken.com)
websocket api 서버 테스트하기(postman)
대충 이런 과정으로 해보면 될듯
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
이제 마이크 소리를 보내보자.