0
0

Golang+Reactでアプリを作成してみた【Realtime Chat App】

Last updated at Posted at 2024-05-27

Technology used

golang
goroutines
websockets
webserver
channels

Frontend
react

backendを作成

①backendディレクトリとmain.jsを作成

# バックエンド用のディレクトリを作成
mkdir backend
touch main.go
cd backend
go mod init chatapplication
go get github.com/gorilla/websocket
go run main.go

②main.goを作成する

backend/main.js
package main

import (
	customwebsocket "chatapplication/websocket"
	"log"
	"net/http"
)

func serverWs(pool *customwebsocket.Pool,w http.ResponseWriter, r *http.Request) {
    log.Println("This is working")
    conn, err := customwebsocket.Upgrade(w,r)
    if err != nil {
        log.Println(err)
        return
    }

    client := &customwebsocket.Client{
        Conn: conn,
        Pool: pool,
    }
    pool.Register <- client
    client.Read()
}

func setupRoutes(){
    log.Println("This is working")
    pool := customwebsocket.NewPool()
    go pool.Start()

    http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
        serverWs(pool, w, r)
    })
}

func main() {
    setupRoutes()
    http.ListenAndServe(":9000", nil)
};

③backendにwebsocketフォルダとwebsocket.goを作成する

mkdir websocket
touch websocket.go
backend/websocket/websocket.go
package customwebsocket

import (
	"log"
	"net/http"

	"github.com/gorilla/websocket"
)

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

func Upgrade(w http.ResponseWriter, r *http.Request) (*websocket.Conn, error){
    upgrader.CheckOrigin = func(r *http.Request) bool { return true }

    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Println("websocket connection error:", err)
		return nil, err
    }
	return conn, nil
}
cd backend
go mod tidy

④backendにwebsocket/client.goを作成する

backend/websocket/client.go
package customwebsocket

import (
	"fmt"
	"sync"

	"github.com/gorilla/websocket"
)

type Client struct{
	Conn * websocket.Conn
	Pool *Pool
	mu sync.Mutex
}

type Message struct {
    Type int `json:"type"`
    Body string `json:"body"`
}

func(c *Client) Read(){
	defer func ()  {
		c.Pool.Unregister <- c
		c.Conn.Close()
	}()

	for {
		msgType, msg, err := c.Conn.ReadMessage()
		if err != nil {
			fmt.Println(err)
					return
		}
		m := Message{Type: msgType, Body: string(msg)}
		c.Pool.Broadcast <- m
		fmt.Println("msg recived===>>>\n", m)
	}
}

⑤backendにwebsocket/pool.goを作成する

backend/websocket/pool.go
package customwebsocket

import "fmt"

type Pool struct{
	Register chan *Client
	Unregister chan *Client
	Clients map [*Client] bool
	Broadcast chan Message
}

func NewPool() *Pool{return &Pool{
	Register: make(chan *Client),
	Unregister:  make(chan *Client),
	Clients: make(map [*Client] bool),
	Broadcast: make(chan Message),
}}

func(pool *Pool) Start(){
	for {
		select{
		case client := <-pool.Register:
			pool.Clients[client] = true
			fmt.Println("total connection ppol:- ", len(pool.Clients))
			for k, _ := range pool.Clients{
				fmt.Println(k)
				k.Conn.WriteJSON(Message{Type: 1, Body: "New User Joined"})
			}
		case client := <-pool.Unregister:
			delete(pool.Clients,client)
			fmt.Println("total connection ppol:- ", len(pool.Clients))
			for k, _ := range pool.Clients{
				fmt.Println(k)
				k.Conn.WriteJSON(Message{Type: 1, Body: "User Disconnected"})
			}
		case msg := <-pool.Broadcast:
			fmt.Println("broadcasting a message")
			for k, _ := range pool.Clients {
				if err := k.Conn.WriteJSON(msg); err != nil {
					fmt.Println(err)
					return
				}
			}
		}
	}
}

Frontendを作成する

①frontendディレクトリ

mkdir frontend
cd frontend
npx create-react-app <プロジェクト>

②srcにapiフォルダとindex.jsを作成する

src/api/index.js
var socket = new WebSocket('ws://localhost:9000/ws');

let connect = (cb) => {
  console.log('connecting');

  socket.onopen = () => {
    console.log('websocket connected successfully');
  };

  socket.onmessage = (msg) => {
    console.log('message from socket', msg);
    cb(msg);
  };
  socket.onclose = (event) => {
    console.log('websocket connected closed', event);
  };
  socket.onerror = (error) => {
    console.log('websocket error', error);
  };
};
let sendMsg = (msg) => {
  console.log('msg send:-', msg);
  socket.send(msg);
};

export { connect, sendMsg };

mkdir api
touch index.js

③srcにComponents/Header/Header.jsxを作成する

src/Components/Header/Header.jsx
import React from 'react';
import './Header.scss';

const Header = () => {
  return (
    <div>
      <h2>Go chat application in react</h2>
    </div>
  );
};

export default Header;

④srcにComponents/Header/Header.scssを作成する

src/Components/Header/Header.scss
.header {
  background-color: gray;
  color: #ffeda3;
  h2 {
    font-size: 5em;
    text-align: center;
  }
}

⑤srcにComponents/Header/index.jsを作成する

src/Components/Header/index.js
import Header from './Header';

const index = () => {
  return <div>index</div>;
};

export default Header;
cd frontend
cd chat
npm i sass --save-dev

⑥srcにComponents/ChatInput/ChatInput.jsxを作成する

src/Components/ChatInput/ChatInput.jsx
import React, { Component } from 'react';
import './ChatInput.scss';

class ChatInput extends Component {
  render() {
    return (
      <div className='ChatInput'>
        <input onKeyDown={this.props.send} placeholder='Enter a message...' />
      </div>
    );
  }
}

export default ChatInput;

⑦srcにComponents/ChatInput/ChatInput.scssを作成する

.ChatInput {
  width: 90%;
  display: block;
  margin: auto;

  input {
    padding: 10px;
    margin: 0;
    background-color: white;
    font-size: 15px;
    border: none;
    border-radius: 5px;
    border: 1px solid black;
    width: 98%;
  }
}

⑧srcにComponents/ChatInput/index.jsを作成する

src/Components/ChatInput/index.js
import ChatInput from './ChatInput';

const index = () => {
  return <div>index</div>;
};

export default ChatInput;

⑨srcにComponents/Message/Message.jsxを作成する

src/Components/Message/Message.jsx
import React, { Component } from 'react';
import './Message.scss';

class Message extends Component {
  constructor(props) {
    super(props);
    let temp = JSON.parse(this.props.message);
    this.state = { message: temp };
  }
  render() {
    return <div className='Message'>{this.state.message.body}</div>;
  }
}

export default Message;

⑩srcにComponents/Message/Message.scssを作成する

src/Components/Message/Message.scss
.Message {
  display: block;
  background-color: lightblue;
  margin: 10px auto;
  padding: 10px 20px;
  border-radius: 5px;
  box-shadow: 0 5px 15px -5px black;
  clear: both;

  &.me {
    color: rgb(138, 131, 245);
    float: right;
  }
}

⑪srcにComponents/Message/index.jsを作成する

src/Components/Message/index.js
import Message from './Message';

export default Message;

⑫srcにComponents/ChatHistory/ChatHistory.jsxを作成する

src/Components/ChatHistory/ChatHistory.jsx
import React, { Component } from 'react';
import './ChatHistory.scss';
import Message from '../Message';

class ChatHistory extends Component {
  render() {
    const messages = this.props.ChatHistory.map((msg) => (
      <Message key={msg.timeStamp} message={msg.data} />
    ));
    console.log(messages);
    return (
      <div className='ChatHistory'>
        <h2>Chat History</h2>
        {messages}
      </div>
    );
  }
}

export default ChatHistory;

⑬srcにComponents/ChatHistory/ChatHistory.scssを作成する

src/Components/ChatHistory/ChatHistory.scss
.ChatHistory {
  background-color: lightcoral;
  margin: 0;
  padding: 20px;
  h2 {
    margin: 0;
    padding: 0;
    color: white;
  }
}

⑭srcにComponents/ChatHistory/index.jsを作成する

src/Components/ChatHistory/index.js
import ChatHistory from './ChatHistory';

export default ChatHistory;

⑮src/App.jsを編集する

src/App.js
import Header from './Components/Header';
import ChatInput from './components/ChatInput';
import './App.css';
import React, { Component } from 'react';
import { connect, sendMsg } from './api';
import ChatHistory from './components/ChatHistory';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      chatHistory: [],
    };
  }

  componentDidMount() {
    connect((msg) => {
      console.log();
      this.setState((prevState) => ({
        chatHistory: [...prevState.chatHistory, msg],
      }));
      console.log(this.state);
    });
  }

  send(event) {
    if (event.keyCode === 30) {
      sendMsg(event.target.value);
      event.target.value = '';
    }
  }

  render() {
    return (
      <div className='App'>
        <Header />
        <ChatHistory chatHistory={this.state.chatHistory} />
        <ChatInput send={this.send} />
      </div>
    );
  }
}
export default App;

参考サイト

GO + REACT Fullstack App - Chat Application PART- 1 IN HINDI
GO + REACT Fullstack App - Chat Application PART- 2 IN HINDI
GO + REACT Fullstack App - Chat Application PART- 3 IN HINDI
GO + REACT Fullstack App - Chat Application PART- 4 IN HINDI
GO + REACT Fullstack App - Chat Application PART- 5 IN HINDI
GO + REACT Fullstack App - Chat Application PART- 6 IN HINDI
GO + REACT Fullstack App - Chat Application PART- 7 IN HINDI
GO + REACT Fullstack App - Chat Application PART- 8 IN HINDI
GO + REACT Fullstack App - Chat Application PART- 9 IN HINDI

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0