{"id":19782462,"url":"https://github.com/steadylearner/chat","last_synced_at":"2026-03-10T17:07:10.940Z","repository":{"id":37889932,"uuid":"163676720","full_name":"steadylearner/Chat","owner":"steadylearner","description":"Learn how to build chat app with Rust ws-rs.","archived":false,"fork":false,"pushed_at":"2023-02-28T23:29:11.000Z","size":864,"stargazers_count":31,"open_issues_count":12,"forks_count":8,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-06T05:34:18.149Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.steadylearner.com/blog","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/steadylearner.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-12-31T14:53:03.000Z","updated_at":"2024-11-13T15:09:40.000Z","dependencies_parsed_at":"2023-01-26T00:32:31.328Z","dependency_job_id":null,"html_url":"https://github.com/steadylearner/Chat","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steadylearner%2FChat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steadylearner%2FChat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steadylearner%2FChat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steadylearner%2FChat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/steadylearner","download_url":"https://codeload.github.com/steadylearner/Chat/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251791491,"owners_count":21644402,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T06:05:13.431Z","updated_at":"2026-03-10T17:07:05.911Z","avatar_url":"https://github.com/steadylearner.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--\n Post{\n   title: \"How to start Rust Chat App\",\n   subtitle: \"Build your local chat application with it.\",\n   image: \"post/chat/rust_chat_title.png\",\n   image_decription: \"Rust Chat App by Steadylearner\",\n   tags: \"Rust chat app code\",\n   theme: \"rust\",\n }\n--\u003e\n\n\u003c!-- Link here --\u003e\n\n[Steadylearner]: https://www.steadylearner.com\n[Steadylearner Github Repository]: https://github.com/steadylearner/Steadylearner\n[Steadylearner Chat]: https://github.com/steadylearner/Chat\n[How to deploy Rust Web App]: https://medium.com/@steadylearner/how-to-deploy-rust-web-application-8c0e81394bd5?source=---------9------------------\n[Steadylearner Post]: https://github.com/steadylearner/Steadylearner/tree/master/post\n[LinkedIn]: https://www.linkedin.com/in/steady-learner-3151b7164/\n[Twitter]: https://twitter.com/steadylearner_p\n\n[prop-passer]: https://github.com/steadylearner/prop-passer\n\n[How to install Rust]: https://www.rust-lang.org/learn/get-started\n[Rust Documentation]: https://doc.rust-lang.org/std/\n[cargo-edit]: https://github.com/killercup/cargo-edit\n[Rocket]: https://rocket.rs/\n[Concurrency in Rust]: https://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html\n\n[Websocket API]: https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API\n[ws-rs]: https://ws-rs.org/\n[ws-rs-html-example]: https://github.com/housleyjk/ws-rs/blob/master/examples/html_chat.rs\n[socket-io]: https://socket.io/\n[socket-io-and-ws-rs-comparision]: https://github.com/steadylearner/Chat/tree/master/socket_io\n\n[browserify]: https://github.com/browserify/browserify\n[node-emoji]: https://www.npmjs.com/package/node-emoji\n[has-emoji]: https://www.npmjs.com/package/has-emoji\n\n\u003c!-- Post for this series --\u003e\n\n\u003c!-- / --\u003e\n\n# How to start Rust Chat App\n\nYou can also find post for this at [Steadylearner Post for this](https://www.steadylearner.com/blog/read/How-to-start-Rust-Chat-App).\n\n\u003ch2 class=\"red-white\"\u003e[Prerequisite]\u003c/h2\u003e\n\n1. [How to install Rust]\n2. [Websocket API]\n3. [ws-rs]\n4. [ws-rs-html-example]\n5. [Steadylearner Chat]\n6. [browserify]\n7. [node-emoji]\n8. [Thread in Rust](https://doc.rust-lang.org/std/thread/)\n\n---\n\nYou will use **Rust** mainly to build socket server to handle messages. So you need to install it following the instruction from [its official website][How to install Rust].\n\nYou also need to understand what is [Websocket API] to understand what you need to connect, send, receive and close the websocket for your chat app.\n\n(You may also visit [socket-io] JavaScript framework if you are more familar with JavaScript to understand the topic better.)\n\nWe will use ws-rs Rust crate for this post. So I want you to visit [its website][ws-rs] and read its API and documenation first.\n\nThe chat app we will build here is just the improved version of [ws-rs-html-example]. Therefore, I want you to visit it and read its source code.\n\nI also prepared the examples to compare [ws-rs] to [socket-io] at [socket-io-and-ws-rs-comparision] GitHub page. You may refer to it if you are already knew  API of [socket-io].\n\nWhenever you have doubt about **Rust**, please visit [Rust Documentation] page and seach on your own. It will be better for you to read [Concurrency in Rust] and search other articles if you want to understand why Rust is fast.\n\n(If you were completely new at Rust, but familar with JavaScript, you may read [TypeScript](https://www.typescriptlang.org/docs/index.html) documentation first because the purpose of both langauges is to have strong type system. It will help you to learn **Rust** if you haven't any experience in Rust.)\n\n\u003cbr /\u003e\n\n\u003ch2 class=\"blue\"\u003eTable of Contents\u003c/h2\u003e\n\n1. Setup [Rocket] to serve files\n2. ws-rs for socket server\n3. HTML and CSS for layout\n4. JavaScript for chat app users\n5. Conclusion\n\n---\n\n\u003cbr /\u003e\n\n## 1. Setup Rocket to serve files\n\n(You can skip this part if you already downloaded [GitHub Respoitory][Steadylearner Chat] and understand how to structure Rust application.)\n\nIf you have tested code at [ws-rs-html-example] before you read on, you should have found that a single Rust(.rs) file does everything to render html, serve file, and exchange messages.\n\nIt may be a decent single file example but it will be difficult to build more complicated app later. Therefore, we will pass its role to serve files to [Rocket] web framework.\n\n(I prefer [it][Rocket] for it has many examples but you may use whatever framework.)\n\nWe can start this from our **Cargo.toml** file like the code snippet below or use **$cargo add ws-rs rocket**.(You can visit [cargo-edit] page for this command)\n\n```toml\n[package]\nname = \"chat_app_with_rust_by_steadylearner\"\nversion = \"0.1.0\"\nedition = \"2018\"\n\n[dependencies]\nws = \"0.8.1\"\nrocket = \"0.4.1\"\n```\n\nNothing complicated for our Cargo.toml, What we need is to notify **Rust** that we need [Rocket] to serve our files such as **HTML** file to work as socket client, CSS, JavaScript, images etc at webpage. \n\nThen, [ws-rs] crate to work as socket server to handle chat messages.\n\n(If you are not familar with [.toml files](https://doc.rust-lang.org/cargo/reference/manifest.html), you may think it is similar to **package.json** in JavaScript)\n\nThen we will build **main.rs** file first to be starting point for our Rust app.(Please, refer to the repository I gave before whenever you have doubts.)\n\n```rust\n#![feature(\n    proc_macro_hygiene,\n    decl_macro,\n    custom_attribute,\n    rustc_private,\n    type_ascription\n)]\n#[macro_use]\nextern crate rocket;\n\nextern crate ws;\n\nuse std::thread;\n\nmod route;\nuse crate::route::{get, static_files};\n\nmod chat;\nuse crate::chat::ws_rs;\n\nfn rocket() -\u003e rocket::Rocket {\n    let rocket_routes = routes![\n        static_files::file,\n        //\n        get::index,\n        get::chat,\n    ];\n\n    rocket::ignite()\n        .mount(\"/\", rocket_routes)\n}\n\nfn main() {\n    // 1.\n    thread::Builder::new()\n        .name(\"Thread for Rust Chat with ws-rs\".into())\n        // 2.\n        .spawn(|| {\n            ws_rs::websocket();\n        })\n        .unwrap();\n\n    rocket().launch();\n}\n```\n\nThe major part of the [Rocket] relevant code will be the boilerplate if you want to write minimum webpage with it. So you don't have to understand all at once.\n\nBut the important points here are\n\n1. We use [thread](https://doc.rust-lang.org/std/thread/) to separate chat server and not to affect(break) the main server that manages your website(It is Rocket here)\n\n2. You can assign **.stack_size(83886 * 1024)** here if you want to be serious with your chat app later.(You can search \"How many resources chat app need\" at your search engine.)\n\nThe part of the code snippet above includes\n\n```rust\nmod route;\nuse crate::route::{get, static_files};\n\nmod chat;\nuse crate::chat::ws_rs;\n\nfn rocket() -\u003e rocket::Rocket {\n    let rocket_routes = routes![\n        static_files::file,\n        //\n        get::index,\n        get::chat,\n    ];\n\n    rocket::ignite()\n        .mount(\"/\", rocket_routes)\n}\n```\n\nThey are to serve routes and init your app with them.\n\nThe important part here will be **static_files** and **ws_rs**.\n\nWhen you see the source code for static_routes first,\n\n```rust\nuse std::path::{Path, PathBuf};\nuse rocket::response::NamedFile;\n\n#[get(\"/static/\u003cfile..\u003e\")]\npub fn file(file: PathBuf) -\u003e Option\u003cNamedFile\u003e {\n    NamedFile::open(Path::new(\"static/\").join(file)).ok()\n}\n```\n\nIt is just to serve every files in static folder. You can just copy and paste it when you need to serve every files in static folder.\n\n(You can use simplified API in newer version of [Rocket] if you want.)\n\nfor **ws_rs** route, important part is\n\n```rust\n#[get(\"/chat\")]\npub fn chat() -\u003e io::Result\u003cNamedFile\u003e {\n    NamedFile::open(\"static/chat/index.html\")\n}\n```\n\nand it is to serve **HTML** files for chat app.\n\nFor example, https://www.yourwebsite.com/chat\n\nThe file will help users to connect socket and have their separtate data with JavaScript and brwoser API later. We will learn how to do that in the last part of this post.\n\nYou can refer to [Steadylearner Chat] and [Rocket] Documentation for more information.\n\n\u003cbr /\u003e\n\n## 2. ws-rs for socket server\n\nIn this part, we will learn how to build server socket with Rust.\n\nIf you see the code snippet for [ws-rs](https://github.com/steadylearner/Chat/blob/master/ws_rs_with_rocket/src/chat/ws_rs.rs), it will be similar to this and not so different to [ws-rs-html-example] from its official website.\n\n```rust\nuse ws::{\n    listen,\n    CloseCode,\n    Error,\n    Handler,\n    Handshake,\n    Message,\n    Request,\n    Response,\n    Result,\n    Sender,\n};\n\nuse std::cell::Cell;\nuse std::rc::Rc;\n\n// Server web application handler\nstruct Server {\n    out: Sender,\n    count: Rc\u003cCell\u003cu32\u003e\u003e,\n}\n\nimpl Handler for Server {\n    // 1.\n    fn on_request(\u0026mut self, req: \u0026Request) -\u003e Result\u003c(Response)\u003e {\n        match req.resource() {\n            \"/ws\" =\u003e {\n                // 2.\n                println!(\"Browser Request from {:?}\", req.origin().unwrap().unwrap());\n                // Uncomment this and find what you can do with them when you develope\n                // println!(\"Client found is {:?}\", req.client_addr().unwrap());\n                // println!(\"{:?} \\n\", \u0026resp);\n                let resp = Response::from_request(req);\n                resp\n            }\n\n            _ =\u003e Ok(Response::new(404, \"Not Found\", b\"404 - Not Found\".to_vec())),\n        }\n    }\n\n    fn on_open(\u0026mut self, handshake: Handshake) -\u003e Result\u003c()\u003e {\n        // 3.\n        self.count.set(self.count.get() + 1);\n        let number_of_connection = self.count.get();\n\n        if number_of_connection \u003e 5 {\n            // panic!(\"There are more user connection than expected.\");\n        }\n\n        // 4.\n        let open_message = format!(\"{} entered and the number of live connections is {}\", \u0026handshake.peer_addr.unwrap(), \u0026number_of_connection);\n        // println!(\"{}\", \u0026handshake.local_addr.unwrap());\n\n        println!(\"{}\", \u0026open_message);\n        self.out.broadcast(open_message);\n\n        Ok(())\n    }\n\n    fn on_message(\u0026mut self, message: Message) -\u003e Result\u003c()\u003e {\n        let raw_message = message.into_text()?;\n        println!(\"The message from the client is {:#?}\", \u0026raw_message);\n\n        // 5.\n        let message = if raw_message.contains(\"!warn\") {\n            let warn_message = \"One of the clients sent warning to the server.\";\n            println!(\"{}\", \u0026warn_message);\n            Message::Text(\"There was warning from another user.\".to_string())\n        } else {\n            Message::Text(raw_message)\n        };\n\n        // 6.\n        // Broadcast to all connections\n        self.out.broadcast(message)\n    }\n\n    fn on_close(\u0026mut self, code: CloseCode, reason: \u0026str) {\n        match code {\n            CloseCode::Normal =\u003e println!(\"The client is done with the connection.\"),\n            CloseCode::Away =\u003e println!(\"The client is leaving the site.\"),\n            CloseCode::Abnormal =\u003e {\n                println!(\"Closing handshake failed! Unable to obtain closing status from client.\")\n            },\n            _ =\u003e println!(\"The client encountered an error: {}\", reason),\n        }\n\n        // 7.\n        self.count.set(self.count.get() - 1)\n    }\n\n    fn on_error(\u0026mut self, err: Error) {\n        println!(\"The server encountered an error: {:?}\", err);\n    }\n}\n\npub fn websocket() -\u003e () {\n  println!(\"Web Socket Server is ready at ws://127.0.0.1:7777/ws\");\n  println!(\"Server is ready at http://127.0.0.1:7777/\");\n\n  // Rc is a reference-counted box for sharing the count between handlers\n  // since each handler needs to own its contents.\n  // Cell gives us interior mutability so we can increment\n  // or decrement the count between handlers.\n\n  // Listen on an address and call the closure for each connection\n  let count = Rc::new(Cell::new(0));\n  listen(\"127.0.0.1:7777\", |out| { Server { out: out, count: count.clone(), } }).unwrap()\n}\n```\n\nThe code snippet is a little bit long but the important parts will be\n\n1. [You need on_request part just once and you don't have to reconnect later](https://blog.stanko.io/do-you-really-need-websockets-343aed40aa9b).\n\n2. Use them to verify what you can do when the first socket connection between server and client happen and read [the documenation for them](https://ws-rs.org/api_docs/ws/struct.Request.html)\n\n3. We need to count how many connections there are because it affects connection quality. You may use the `number_of_connection` variable with conditional statement.(We will write code for that in client side later. You may use your own code.)\n\n4. **This is the most important part.** Even though we use localhost first and not real users, there should be some ways to differenciate the users from one another. So We will use return value of `\u0026handshake.peer_addr.unwrap()` for the purpose and also `number of connection` inside `fn on_open`. (If you open various windows for http://localhost:8000/chat later, You can see that it always return different values in your CLI.)\n\n5. This is where you can do various things with messages from users. You can use database to save messages from users here. You may write experimental code, for example, to send **warning** received from other users to everyone connected to the server socket.(You may test it with **!warn** in socket client later.)\n\n6. `self.out.broadcast(message)` used to send messages to all users. It is the last API used before the messages from the server arrive to clients connected to socket.\n\n7. `self.count.set(self.count.get() - 1)` is used to recalculate the total number of user when some client close the connection.\n\nI hope it helped you to understand this code snippet. You will need to find what are the uses of [Sender](https://doc.rust-lang.org/std/sync/mpsc/struct.Sender.html), [Rc](https://doc.rust-lang.org/std/rc/index.html) and [Cell](https://doc.rust-lang.org/std/cell/index.html) on your own if you want to understand it fully.\n\nIt is also important for you to understand that the most of the code used above are relevant to the JavaScript client code we will use later.\n\n(It is important to think that Frontend and Backend code all in one.)\n\n\u003cbr /\u003e\n\n## 3. HTML and CSS for layout\n\n![Rust Chat App](https://www.steadylearner.com/static/images/post/chat/rust_chat.png)\n\nWe briefly learnt the Rust serverside code to build our chat app. It is time to build Frotnend part to help users.\n\nIf you see the [index.html](https://github.com/steadylearner/Chat/blob/master/ws_rs_with_rocket/static/chat/index.html) file, The important part will be\n\n```html\n\u003chead\u003e\n  \u003c!-- 1. --\u003e\n  \u003clink rel=\"stylesheet\" href=\"/static/css/normalize.css\" /\u003e\n  \u003clink rel=\"stylesheet\" href=\"/static/css/steadylearner.css\" /\u003e\n  \u003clink rel=\"stylesheet\" href=\"/static/chat/index.css\" /\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n  \u003csection\u003e\n    \u003cnav id=\"nav\" class=\"nav flex center\"\u003e\n      \u003ca\n        href=\"https://www.steadhylearner.com/blog\"\n        title=\"Click it to learn how to code this.\"\n        class=\"flex no-text-decoration hover cursor-pointer transition-half right-auto\"\n      \u003e\n        \u003cspan class=\"white\" \u003eRust Chat App\u003c/span\u003e\n      \u003c/a\u003e\n      \u003c!-- 2. --\u003e\n      \u003cspan\n        id=\"exit\"\n        class=\"margin-right-one white cursor-pointer hover transition\"\n      \u003e\n        Exit\n      \u003c/span\u003e\n    \u003c/nav\u003e\n    \u003cul\n      id=\"messages\"\n    \u003e\n      \u003c!-- 3. --\u003e\n    \u003c/ul\u003e\n    \u003cform id=\"form\" class=\"chat-input flex center\"\u003e\n      \u003cimg\n        id=\"code\"\n        class=\"flex center rust-icon hover cursor-pointer transition-half\"\n        title=\"Click this to use markdown or not\"\n        src=\"/static/images/Rust.svg\"\n      /\u003e\n      \u003cinput\n        id=\"msg\"\n        type=\"text\"\n        placeholder=\"Type here to start to talk with others.\"\n        autocomplete=\"off\"\n      \u003e\n      \u003cbutton class=\"blue cursor-pointer\" \u003eSend\u003c/button\u003e\n      \u003cbutton\n        id=\"clear\"\n        type=\"button\"\n        class=\"margin-left-one red-white cursor-pointer\"\n      \u003e\n        Clear\n      \u003c/button\u003e\n    \u003c/form\u003e\n  \u003c/section\u003e\n  \u003c!-- 4. --\u003e\n  \u003cscript\n    src=\"/static/chat/bundle.js\"\n    type=\"text/javascript\"\n  \u003e\n  \u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\nThe main points here are\n\n1. They are CSS files for layout. You can edit or use your own if you want.\n\n2. We will use various ids inside html file to select and manipulate them with JavaScript later.(We will use id to make our simple Rust chat app development easy without Frontend framework)\n\n3. The chat message will be written here inside `\u003cli\u003e` wrappers and it is important to know that they are under `\u003cul id=\"messages\" \u003e` to be deleted easily later with JavaScript `removeMessages` function later.\n\n4. We will use [browserify] to bundle our JavaScript file with NPM modules later. It will help us to use emoji .\n\nThey are to be used with JavaScript and layout and when you run your app later it will be similar to the image you saw.\n\n(**steadylearner.css** above is especially used for React and [prop-passer] package that I wrote, it is just the bunch of class names that does one thing at a time. I want you not to be confused with many CSS classes when you see the source code. You can verify how they work better at [Steadylearner])\n\n\u003cbr /\u003e\n\n## 4. JavaScript for chat app users\n\nWe prepared a lot to do something interesting with our Rust chat app. In this part, we will write a JavaScript code that will help users to use it in there browser.\n\nIf you already have experience with chat app. The part 1. and 2. is already sufficient for you to start your Rust chat app.\n\nSo before you read on I want you know the two points.\n\n1. I haven't written code for chat app before this post. So please use this just for reference.\n\n2. I decided not to use Frontend Frameworks here because I wanted to find that I can write something useful without them.\n\nTherefore, the code below may not be well-organized and want you to use framework if you want to make it advanced with database, login, send and receive video and image etc.\n\nThe **index.js** file we will use will be similar to the code below.\n\n```js\n\n// 1.\n\nconst emoji = require(\"node-emoji\");\nconst hasEmoji = require(\"has-emoji\");\n\nconst socket = new WebSocket(\"ws://127.0.0.1:7777/ws\");\n\n// 2.\n\nfunction getDateTime() {\n  const today = new Date();\n  const date = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate();\n  const time = today.getHours() + \":\" + today.getMinutes() + \":\" + today.getSeconds();\n  const payload = date + ' ' + time;\n  return payload;\n}\n\nfunction removeMessages() { // remove child elements from its parent element\n  const messages = document.getElementById(\"messages\");\n  while (messages.firstChild) {\n    messages.removeChild(messages.firstChild);\n  }\n}\n\nlet open = false;\n\nlet userId = \"\";\nlet userInputs = [];\n\nlet server = []\n\nsocket.addEventListener('open', function (event) {\n  // socket.send('Start to chat');\n  console.log(\"Start to chat\");\n});\n\n// 3.\n\nconst clear = document.getElementById(\"clear\");\nclear.onclick = removeMessages;\n\nconst exit = document.getElementById(\"exit\");\nexit.onclick = function () {\n  socket.close();\n}\n\n// 4.\n\nconst form = document.getElementById(\"form\");\n\nform.onsubmit = function (event) {\n  event.preventDefault();\n  const input = document.getElementById(\"msg\");\n\n  if (input.value === \"\") {\n    return;\n  }\n\n  if (input.value === \"!clear\") {\n    removeMessages()\n    input.value = \"\";\n    return;\n  }\n\n  if (input.value === \"!exit\") {\n    socket.close();\n    return;\n  }\n\n  const userInputWithTime = `${userId} typed ${input.value} at ${getDateTime()}`;\n  userInputs.push(userInputWithTime);\n\n  socket.send(`${userId}: ${input.value}`);\n  input.value = \"\";\n  // Comment it and find the difference(It scroll down the window when user type)\n  setTimeout(() =\u003e window.scrollTo({ top: window.innerHeight, behavior: \"auto\" }), 10);\n};\n\nsocket.onmessage = function (event) {\n  // To save what server sent to localStorage, use database in production\n  const messagefromServer = `Server ${event.origin} sent ${event.data} at ${getDateTime()}`\n  server.push(messagefromServer);\n\n  // if (userInputs[userInputs.length - 1] === \"!warn\") {\n  //   alert(\"You sent warning to the other users\");\n  // }\n\n  if (event.data.includes(\"!clearall\")) {\n    removeMessages();\n    return;\n  }\n\n  if (event.data.includes(\"!exitall\")) {\n    socket.close();\n    return;\n  }\n\n  if (event.data.includes(\"!x-opacity\")) {\n    const messages = document.getElementById(\"messages\");\n    if (messages.className === \"x-opacity\") { messages.className = \"\"; } else { messages.className = \"x-opacity\" }\n    return;\n  }\n\n  // 5.\n  if (!open) {\n    // To give id to user and verify the maximum number, only work once\n\n    // See the Rust code we defined before and find that they are relevant.\n\n    // We pick the first(id for user and will be You with JavaScript)\n    // and the last part(number of connection) from\n    // open_message variable with JavaScript\n\n    // fn on_open(\u0026mut self, handshake: Handshake) -\u003e Result\u003c()\u003e {\n    //     self.count.set(self.count.get() + 1);\n    //     let number_of_connection = self.count.get();\n\n    //     let open_message = format!(\"{} entered and the number of live connections is {}\", \u0026handshake.peer_addr.unwrap(), \u0026number_of_connection);\n    //     self.out.broadcast(open_message); -\u003e becomes event.data\n\n    //     Ok(())\n    // }\n\n    let separate = event.data.split(\" \");\n    userId = separate[0];\n\n    const messages = document.getElementById(\"messages\");\n    const li = document.createElement(\"li\");\n    const p = document.createElement(\"p\");\n\n    let totalNumber = separate[separate.length - 1];\n    // 6.\n    if (totalNumber \u003e 5) {\n      p.textContent = `${totalNumber - 1} is maximum user allowed. Wait for others exit the chat.`;\n      p.className = \"red-white\";\n      li.append(p)\n      messages.append(li);\n      socket.close();\n      return;\n    }\n\n    open = true;\n\n    p.textContent = `Your id is ${userId} and \"You\" will be used in this page instead`;\n    p.className = \"blue\";\n    li.append(p)\n    messages.append(li);\n    return;\n  } else {\n    let fromServer = event.data;\n    const beforePayload = fromServer.split(\" \")[0];\n    const authorOfMessage = beforePayload.slice(0, beforePayload.length - 1); // to get the id part of the message\n\n    // if (authorOfMessage !== userId \u0026\u0026 fromServer.includes(`!exclude ${userId}`)) {\n    if (fromServer.includes(`!exclude ${userId}`)) {\n      socket.close();\n      return;\n    }\n\n    const messages = document.getElementById(\"messages\");\n    const li = document.createElement(\"li\");\n\n    // Give color and \"You\" for a user when author of the messages is the user.\n    if (authorOfMessage === userId) {\n      li.className = \"red-white\";\n      fromServer = fromServer.replace(userId, \"You\");\n    }\n\n    // 7.\n    const includeEmoji = hasEmoji(emoji.emojify(fromServer));\n    afterEmoji = includeEmoji ? emoji.emojify(fromServer) : fromServer;\n\n    const p = document.createElement(\"p\");\n    p.append(afterEmoji)\n    li.append(p);\n    messages.append(li);\n    return;\n  }\n};\n\n// 8.\nsocket.onclose = function (event) {\n  const closeMessage = event.data === undefined ? \"Server, You or another user closed the connection.\" : \"WebSocket is closed now.\"\n  const messages = document.getElementById(\"messages\");\n\n  const li = document.createElement(\"li\");\n  li.append(closeMessage)\n  li.className = \"blue\";\n  messages.append(li);\n\n  localStorage.setItem(\"userInputs\", `[${userInputs}]`);\n  localStorage.setItem(\"server\", `[${server}]`);\n};\n```\n\nThe code snippet is a little bit long and I will explain only important parts here.\n\n1. We import modules you need later to use emojis in your chat app and connect your client to the web socket server with `new WebSocket(\"ws://127.0.0.1:7777/ws\");`.(You can test it in your browser later)\n\n2. We define custom functions to help log time when the user send messages and remove messages. Then we make the default state for client that we will manipulate with JavaScript later.\n\n3. We assign roles for HTML code with id **clear** and **exit** we wrote in **index.html** before. It won't be difficult to understand what they do and you can find the codes that does similar things in **4.** .\n\n4. We find HTML element with id **form** with `document.getElementById`. Then we define what should happen when users type to it. We save the user input with time(**userInputs.push(userInputWithTime);**) and send it to the server with `socket.send`.(You can see that you can write some features before user input is sent to the socket server such as \"clear\" and \"exit\" here.)\n\n5. **This is the most important**. We defined some variables in **2.** and we can use it to assign **id** to user with **let separate = event.data.split(\" \");** and **userId = separate[0];**. Then, verify the user is already connected to server or not with JavaScript(socket is open or not). You can see that we turn **open = false;** to **open = true;** inside it and the client side code will execute code inside **if(!open)** only once.\n\n6. We didn't write code what to do when there are more users than allowed before at Rust server side. So we make client to leave the connection with JavaScript here.\n\n7. Use this part to allow users to type emojis easily. Please, read the doucmenation for them.([node-emoji], [has-emoji])\n\n8. When socket closes, we notify users that the socket connection is closed and save messages from the user, other users and server to the localStorage.(You can use your database API instead.)\n\nYou can modify and bundle them with [Browserify] `$browserify index.js \u003e bundle.js` after you install them with `$sudo npm install -g browserify`.\n\nThen you can run your chat app with `$cargo run` and verify the result and test them with various windows open while you type commands defined here and click the components.\n\n\u003cbr /\u003e\n\n## 4. Conclusion\n\nI hope the post was helpful to start your own chat app with Rust. It may not be sufficient to call it complete chat application. But it would be a starting point to write chat app with Rust.\n\nIt was also my first trial to write chat app. So please contribute to Steadylearner Chat repository or Steadylearner Post for this blog post if you find something to improve.\n\nIf you want to know someone who wants to improve his coding skill in Rust, JavaScript and Python everyeday, please contact me with [LinkedIn] and [Twitter]\n\n(I would be grateful also if someone give me a chance to know who can help me to imporve Rust code skill for it is difficult to find one here.)\n\nI am planning to convert Frontend code(HTML and JavaScript) used here to Rust with one of its web frameworks later and may write post for that also.\n\nWe might learn how to write Rust code for Frontend and Backend code later with this example.\n\n**Thanks and please share this post with others**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsteadylearner%2Fchat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsteadylearner%2Fchat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsteadylearner%2Fchat/lists"}