Hey, I’m Meytili, and today we’re diving into the world of real-time communication with Go and WebSockets. Get ready to embark on an exciting journey as we build our very own chat application using the Melody library. Let’s jump right in!
Step 1: What do we need?
To create our real-time chat application, we will need a few essential tools and technologies:
- Go: Our trusted programming language, guiding us through the realms of backend magic.
- WebSockets: The secret sauce that enables seamless communication between clients and servers.
- The “github.com/olahol/melody” Package: Our tool of choice for handling WebSockets easily.
- HTML, JS, and Tailwind CSS: Adding a touch of frontend goodness to make our chat application shine.
Step 2: The backend part
Let’s start by setting up our Go project. Open your terminal and run the following command:
go mod init wschat
This initializes our Go module. Now, let’s proceed to the backend code.
Create a new file called
and import the necessary packages:main.go
package main
import (
"encoding/json"
"fmt"
"net/http"
"github.com/olahol/melody"
)
Next, set up our HTTP server and WebSocket handling:
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "index.html")
})
http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
// Handle WebSocket connections
})
fmt.Println("Server started on :8080")
err := http.ListenAndServe(":8080", nil)
if err != nil {
panic("Error starting server: " + err.Error())
}
}
Now, let’s add WebSocket functionality using the Melody library:
// Create a new Melody instance
m := melody.New()
http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
m.HandleRequest(w, r)
})
m.HandleMessage(func(s *melody.Session, msg []byte) {
m.Broadcast(jsonMessage) // Broadcast every message
})
To make our server a chat server, we need to handle messages differently:
Define a Message struct:
type Message struct {
Message string `json:"message"`
}
Modify the HandleMessage
function:
m.HandleMessage(func(s *melody.Session, msg []byte) {
fmt.Println(string(msg))
// read json message and send error if message is not a json message
var message Message
err := json.Unmarshal(msg, &message)
if err != nil {
s.Write([]byte(err.Error()))
return
}
// marshal the message
jsonMessage, err := json.Marshal(message)
if err != nil {
s.Write([]byte(err.Error()))
return
}
// get all connected clients and dont send to sender
sessions, err := m.Sessions()
if err != nil {
s.Write([]byte(err.Error()))
return
}
var sender *melody.Session
for _, se := range sessions {
if se == s {
sender = se
}
}
m.BroadcastOthers(jsonMessage, sender)
})
Step 3: Creating the HTML file
We need to create an
file to build the frontend part of our chat application. Here is a sample structure to get started:index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Real-Time Chat</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<div class="flex-1 p:2 sm:p-6 justify-between flex flex-col h-screen">
<div class="flex sm:items-center justify-between pb-4 border-b-2 border-gray-200">
<div class="relative flex items-center space-x-4">
<div class="flex flex-col leading-tight">
<div class="text-2xl flex items-center">
<span class="text-gray-700 px-12">Real Time chat</span>
</div>
</div>
</div>
</div>
<div id="messages" class="flex flex-col flex-1 space-y-4 p-3 overflow-y-auto scrollbar-thumb-blue scrollbar-thumb-rounded scrollbar-track-blue-lighter scrollbar-w-2 scrolling-touch text-md">
</div>
<div class="border-t-2 border-gray-200 px-4 pt-4 mb-2 sm:mb-0">
<div class="relative flex">
<input id="message-input" type="text" placeholder="Type here..." class="w-full focus:outline-none focus:placeholder-gray-200 text-gray-600 placeholder-gray-600 pl-5 bg-gray-200 rounded-md py-3">
<div class="absolute right-0 items-center inset-y-0 hidden sm:flex" onclick="sendMessage()">
<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 class="h-6 w-6 ml-2" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M1008.00076 6.285714q18.857143 13.714286 15.428571 36.571429l-146.285714 877.714286q-2.857143 16.571429-18.285714 25.714285-8 4.571429-17.714286 4.571429-6.285714 0-13.714286-2.857143l-258.857142-105.714286-138.285715 168.571429q-10.285714 13.142857-28 13.142857-7.428571 0-12.571428-2.285714-10.857143-4-17.428572-13.428572T365.715046 987.428571v-199.428571l493.714285-605.142857-610.857142 528.571428-225.714286-92.571428q-21.142857-8-22.857143-31.428572-1.142857-22.857143 18.285714-33.714285L969.143617 5.142857q8.571429-5.142857 18.285714-5.142857 11.428571 0 20.571429 6.285714z"/></svg>
</button>
</div>
</div>
</div>
</div>
</body>
</html>
Step 4: Make the HTML work, using JS magic
To add interactivity to our chat application, we’ll use JavaScript. Add the following
tag to your HTML file:<script>
<script>
console.log("Hello world!");
</script>
First, let’s connect to the WebSocket server:
var socket = new WebSocket("ws://localhost:8080/ws");
Next, let’s handle the incoming messages and display them on the page:
socket.onmessage = function(event) {
var data = JSON.parse(event.data);
// Create a new div element
var newDiv = document.createElement("div");
newDiv.innerHTML = `<div class="chat-message">
<div class="flex items-end">
<div class="flex flex-col space-y-2 max-w-xs mx-2 order-2 items-start">
<div><span class="px-4 py-2 rounded-lg inline-block rounded-bl-none bg-gray-300 text-gray-600">${ data.message }</span></div>
</div>
</div>
</div>`;
var messagesDiv = document.getElementById("messages");
messagesDiv.appendChild(newDiv);
};
Now, let’s make the send button work and send messages to the WebSocket server:
function sendMessage() {
var messageInput = document.getElementById("message-input");
var message = messageInput.value;
socket.send(JSON.stringify({ message: message }));
var newDiv = document.createElement("div");
// Reset the value
messageInput.value = "";
newDiv.innerHTML = `<div class="chat-message">
<div class="flex items-end justify-end">
<div class="flex flex-col space-y-2 max-w-xs mx-2 order-1 items-end">
<div><span class="px-4 py-2 rounded-lg inline-block rounded-br-none bg-blue-600 text-white">${ message }</span></div>
</div>
</div>
</div>`
var messagesDiv = document.getElementById("messages");
messagesDiv.appendChild(newDiv);
}
Everything should be done for now.
Step 5: Testing
To test our chat application, run the following command in your terminal:
go run .
Then, open your web browser and go to http://localhost:8080 to see the chat application in action.
Please note that this chat application is still unfinished, and there are additional features you can add, such as nicknames, improved security, and user login functionality.
The End
Congratulations! You have successfully built a real-time chat application using Go and WebSockets.
Remember, this chat application is just a starting point. There are many exciting features you can add to enhance its functionality. Some ideas include implementing user authentication, adding support for multiple chat rooms, or integrating emojis and file sharing capabilities.
I hope you enjoyed this tutorial and found it helpful. Feel free to explore and modify the code to suit your needs and take your chat application to the next level!
If you have any questions or feedback, please don’t hesitate to reach out. Have fun!