Skip to content

Instantly share code, notes, and snippets.

@steadylearner
Created May 16, 2019 13:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save steadylearner/e809a298064fbbdaf5983c460eaedae7 to your computer and use it in GitHub Desktop.
Save steadylearner/e809a298064fbbdaf5983c460eaedae7 to your computer and use it in GitHub Desktop.

In this post, we will learn how to build simple chat app in your local machine with Rust and simple JavaScript.

If you already have expereinece in Rust, you can just clone the Steadylearner Chat GitHub repository.

Then, $yarn in /static/chat folder to download NPM packages and $cargo run for Rust crates in ws_rs_with_rocket folder.

It will show you the chat app with Rust Backend at http://localhost:8000/chat.


[Prerequisite]

  1. How to install Rust
  2. Websocket API
  3. ws-rs
  4. ws-rs-html-example
  5. Steadylearner Chat
  6. browserify
  7. node-emoji
  8. Thread in Rust

You will use Rust mainly to build socket server to handle messages. So you need to install it following the instruction from its official website.

You 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.

(You may also visit socket-io JavaScript framework if you are more familar with JavaScript to understand the topic better.)

We will use ws-rs Rust crate for this post. So I want you to visit its website and read its API and documenation first.

The 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.

I 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.

Whenever 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.

(If you were completely new at Rust, but familar with JavaScript, you may read TypeScript 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.)


Table of Contents

  1. Setup Rocket to serve files
  2. ws-rs for socket server
  3. HTML and CSS for layout
  4. JavaScript for chat app users
  5. Conclusion


1. Setup Rocket to serve files

(You can skip this part if you already downloaded GitHub Respoitory and understand how to structure Rust application.)

If 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.

It 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. I prefer Rocket for it has many examples but you may use whatever framework.

We 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)

https://gist.github.com/534ad909b2256a17be341266c04eb179

Nothing 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.

Then, ws-rs crate to work as socket server to handle chat messages.

(If you are not familar with .toml files, you may think it is similar to package.json in JavaScript)

Then 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.)

https://gist.github.com/1f91b81bd35c5598abf4022eb00e4391

The major part of the Rocket relevant code will be the boilerplate if you want to write minimum web with it. So you don't have to understand all at once.

But the important points here are

  1. We use thread to separate chat server and not to affect(break) the main server that manages your website(It is Rocket here)

  2. 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.)

The part of the code snippet above includes

https://gist.github.com/c37753fb602a9649f16261839ab77cef

They are to serve routes and init your app with them. The important part here will be static_files and ws_rs.

When you see the source code for static_routes first.

https://gist.github.com/ea1dead9a5309d7438f108bd9ae9df5f

It 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.

(You can use simplified API in newer version of Rocket if you want.)

for ws_rs route, important part is

https://gist.github.com/76499701786a355f0b430ee10641573b

and it is to serve HTML files for chat app when user visit https://www.yourwebsite.com/chat.

The 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.

You can refer to Steadylearner Chat and Rocket Documentation for more information.


2. ws-rs for socket server

In this part, we will learn how to build server socket with Rust.

If you see the code snippet for ws-rs, it will be similar to this and not so different to ws-rs-html-example from its official website.

https://gist.github.com/3af07c416b18aad120a048565a9588fe

The code snippet is a little bit long but the important parts will be

  1. You need on_request part just once and you don't have to reconnect later.

  2. Use them to verify what you can do when the first socket connection between server and client happen and read the documenation for them

  3. 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.)

  4. 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 &handshake.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.)

  5. 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.)

  6. 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.

  7. self.count.set(self.count.get() - 1) is used to recalculate the total number of user when some client close the connection.

I hope it helped you to understand this code snippet. You will need to find what are the uses of Sender, Rc and Cell on your own if you want to understand it fully.

It 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.

(It is important to think that Frontend and Backend code all in one.)


3. HTML and CSS

Rust Chat App

We briefly learnt the Rust serverside code to build our chat app. It is time to build Frotnend part to help users.

If you see the index.html file, The important part will be

https://gist.github.com/6647d45f97da9332e6ee0d2174448fb1

The main points here are

  1. They are CSS files for layout. You can edit or use your own if you want.

  2. We will use various ids inside html file to select and manipulate them with JavaScript later.(We will use id to make development easy without frontend framework)

  3. The chat message will be written here inside <li> wrappers and it is important to know that they are under <ul id="messages" > to be deleted easily later with JavaScript removeMessages function later.

  4. We will use browserify to bundle our JavaScript file with NPM modules later. It will help us to use emoji .

They are to be used with JavaScript and layout and when you run your app later it will be similar to the main image of this post.

(steadylearner.css above is especially used for React and prop-passer package that I wrote, it is just the bunch of class name 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 it at Steadylearner)


4. JavaScript for chat app users

We 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.

If you already have experience with chat app. The part 1. and 2. is already sufficient for you to start your Rust chat app.

So before you read on I want you know the two points.

  1. I haven't written code for chat app before this post. So please use this just for reference.

  2. I decided not to use Frontend Frameworks here because I want to find that I can write something useful without them.

Therefore, the code below may not be well-organized and want you to use framework if you want to make it advanced.

The index.js file we will use will be similar to the code below.

https://gist.github.com/ccf298bc946d194cc51dd2d3996fe4f2

The code snippet is a little bit long and I will explain only important parts here.

  1. We import modules you need later to use Emoji 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 with I ❤️ Rust in your browser later)

  2. 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.

  3. 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. .

  4. We find html element with id form with document.getElementById. Then we define what should happen when user 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.)

  5. 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.

  6. 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.

  7. Use this part to allow users to type emoji easily. Please, read the doucmenation for them.(node-emoji, has-emoji)

  8. 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.)

You can modify and bundle them with Browserify $browserify index.js > bundle.js after you install them with $sudo npm install -g browserify.

Then 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.


4. Conclusion

I 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.

It 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.

If 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

(I would be grateful also if someone give me a chance to imporve Rust code skill for it is difficult to find one here.)

I am planning to convert Frontend code(html and JavaScript) used here to Rust with its webframework later and may write post for that also.

Thanks and please share this post with others

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment