ソケットで匿名のチャットルームを作成する.IOとエクスプレス.js
プロジェクトの設定
chat-app
を使ってディレクトリをディレクトリに変更します.$ mkdir chat-app && cd chat-app
$ yarn init -y
$ yarn add express
app.js
, と簡単なノードのHTTPサーバを作成します.8001
.// app.js
const http = require("http")
const express = require("express")
const app = express()
app.get("/index", (req, res) => {
res.send("Welcome home")
})
const server = http.createServer(app)
server.on("error", (err) => {
console.log("Error opening server")
})
server.listen(8001, () => {
console.log("Server working on port 8001")
})
$ node app.js
訪問できます[http://localhost:8001/index](http://localhost:8001/index)
ブラウザでアプリケーションが動作することをテストしますソケットの初期化。サーバ側のIO
サーバー側のソケットを初期化するには、次の手順に従います.
ソケットをインストールします.コマンドの実行によってアプリケーションにIO依存性があります.
$ yarn add socket.io
インポートソケット.コードをIOソケットに作成し、ソケットにイベントリスナーを追加し、接続が完了したかどうかをリッスンします.
// app.js
const http = require("http");
const { Server } = require("socket.io");
const express = require("express");
const app = express();
app.get("/index", (req, res) => {
res.send("Welcome home");
});
const server = http.createServer(app);
const io = new Server(server);
io.on("connection", (socket) => {
console.log("connected");
});
server.on("error", (err) => {
console.log("Error opening server");
});
server.listen(8001, () => {
console.log("Server working on port 3000");
});
ソケットの初期化。クライアント側のIO
我々は、バニラJavaScriptを使用して簡単なUIを作成し、我々はExpressのアプリケーションから静的ファイルとしてWebページを提供します.
我々のUIを構築するためのファイルを含むパブリックディレクトリを作成し、プロジェクトの構造をこのようにします.
chat-app/
|- node_modules/
|- public/
|- index.html
|- main.js
|- app.js
|- package.json
|- yarn.lock
We are going to be making use of Tailwind CSS to style the Client UI to reduce the amount of custom CSS we’d be writing.
に
index.html
, 私たちのチャットウィンドウのテンプレートを作成します.<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.tailwindcss.com"></script>
<title>Anon Chat App</title>
</head>
<body>
<div class="flex-1 p:2 sm:p-6 justify-between flex flex-col h-screen">
<div id="messages" class="flex flex-col space-y-4 p-3 overflow-y-auto scrollbar-thumb-blue scrollbar-thumb-rounded scrollbar-track-blue-lighter scrollbar-w-2 scrolling-touch">
</div>
<div class="border-t-2 border-gray-200 px-4 pt-4 mb-2 sm:mb-0">
<div class="relative flex">
<input type="text" placeholder="Write your message!" class="w-full focus:outline-none focus:placeholder-gray-400 text-gray-600 placeholder-gray-600 pl-12 bg-gray-200 rounded-md py-3">
<div class="absolute right-0 items-center inset-y-0 hidden sm:flex">
<button type="button" class="inline-flex items-center justify-center rounded-lg px-4 py-3 transition duration-500 ease-in-out text-white bg-blue-500 hover:bg-blue-400 focus:outline-none">
<span class="font-bold">Send</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="h-6 w-6 ml-2 transform rotate-90">
<path d="M10.894 2.553a1 1 0 00-1.788 0l-7 14a1 1 0 001.169 1.409l5-1.429A1 1 0 009 15.571V11a1 1 0 112 0v4.571a1 1 0 00.725.962l5 1.428a1 1 0 001.17-1.408l-7-14z"></path>
</svg>
</button>
</div>
</div>
</div>
</div>
<script src="/socket.io/socket.io.js"></script>
<script src="./main.js"></script>
</body>
</html>
上記のHTMLファイルでは、2つのJavaScriptファイルを含み、最初のソケットを初期化しました.クライアント側と別のIOmain.js
カスタムJavaScriptコードを書くファイル.それから
main.js
ファイルは、チャットボックスにメッセージを追加できる機能を作成します.機能createMessage
は2つの引数を期待する.最初の引数はメッセージ文字列です、そして、2番目の引数はメッセージがユーザーか他の外部ユーザーからあるかどうか決定するブールです.// main.js
const messageBox = document.querySelector("#messages");
function createMessage(text, ownMessage = false) {
const messageElement = document.createElement("div");
messageElement.className = "chat-message";
const subMesssageElement = document.createElement("div");
subMesssageElement.className =
"px-4 py-4 rounded-lg inline-block rounded-bl-none bg-gray-300 text-gray-600";
if (ownMessage) {
subMesssageElement.className += " float-right bg-blue-800 text-white";
}
subMesssageElement.innerText = text;
messageElement.appendChild(subMesssageElement);
messageBox.appendChild(messageElement);
}
createMessage("Welcome to vahalla");
createMessage("Who are you to talk to me", true);
サーバーアプリケーションのコードを変更します.app.js
クライアントUIをレンダリングするには、静的ファイルを使用します.// app.js
const http = require("http");
const { Server } = require("socket.io");
const express = require("express");
const path = require("path");
const app = express();
app.use(express.static(path.join(__dirname, "public")));
const server = http.createServer(app);
const io = new Server(server);
io.on("connection", (socket) => {
console.log("connected");
});
server.on("error", (err) => {
console.log("Error opening server");
});
server.listen(8001, () => {
console.log("Server working on port 8001");
});
NOTE: To view the changes made in our application, we have to stop the running server application and re-run it for the new changes to take effect. So we are making use of
nodemon
to automate this process for us.
実行してnodemonをインストールします.
$ npm install -g nodemon
次にNodeMonを使用してノードアプリケーションを実行します.$ nodemon ./app.js
オープン[http://localhost:8001](http://localhost:3000)
あなたのブラウザでチャットアプリがどのように見えるかを表示します.Webソケット通信用の異なる部屋の作成
部屋を作成し、各部屋に接続されたユーザーの数を追跡するには
Room
我々のためにこのデータを管理するクラス.新しいファイルを作成します
room.js
プロジェクトのルートディレクトリにあります.その後、我々はRoom
クラスとコンストラクターは、我々の部屋の状態を維持するためのプロパティを初期化します.// room.js
// the maximum number of people allowed in each room
const ROOM_MAX_CAPACITY = 2;
class Room {
constructor() {
this.roomsState = [];
}
}
module.exports = Room;
The roomsState
は、作成した各部屋IDに関する情報とその部屋のユーザ数を保持するオブジェクトの配列です.だから典型的なroomsState
このようになります.// rooms state
[
{
roomID: "some id",
users: 1
},
{
roomID: "a different id",
users: 2
}
]
次に、部屋に参加するメソッドを追加します.どの部屋には、各部屋で許される参加者の最大数より少ないユーザー数を持っているかどうかを確認するために、部屋を通ってループします.リスト内のすべての部屋が占有されている場合、それは新しい部屋を作成し、その部屋のユーザー数を1に初期化します.ユニークなIDを生成するには、uuid 我々のアプリケーションで.
uuidをインストールします.
$ yarn add uuid
次に、次のように実行してパッケージをアプリケーションにインポートします.// room.js
const { v4: uuidv4 } = require("uuid");
class Room {
constructor() {
/**/
}
joinRoom() {
return new Promise((resolve) => {
for (let i = 0; i < this.roomsState.length; i++) {
if (this.roomsState[i].users < ROOM_MAX_CAPACITY) {
this.roomsState[i].users++;
return resolve(this.roomsState[i].id);
}
}
// else generate a new room id
const newID = uuidv4();
this.roomsState.push({
id: newID,
users: 1,
});
return resolve(newID);
});
}
}
module.exports = Room;
NOTE: Making use of an array to manage the rooms' state is, obviously, not the best way to do so. Imagine having thousands of rooms in your application and you have to loop through each room for each join request. It would execute at O(n). For the purpose of this tutorial, we will stick to this approach.
我々は別の方法を追加します
Room
クラスleaveRoom()
, 特定の部屋のユーザー数を減らすために.// room.js
class Room {
constructor() {
/**/
}
joinRoom() {}
leaveRoom(id) {
this.roomsState = this.roomsState.filter((room) => {
if (room.id === id) {
if (room.users === 1) {
return false;
} else {
room.users--;
}
}
return true;
});
}
}
module.exports = Room;
The leaveRoom()
メソッドは部屋のIDを取り、部屋の配列を通してループを行います.それが一致する部屋を見つけるならば、部屋のユーザーがその特定の部屋状態を削除するために1つであるかどうかチェックします.
部屋のユーザが1より大きいならば
leaveRoom()
方法は、ちょうどその部屋のユーザーの数を控除します.最後に
room.js
コードはこれに似ているはずです.// room.js
const { v4: uuidv4 } = require("uuid");
// the maximum number of people allowed in a room
const ROOM_MAX_CAPACITY = 2;
class Room {
constructor() {
this.roomsState = [];
}
joinRoom() {
return new Promise((resolve) => {
for (let i = 0; i < this.roomsState.length; i++) {
if (this.roomsState[i].users < ROOM_MAX_CAPACITY) {
this.roomsState[i].users++;
return resolve(this.roomsState[i].id);
}
}
const newID = uuidv4();
this.roomsState.push({
id: newID,
users: 1,
});
return resolve(newID);
});
}
leaveRoom(id) {
this.roomsState = this.roomsState.filter((room) => {
if (room.id === id) {
if (room.users === 1) {
return false;
} else {
room.users--;
}
}
return true;
});
}
}
module.exports = Room;
部屋に出入りする
私たちのチャットアプリケーション内のユーザーのためのさまざまなチャネルを作成するには、我々のための部屋を作成する予定です.
ソケット.IOはソケットが結合したり残したりできる任意のチャネルを作ることができます.これは、クライアントのサブセットにイベントをブロードキャストするために使用することができます.
(ソース:https://socket.io/docs/v3/rooms/ )
部屋に入るために、我々はユニークな部屋IDで部屋に加わるでしょう.
io.on("connection", socket => {
// join a room
socket.join("some room id");
socket.to("some room id").emit("some event");
});
当社のサーバーアプリケーションでは、新しいユーザーが接続に参加するとRoom.joinRoom()
我々のユニークな部屋IDであるユニークなIDを返します.// app.js
io.on("connection", async (socket) => {
const roomID = await room.joinRoom();
// join room
socket.join(roomID);
socket.on("disconnect", () => {
// leave room
room.leaveRoom(roomID);
});
});
メッセージの送受信
さて、クライアント側から送られてきたメッセージに対してイベントを放射するためにクライアント側のコードに戻ります.また、メッセージイベントをサーバーから来て聞いて、我々のチャットボックスにそのメッセージを書き込みます.
// main.js
socket.on("receive-message", (message) => {
createMessage(message);
});
sendButton.addEventListener("click", () => {
if (textBox.value != "") {
socket.emit("send-message", textBox.value);
createMessage(textBox.value, true);
textBox.value = "";
}
});
NOTE: In our chat application, we directly add the message from user to the chatbox without confirming if the message is received by the socket server. This is not usually the case.
その後、私たちのエクスプレスアプリケーションで.
// app.js
io.on("connection", async (socket) => {
const roomID = await room.joinRoom();
// join room
socket.join(roomID);
socket.on("send-message", (message) => {
socket.to(roomID).emit("receive-message", message);
});
socket.on("disconnect", () => {
// leave room
room.leaveRoom(roomID);
});
});
我々の急行アプリケーションコードを作ることは、最終的にこれのように見えます.// app.js
const http = require("http");
const { Server } = require("socket.io");
const express = require("express");
const path = require("path");
const Room = require("./room");
const app = express();
app.use(express.static(path.join(__dirname, "public")));
const server = http.createServer(app);
const io = new Server(server);
const room = new Room();
io.on("connection", async (socket) => {
const roomID = await room.joinRoom();
// join room
socket.join(roomID);
socket.on("send-message", (message) => {
socket.to(roomID).emit("receive-message", message);
});
socket.on("disconnect", () => {
// leave room
room.leaveRoom(roomID);
});
});
server.on("error", (err) => {
console.log("Error opening server");
});
server.listen(8001, () => {
console.log("Server working on port 8001");
});
クライアント側のJavaScriptはこのように見えます.// main.js
const messageBox = document.querySelector("#messages");
const textBox = document.querySelector("input");
const sendButton = document.querySelector("button");
function createMessage(text, ownMessage = false) {
const messageElement = document.createElement("div");
messageElement.className = "chat-message";
const subMesssageElement = document.createElement("div");
subMesssageElement.className =
"px-4 py-4 rounded-lg inline-block rounded-bl-none bg-gray-300 text-gray-600";
if (ownMessage) {
subMesssageElement.className += " float-right bg-blue-800 text-white";
}
subMesssageElement.innerText = text;
messageElement.appendChild(subMesssageElement);
messageBox.appendChild(messageElement);
}
const socket = io();
socket.on("connection", (socket) => {
console.log(socket.id);
});
socket.on("receive-message", (message) => {
createMessage(message);
});
sendButton.addEventListener("click", () => {
if (textBox.value != "") {
socket.emit("send-message", textBox.value);
createMessage(textBox.value, true);
textBox.value = "";
}
});
チャットアプリケーションのテスト
テキストを我々のチャットアプリには、我々は2つの部屋が作成されていることを確認する4つのブラウザを開きます.
結論
あなたがこれを見るならば、それは我々がこれまで読んで、おそらく我々のマシンで実行しているチャットアプリを持っていることを意味します.
この記事からコードを見つけることができますGitHub repository .
より多くの課題を含めるには、これらのチャットアプリケーションに含めることができる機能です
この記事を読むのを楽しむなら、あなたは考えることができますbuying me a coffee .
Reference
この問題について(ソケットで匿名のチャットルームを作成する.IOとエクスプレス.js), 我々は、より多くの情報をここで見つけました https://dev.to/zt4ff_1/creating-anonymous-chat-rooms-with-socketio-and-expressjs-1cm0テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol