CookIM - 一个基于akka的分布式websocket聊天程序

网友投稿 921 2022-10-23

CookIM - 一个基于akka的分布式websocket聊天程序

CookIM - 一个基于akka的分布式websocket聊天程序

CookIM - is a distributed websocket chat applications based on akka

Support private message and group messageSupport chat servers cluster communicationNow we support send text message, file message and voice message. Thanks for ft115637850 's PR for voice message.

中文文档English document

GitHub projectOSChina project

Category

DemoDemo on PCDemo on MobileDemo link Start multiple nodes CookIM in docker composeStart docker composeAdd nodes in docker composeDebug in docker containerStop docker compose How to runPrerequisitesClone source codeConfiguration and assemblyStart CookIM serverOpen browser and access web port 8080Start another CookIM serverOpen browser and access web port 8081 ArchitectureArchitecture pictureakka stream websocket graphMongoDB tables specificationWebsocket message type ChangeLog0.1.0-SNAPSHOT0.2.0-SNAPSHOT0.2.4-SNAPSHOT

Category

###Demo

Demo on PC

Demo on Mobile

Demo link

https://im.cookeem.com

Start multiple nodes CookIM in docker compose

Start docker compose

Change into CookIM directory, run command below, start multiple nodes CookIM servers in docker compose mode. This way will start 3 container: mongo, cookim1 and cookim2

$ git clone https://github.com/cookeem/CookIM.git$ cd CookIM$ sudo docker-compose up -dCreating mongoCreating cookim1Creating cookim2

After run docker compose, use different browser to access the URLs below to connect to cookim1 and cookim2

http://localhost:8080 http://localhost:8081

Category

Add nodes in docker compose

You can add config in docker-compose.yml (in CookIM directory) to add CookIM server nodes, this example show how to add cookim3 in docker compose:

cookim3: image: cookeem/cookim container_name: cookim3 hostname: cookim3 environment: HOST_NAME: cookim3 WEB_PORT: 8080 AKKA_PORT: 2551 SEED_NODES: cookim1:2551 MONGO_URI: mongodb://mongo:27017/local ports: - "8082:8080" depends_on: - mongo - cookim1

Category

Debug in docker container

View container cookim1 logs output

$ sudo docker logs -f cookim1

Exec into container cookim1 to debug

$ sudo docker exec -ti cookim1 bash

Category

Stop docker compose

$ sudo docker-compose stop$ sudo docker-compose rm

Category

How to run

Prerequisites

JDK 8+Scala 2.11+SBT 0.13.15MongoDB 2.6 - 3.4

Category

Clone source code

git clone https://github.com/cookeem/CookIM.gitcd CookIM

Category

Configuration and assembly

The configuration file locate at conf/application.conf, please make sure your mongodb uri configuration.

mongodb { dbname = "cookim" uri = "mongodb://mongo:27017/local"}

Assembly CookIM project to a fatjar, target jar locate at target/scala-2.11/CookIM-assembly-0.2.0-SNAPSHOT.jar

sbt clean assembly

Category

Start CookIM server

CookIM use MongoDB to store chat messages and users data, make sure you startup MongoDB before you startup CookIM.

There are two ways to start CookIM server: sbt and java

a. sbt debug way:

$ cd #CookIM directory#$ sbt "run-main com.cookeem.chat.CookIM -h localhost -w 8080 -a 2551 -s localhost:2551"

b. pack and compile fat jar:

$ sbt assembly

c. java production way:

$ java -classpath "target/scala-2.11/CookIM-assembly-0.2.4-SNAPSHOT.jar" com.cookeem.chat.CookIM -h localhost -w 8080 -a 2551 -s localhost:2551

Command above has start a web server listen port 8080 and akka system listen port 2551

Parameters:

-a -h [-m ] [-n] -s -w -a,--akka-port akka cluster node port -h,--host-name current web service external host name -m,--mongo-uri mongodb connection uri, example: mongodb://localhost:27017/local -n,--nat is nat network or in docker -s,--seed-nodes akka cluster seed nodes, seperate with comma, example: localhost:2551,localhost:2552 -w,--web-port web service port

Category

Open browser and access web port 8080

http://localhost:8080

Category

Start another CookIM server

Open another terminal, start another CookIM server to test message communication between servers:

a. sbt debug way:

$ sbt "run-main com.cookeem.chat.CookIM -h localhost -w 8081 -a 2552 -s localhost:2551"

b. java production way:

$ java -classpath "target/scala-2.11/CookIM-assembly-0.2.0-SNAPSHOT.jar" com.cookeem.chat.CookIM -h localhost -w 8081 -a 2552 -s localhost:2551

Command above has start a web server listen port 8081 and akka system listen port 2552

Category

Open browser and access web port 8081

http://localhost:8081

Category

Architecture

Architecture picture

**CookIM server make from 3 parts: **

akka http: provide web service, browser connect distributed chat servers by websocket

akka stream: akka http receive websocket message (websocket message include TextMessage and BinaryMessage), then send message to chatService by akka stream way, websocket message include JWT(Javascript web token), if JWT verify failure, chatService stream will return reject message; if JWT verify success, chatService stream will send message to ChatSessionActor

akka cluster:akka stream send websocket message to akka cluster ChatSessionActor, ChatSessionActor use DistributedPubSub to subscribe and publish message in akka cluster. When user online session, it will subscribe the session; when user send message in session, it will publish message in akka cluster, the actors who subscribe the session will receive the publish message

Category

akka stream websocket graph

When akka http receive messsage from websocket, it will send message to chatService flow, here we use akka stream graph:

Websocket message body include JWT, flowFromWS use to receive websocket message and decode JWT;

When JWT verify failure, it will broadcast to filterFailure to filter to fail message; When JWT verify success, it will broadcast to filterSuccess to filter to success message;

When akka stream created, builder.materializedValue will send message to connectedWs, connectedWs convert message receive to UserOnline message, then send to chatSinkActor finally send to ChatSessionActor;

chatActorSink send message to chatSessionActor, when akka stream closed if will send UserOffline message to down stream;

chatSource receive message back from ChatSessionActor, then send message back to flowAcceptBack;

flowAcceptBack will let the websocket connection keepAlive;

flowReject and flowAcceptBack messages finally send to flowBackWs, flowBackWs convert messages to websocket format then send back to users;

Category

MongoDB tables specification

users: users table

*login (login email)nickname (nickname)password (password SHA1)gender (gender: unknow:0, boy:1, girl:2)avatar (avatar abs path, example: /upload/avatar/201610/26/xxxx.JPG)lastLogin (last login timestamp)loginCount (login counts)sessionsStatus (user joined sessions status) [{sessionid: session id, newCount: unread message count in this session}]friends (user's friends list: [friends uid])dateline (register timestamp)

sessions: sessions table

*createuid (creator uid)*ouid (receiver uid, when session type is private available)sessionIcon (session icon, when session type is group available)sessionType (session type: 0:private, 1:group)publicType (public type: 0:not public, 1:public)sessionName (session name)dateline (created timestamp)usersStatus (users who joined this session status) [{uid: uid, online: (true, false)}]lastMsgid (last message id)lastUpdate (last update timestamp)

messages: messages tables

*uid (send user uid)*sessionid (relative session id)msgType (message type)content (message content)fileInfo (file information) { filePath fileName fileType fileSize fileThumb }*dateline (created timestamp)

onlines: online users table

*uid (online user id)dateline (last update timestamp)

notifications: receive notifications table

noticeType (notification type: "joinFriend", "removeFriend", "inviteSession")senduid (send user id)*recvuid (receive user id)sessionid (relative session id)isRead (notification is read: 0:not read, 1:already read)dateline (created timestamp)

Category

Websocket message type

There are two websocket channel: ws-push and ws-chat

ws-push send sessions new message to users, when user not online the session, they still can receive which sessions has new messages

/ws-push channel

up message, use to subscribe push message:{ userToken: "xxx" }down message:acceptMsg: { uid: "xxx", nickname: "xxx", avatar: "xxx", sessionid: "xxx", sessionName: "xxx", sessionIcon: "xxx", msgType: "accept", content: "xxx", dateline: "xxx" }rejectMsg: { uid: "", nickname: "", avatar: "", sessionid: "", sessionName: "", sessionIcon: "", msgType: "reject", content: "xxx", dateline: "xxx" }keepAlive: { uid: "", nickname: "", avatar: "", sessionid: "", sessionName: "", sessionIcon: "", msgType: "keepalive", content: "", dateline: "xxx" }textMsg: { uid: "xxx", nickname: "xxx", avatar: "xxx", sessionid: "xxx", sessionName: "xxx", sessionIcon: "xxx", msgType: "text", content: "xxx", dateline: "xxx" }fileMsg: { uid: "xxx", nickname: "xxx", avatar: "xxx", sessionid: "xxx", sessionName: "xxx", sessionIcon: "xxx", msgType: "file", fileName: "xxx", fileType: "xxx", fileid: "xxx", thumbid: "xxx", dateline: "xxx" }onlineMsg: { uid: "xxx", nickname: "xxx", avatar: "xxx", sessionid: "xxx", sessionName: "xxx", sessionIcon: "xxx", msgType: "online", content: "xxx", dateline: "xxx" }offlineMsg: { uid: "xxx", nickname: "xxx", avatar: "xxx", sessionid: "xxx", sessionName: "xxx", sessionIcon: "xxx", msgType: "offline", content: "xxx", dateline: "xxx" }joinSessionMsg: { uid: "xxx", nickname: "xxx", avatar: "xxx", sessionid: "xxx", sessionName: "xxx", sessionIcon: "xxx", msgType: "join", content: "xxx", dateline: "xxx" }leaveSessionMsg:{ uid: "xxx", nickname: "xxx", avatar: "xxx", sessionid: "xxx", sessionName: "xxx", sessionIcon: "xxx", msgType: "leave", content: "xxx", dateline: "xxx" }noticeMsg: { uid: "", nickname: "", avatar: "", sessionid: "", sessionName: "xxx", sessionIcon: "xxx", msgType: "system", content: "xxx", dateline: "xxx" }message push to browser:pushMsg: { uid: "xxx", nickname: "xxx", avatar: "xxx", sessionid: "xxx", sessionName: "xxx", sessionIcon: "xxx", msgType: "xxx", content: "xxx", fileName: "xxx", fileType: "xxx", fileid: "xxx", thumbid: "xxx", dateline: "xxx" }

Category

ws-chat is session chat channel, user send and receive session messages in this channel

/ws-chat channelup message: onlineMsg: { userToken: "xxx", sessionToken: "xxx", msgType:"online", content:"" }textMsg: { userToken: "xxx", sessionToken: "xxx", msgType:"text", content:"xxx" }fileMsg: { userToken: "xxx", sessionToken: "xxx", msgType:"file", fileName:"xxx", fileSize: 999, fileType: "xxx" }<#BinaryInfo#>binary_file_array_bufferdown message: rejectMsg: { uid: "", nickname: "", avatar: "", sessionid: "", sessionName: "", sessionIcon: "", msgType: "reject", content: "xxx", dateline: "xxx" }keepAlive: { uid: "", nickname: "", avatar: "", sessionid: "", sessionName: "", sessionIcon: "", msgType: "keepalive", content: "", dateline: "xxx" }textMsg: { uid: "xxx", nickname: "xxx", avatar: "xxx", sessionid: "xxx", sessionName: "xxx", sessionIcon: "xxx", msgType: "text", content: "xxx", dateline: "xxx" }fileMsg: { uid: "xxx", nickname: "xxx", avatar: "xxx", sessionid: "xxx", sessionName: "xxx", sessionIcon: "xxx", msgType: "file", fileName: "xxx", fileType: "xxx", fileid: "xxx", thumbid: "xxx", dateline: "xxx" }onlineMsg: { uid: "xxx", nickname: "xxx", avatar: "xxx", sessionid: "xxx", sessionName: "xxx", sessionIcon: "xxx", msgType: "online", content: "xxx", dateline: "xxx" }offlineMsg: { uid: "xxx", nickname: "xxx", avatar: "xxx", sessionid: "xxx", sessionName: "xxx", sessionIcon: "xxx", msgType: "offline", content: "xxx", dateline: "xxx" }joinSessionMsg:{ uid: "xxx", nickname: "xxx", avatar: "xxx", sessionid: "xxx", sessionName: "xxx", sessionIcon: "xxx", msgType: "join", content: "xxx", dateline: "xxx" }leaveSessionMsg:{ uid: "xxx", nickname: "xxx", avatar: "xxx", sessionid: "xxx", sessionName: "xxx", sessionIcon: "xxx", msgType: "leave", content: "xxx", dateline: "xxx" }noticeMsg: { uid: "", nickname: "", avatar: "", sessionid: "", sessionName: "xxx", sessionIcon: "xxx", msgType: "system", content: "xxx", dateline: "xxx" }message push to browser:chatMsg: { uid: "xxx", nickname: "xxx", avatar: "xxx", msgType: "xxx", content: "xxx", fileName: "xxx", fileType: "xxx", fileid: "xxx", thumbid: "xxx", dateline: "xxx" }

Category

ChangeLog

0.1.0-SNAPSHOT

Category

0.2.0-SNAPSHOT

CookIM now support MongoDB 3.4.4Upgrade akka version to 2.5.2Update docker-compose startup CookIM cluster readme

Category

0.2.4-SNAPSHOT

Now support send voice message, required WebRTC support browser, now Chrome Firefox and the new Safari11 available.Configurate mongodb connection params by command line.Update docker startup mode.

Category

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:nyoj613 免费馅饼 动态规划
下一篇:poj2479Maximum sum
相关文章

 发表评论

暂时没有评论,来抢沙发吧~