How to use Golang and React for WebSocket

I found myself wanting to try out little bit of experimenting to learn more about web sockets, let us try it out using golang and react.

First, set up a project Golang project by creating a folder and in it, create main.go file.

Golang WebSocket Server

It’s very simple if you take use of the already great crates that are out there. One that I found working out very well with web socket is gorilla websocket.

package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

func main() {
	http.HandleFunc("/ws", wsEndpoint)
	log.Fatal(http.ListenAndServe(":8080", nil))
}

func wsEndpoint(w http.ResponseWriter, r *http.Request) {
	upgrader.CheckOrigin = func(r *http.Request) bool { return true }
	// upgrade this connection to a WebSocket
	// connection
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
	}

	log.Println("Client Connected")
	err = ws.WriteMessage(1, []byte("Hello client you've connected!"))
	if err != nil {
		log.Println(err)
	}
	reader(ws)
}

func reader(conn *websocket.Conn) {
	for {
		// read in a message
		messageType, p, err := conn.ReadMessage()
		if err != nil {
			log.Println(err)
			return
		}

		// print out incoming message
		fmt.Println("incoming message: " + string(p))

		if err := conn.WriteMessage(messageType, p); err != nil {
			log.Println(err)
			return
		}
	}
}

You should be able to run your program from the get-go. This is how the mod file looks:

module example.com/m/v2

go 1.15

require github.com/gorilla/websocket v1.5.0 // indirect

http.HandleFunc("/ws", wsEndpoint)

So let’s go through the code, first of all we got a main function, the starting point of the program and in it will first of all take use of the http package and set up our listeners for the endpoint /ws, which we pass in the method wsEndpoint. So each

log.Fatal(http.ListenAndServe(":8080", nil))

The ListenAndServe function will be running our actual http server and we will print out error if we get one into the log.

func wsEndpoint(w http.ResponseWriter, r *http.Request) {
	upgrader.CheckOrigin = func(r *http.Request) bool { return true }
	// upgrade this connection to a WebSocket
	// connection
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
	}

	log.Println("Client Connected")
	err = ws.WriteMessage(1, []byte("Hi Client!"))
	if err != nil {
		log.Println(err)
	}
	reader(ws)
}

Our Endpoint function takes in a ResponseWriter and a Request object which is what we need to make to make the incoming request into a websocket protocol connection with our server. This is called that we do an upgrade. From the upgrade function we get back a ws connection which we can read messages from.

func reader(conn *websocket.Conn) {
	for {
		// read in a message
		messageType, p, err := conn.ReadMessage()
		if err != nil {
			log.Println(err)
			return
		}

		// print out incoming message
		fmt.Println("incoming message: " + string(p))

		if err := conn.WriteMessage(messageType, p); err != nil {
			log.Println(err)
			return
		}
	}
}

From our reader function we can read the message from the websocket which we convert from bytes into string with help from string(p), which we then can send a response back with WriteMessage on the same socket to the client.

React WebSocket Client

Now let’s create a React project, I like to use vite to get started fast like this:

npm create vite@latest

Then go with React and nativescript. Then what web socket package I use is websocket from here: https://www.npmjs.com/package/websocket. Also remember to download the types for typescript: node_modules/@types/websocket. So we will run npm install on these:

npm i websocket 
npm i node_modules/@types/websocket

Then in our React main.tsx let’s write some code where we connect to the server and send a random message for testing:

import { useEffect, useState } from 'react'
import logo from './logo.svg'
import './App.css'

import * as WebSocket from "websocket"




function App() {

  useEffect(() => {
    console.log("in it")
    const socket = new WebSocket.w3cwebsocket('ws://localhost:8080/ws');

    socket.onopen = function () {
      socket.send("helloheee!")
      socket.onmessage = (msg: any) => {
        console.log(msg);
        console.log("we got msg..")
      };
    };
  }, []);


  const [count, setCount] = useState(0)

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>Hello Vite + React!</p>
        <p>
          <button type="button" onClick={() => setCount((count) => count + 1)}>
            count is: {count}
          </button>
        </p>
        <p>
          Edit <code>App.tsx</code> and save to test HMR updates.
        </p>
        <p>
          <a
            className="App-link"
            href="https://reactjs.org"
            target="_blank"
            rel="noopener noreferrer"
          >
            Learn React
          </a>
          {' | '}
          <a
            className="App-link"
            href="https://vitejs.dev/guide/features.html"
            target="_blank"
            rel="noopener noreferrer"
          >
            Vite Docs
          </a>
        </p>
      </header>
    </div>
  )
}

export default App

Also worth noting, inside the main.tsx I removed the StrictMode elements

<React.StrictMode>

if I didn’t it would trigger the user effect twice for some reason. Anyway that’s it to get started fast with a web socket to start experimenting. Hope coding!

Blocking waiting for file lock on the registry index error in Rust

What helped for me was going to the task manager through CTRL+ALT+DELETE and selecting all the cargo.exe services and terminate them, and then reopen my IDE (Visual Code). Basically cargo the package manager was trying to launch multiple instances on the same project at once. Did this, and then just ran cargo clean and then cargo build without any problems. If you are in a Linux environment, try the following command in the terminal: sudo pkill rls cargo.