C++/Stimulusでのリアルタイムチャットを作った話

はじめに

以前、C++/StimulusでのWeb開発記事を書いた

 

gamelinks007.hatenablog.com

 

あれから、C++/Stimulus/FireBaseを使ったリアルタイムチャットアプリを作ったりしてた

 

github.com

 

ただ、この場合だとFireBaseに依存した実装となっているので、FireBaseが使えなくなる状況が発生すると活用が難しい

 

そこで、C++/Stimulusだけでリアルタイムチャットアプリが作れないか試してみたのが今回の話です

 

作ったもの

以下は実際に作ったものです!

 

github.com

 

やったこと

まず、C++側でチャットのメッセージを受け取ったり、表示するAPIっぽいものを作成します

 

svr.Get("/messages", [&](const httplib::Request& req, httplib::Response& res) {

std::ostringstream chat;

for(auto&& c : chats)
chat << "<p>" << c.c_str() << "</p>";

res.set_content(chat.str(), "text/plain");
});

svr.Post("/messages", [&](const httplib::Request& req, httplib::Response& res) {

chats.emplace_back(std::move(req.body));

res.set_content(std::to_string(req.get_param_value_count("chat")), "text/html");
});
 

 

肝としては、/messagesにGETリクエストが送られると最新のチャット内容すべてをtext/plainとして吐き出させているところですね

 

次に、フロントを以下のように書いていきます

 

<!DOCTYPE html>
<html>
<body>
<div data-controller="chat" data-chat-url="/messages" data-chat-refresh-interval="10">
<div data-target="chat.response"></div>
<div data-target="chat.chats"></div>
<input data-target="chat.content">
<button data-action="click->chat#chat">add</button>
</div>

<script src="./index.js" type="text/javascript"></script>
</body>
</html>

 

StimulusではJavaScript側に渡したいデータなどをdata-chat-urやdata-chat-refresh-intervallのように定義することで、以下のように渡すことができます

 

this.data.get("refreshInterval")
this.data.get("url")

 

 その為、各ページごとにaxiosやfetchでリクエスト先をガリガリと書く必要はなく、以下のようにシンプルに書くことができます

chat() {
  axios.post(this.data.get("url"), `${this.contentTarget.value}`).then*1 {
this.startRefreshing()
}
}

load() {
axios.get(this.data.get("url")).then*2
}

stopRefreshing() {
if (this.refreshTimer) {
clearInterval(this.refreshTimer)
}
}
}

肝としてはdata-chat-refresh-intervalで渡している時間が経過すると、/messagesにチャット内容をGETするように処理しているところですね

 

これで然もリアルタイムでチャットが更新されているかのように動きます!

 

おわりに

今後は、もうちょっと頑張って少し小さめな掲示板アプリでもC++/Stimulusで作ってみたいと思うねー

 

参考

stimulusjs.org

 

github.com

*1:res) => {

   console.log(res);
  }, (error) => {
console.log(error);
})
} 

 

これを利用して、以下のようにchat_controller.jsを書いていきます

import { Controller } from "stimulus";
import axios from "axios";

export default class extends Controller {
static get targets() {
return ["chats", "content", "response"];
}

connect() {
this.load();

if (this.data.has("refreshInterval"

*2:res) => {

this.responseTarget.innerHTML = res.data;
}, (error) => {
console.log(error);
})
}

chat() {
axios.post(this.data.get("url"), `${this.contentTarget.value}`).then((res) => {
console.log(res);
}, (error) => {
console.log(error);
})
}

startRefreshing() {
this.refreshTimer = setInterval(() => {
this.load()
}, this.data.get("refreshInterval"