You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 4 Next »

Blazor를 이용하여~ 그래픽 웹챗을 구현하는 변종 실험입니다.


GIT : https://github.com/psmon/BlazorChatApp


구현기능

  • 입장을 하면, 자신의 캐릭터(도형)가 랜덤생성됩니다.

실행 샘플

meta-chat.mp4



메시지 설계

웹소켓(브라우져)와 서버메시지(액터)의 정의를 통합할수 있습니다. - 블레이즈 특성

namespace BlazorChatApp.Shared
{
    public class ChatData
    {
    }

    public class UserInfo
    {
        public string Id { get; set; }
        public string Name { get; set; }
 
        public string Color { get; set; }
    }

    public class RoomInfo
    {
        public string Id { get; set; }
        public string Name { get; set; }
    }

    public class UpdateUserPos :UserInfo
    { 
        public double PosX{get; set; }
        public double PosY{get; set; }
        
    }


    public class ChatMessage
    { 
        public UserInfo From { get; set; }
        public string Message { get; set; }
    }

    public class JoinRoom
    {
        public RoomInfo RoomInfo { get; set; }
        public UserInfo UserInfo { get; set; }
    }

    public class SyncRoom
    {
        public RoomInfo RoomInfo { get; set; }
        public UserInfo UserInfo { get; set; }
    }

    public class LeaveRoom
    {
        public RoomInfo RoomInfo { get; set; }
        public UserInfo UserInfo { get; set; }
    }


    public class BaseCmd
    {
        public string Command {get;set; }
    }


    public class RoomCmd : BaseCmd
    {        
        public UserInfo UserInfo{ get; set; }
        public object Data{get;set; }
    }

}


웹소켓 처리코드

시그널 R이 이용되었으며, 일부 서버에서 상태처리를 해야하는경우 액터를 연결하여 처리가 가능합니다.

  • Cilent To Server : 브라우저에서 출발한 메시지를 서버에 전송합니다.
  • Server To Client : 서버에서 연산된 메시지를, 브라우저에게 전송합니다.
using System.Collections.Generic;
using System.Threading.Tasks;

using Akka.Actor;

using BlazorChatApp.Shared;

using Microsoft.AspNetCore.SignalR;

namespace BlazorChatApp.Server.Hubs
{
    public class ChatHub : Hub
    {
        private ActorSystem actorSystem;

        private ActorSelection roomActor;

        public ChatHub(ActorSystem _actorSystem)
        {
            actorSystem = _actorSystem;
            roomActor = actorSystem.ActorSelection("user/room1");
        }

        
        // Client To Server

        public async Task JoInRoom(JoinRoom joinRoom)
        {
            roomActor.Tell(joinRoom);
        }

        public async Task SyncRoom(SyncRoom syncRoom)
        {
            roomActor.Tell(syncRoom);
        }

        public async Task LeaveRoom(LeaveRoom leaveRoom)
        {
            roomActor.Tell(leaveRoom);
        }

        public async Task UpdateUserPos(UpdateUserPos updateUserPos)
        {
            roomActor.Tell(updateUserPos);
        }

        // Server To Client

        public async Task OnJoinRoom(RoomInfo roomInfo, UserInfo user, UpdateUserPos updateUserPos)
        {
            await Clients.All.SendAsync("OnJoinRoom", user, roomInfo, updateUserPos);
        }

        public async Task OnSyncRoom(UserInfo user, List<UpdateUserPos> updateUserPos)
        {
            await Clients.All.SendAsync("OnSyncRoom", user, updateUserPos);
        }

        public async Task OnLeaveRoom(LeaveRoom leaveRoom)
        {
            await Clients.All.SendAsync("OnLeaveRoom", leaveRoom);
        }

        public async Task OnUpdateUserPos(UpdateUserPos updateUserPos)
        {
            await Clients.All.SendAsync("OnUpdateUserPos", updateUserPos);
        }

        
        public async Task SendMessage(string user, string message)       
        {
            await Clients.All.SendAsync("ReceiveMessage", user, message);
        }

        public async Task SendRoomMessage(RoomCmd roomCmd)
        {
            roomActor.Tell(roomCmd);        
        }

    }
}


서버코드

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;

using Akka.Actor;
using Akka.Event;

using BlazorChatApp.Shared;

using Microsoft.AspNetCore.SignalR.Client;

namespace BlazorChatApp.Server.Hubs
{
    public class RoomActor : ReceiveActor
    {
        private readonly ILoggingAdapter log = Context.GetLogger();

        public Dictionary<string,UpdateUserPos> users = new Dictionary<string,UpdateUserPos>();

        private string roomName;

        private int userAutoNo = 0;

        public HubConnection hubConnection { get; set; }

        Random random= new Random();

        public RoomActor(string _roomName)
        {
            string baseUrl = "http://localhost:5000";
            var _hubUrl = baseUrl.TrimEnd('/') + "/chathub";
            hubConnection = new HubConnectionBuilder().WithUrl(_hubUrl).Build();

            hubConnection.StartAsync().Wait();

            roomName = _roomName;

            log.Info($"Create Room{roomName}");

            Receive<RoomCmd>(cmd => {
                log.Info("Received String message: {0}", cmd);
                //Sender.Tell(message);                
            });

            Receive<JoinRoom>(async cmd => {
                userAutoNo++;
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received JoinRoom message: {0}", jsonString);                
                string RandomColor =  string.Format("#{0:X6}", random.Next(0xFFFFFF));
                
                UserInfo userInfo = new UserInfo()
                { 
                    Id=cmd.UserInfo.Id,
                    Name=$"User-{userAutoNo}",
                    Color=RandomColor
                };

                UpdateUserPos updateUserPos= new UpdateUserPos()
                { 
                    Id=cmd.UserInfo.Id,
                    Name=$"User-{userAutoNo}",
                    PosX=random.NextDouble()*500,PosY=random.NextDouble()*500
                };

                users[cmd.UserInfo.Id] = updateUserPos;

                await OnJoinRoom(cmd.RoomInfo, userInfo, updateUserPos);
            });

            Receive<SyncRoom>(async cmd => {           
                userAutoNo++;
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received SyncRoom message: {0}", jsonString);

                List<UpdateUserPos> updateUserPosList = users.Values.ToList();                
                //await hubConnection.SendAsync("OnSyncRoom", cmd.UserInfo, updateUserPosList);
                string RandomColor =  string.Format("#{0:X6}", random.Next(0xFFFFFF));

                UserInfo userInfo = new UserInfo()
                { 
                    Id=cmd.UserInfo.Id,
                    Name=$"User-{userAutoNo}",
                    Color=RandomColor
                };

                await OnSyncRoom(userInfo, users.Values.ToList());

            });

            Receive<UpdateUserPos>(async cmd => { 
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received SyncRoom message: {0}", jsonString);
                if(users.ContainsKey(cmd.Id))
                {
                    users[cmd.Id].PosX+=cmd.PosX;
                    users[cmd.Id].PosY+=cmd.PosY;
                }

                UpdateUserPos updateUserPos = new UpdateUserPos()
                {
                    Id = cmd.Id,
                    Name = cmd.Name,
                    PosX = cmd.PosX,
                    PosY = cmd.PosY
                };

                await OnUpdateUserPos(updateUserPos);

            });


            Receive<LeaveRoom>(async cmd => {                
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received LeaveRoom message: {0}", jsonString);

                if(users.ContainsKey(cmd.UserInfo.Id))
                {
                    users.Remove(cmd.UserInfo.Id);
                    await OnLeaveRoom(cmd);
                }
            });

        }

        public async Task OnJoinRoom(RoomInfo roomInfo, UserInfo user, UpdateUserPos updateUserPos)
        {
            await hubConnection.SendAsync("OnJoinRoom", user, roomInfo, updateUserPos);
        }

        public async Task OnSyncRoom(UserInfo user, List<UpdateUserPos> updateUserPos )
        {
            await hubConnection.SendAsync("OnSyncRoom", user, updateUserPos);
        }

        public async Task OnLeaveRoom(LeaveRoom leaveRoom)
        {
            await hubConnection.SendAsync("OnLeaveRoom", leaveRoom);
        }

        public async Task OnUpdateUserPos(UpdateUserPos updatePos)
        {
            await hubConnection.SendAsync("OnUpdateUserPos", updatePos);
        }

    }
}














  • No labels