この記事はHRBrain Advent Calendar 2024 23日目の記事です。
はじめに
最近今年初の鍋を食べたyakiniku0220です。
好きな鍋はもつ鍋ときりたんぽです。
今回はGorilla WebSocketを使ってターミナル上で動くチャットツールを作ってみました。
自分はGoを始めてまだ1年が経っていないため勉強も兼ねて今回作ってみました。
デモ
実際の画面です。
このような感じでクライアント同士でのチャットをターミナル上でできます。
client側とserver側でどういう処理をしているかの説明です。
まず初めにserverディレクトリのmain.go側の説明です。
こちらはWebSocketの設定と接続管理をやってます。
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
次に接続処理です。
func handleConnections(w http.ResponseWriter, r *http.Request) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Printf("Error upgrading connection: %v", err)
return
}
defer ws.Close()
clients[ws] = true
log.Println("New client connected")
for {
var msg string
err := ws.ReadJSON(&msg)
if err != nil {
log.Printf("Error reading message: %v", err)
delete(clients, ws)
break
}
broadcast <- msg
}
}
ws, err := upgrader.Upgrade(w, r, nil)
まずgorilla/websocket
ライブラリのUpgrader構造体を使って、HTTP接続をWebSocket接続に切り替える処理をしています。
その後接続ができた場合、成功時のメッセージをlog.Printlnを使用して出力します。
for {
var msg string
err := ws.ReadJSON(&msg)
if err != nil {
log.Printf("Error reading message: %v", err)
delete(clients, ws)
break
}
broadcast <- msg
}
次の処理ではクライアント側からのメッセージを取得し文字列に変換後、broadcastチャネルにメッセージを送信してます。
func handleMessages() {
for {
msg := <-broadcast
for client := range clients {
err := client.WriteJSON(msg)
if err != nil {
log.Printf("Error sending message: %v", err)
client.Close()
delete(clients, client)
}
}
}
}
こちらではメッセージの送信処理をしています。
broadcastチャネルからメッセージを受け取り、全クライアントに送信しています。
次にclient側です。
func main() {
serverAddr := "ws://localhost:8080/ws"
conn, _, err := websocket.DefaultDialer.Dial(serverAddr, nil)
if err != nil {
log.Fatalf("Failed to connect to server: %v", err)
}
defer conn.Close()
go func() {
for {
var msg string
err := conn.ReadJSON(&msg)
if err != nil {
log.Printf("Error reading message: %v", err)
break
}
fmt.Println("Message:", msg)
}
}()
scanner := bufio.NewScanner(os.Stdin)
fmt.Println("Enter messages (type 'exit' to quit):")
for scanner.Scan() {
text := scanner.Text()
if text == "exit" {
break
}
err := conn.WriteJSON(text)
if err != nil {
log.Printf("Error sending message: %v", err)
break
}
}
}
クライアント側ではサーバー側に接続したのち、メッセージの受信/送信をしています。
ユーザー名を付与してみる。
作ってみたコードだとどちらのクライアントがメッセージを送信しているのかが分かりにくくなっています。
なのでユーザー名を入力する処理を加えてみます。
type Message struct {
Username string `json:"username"`
Text string `json:"text"`
}
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter your username: ")
username, _ := reader.ReadString('\n')
username = username[:len(username)-1]
msgで定義していた構造体を上記のように変更し、新たにユーザーを入力するメッセージを定義しました。
これで以下のような挙動になりました。
まとめ
ターミナル上でのチャットツールを作ってみましたが、以前紹介したGUIと併用すればGUI上でのチャットツールも作れると思うので、色々とできそうかと思いました。
今回作ったコードはこちらです。
GUIのブログはこちらです。
最後に
株式会社HRBrainでは新しいメンバーを募集中です。
興味がある方は下記のリンクから宜しくお願い致します。