1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

BunAdvent Calendar 2023

Day 11

BunでWebSocketのデータ配信サーバーを建ててccchartにリアルタイム表示する

Last updated at Posted at 2023-11-20

Bunのページ https://bun.sh/ へ行くと、まず「高速な JavaScriptランタイム・パッケージマネージャー・バンドラ―」などと書かれており、次のようなベンチマークが目を引きます。

速いですね。WebSocket好きは黙っていられない速度です。まぁ、他のHTTPサーバーやsqlitのベンチも驚くべきものですが、今回は早速WebSocket使ってBunで書いてみました。

とりあえず説明は Wiki に任せます。こんな感じ。

Bunとは、プログラミング言語Zigを用いてゼロから構築されたJavaScriptランタイム、パッケージマネージャー、テストランナービルダーである[3]。Jarred SumnerによってNode.jsの完全互換として設計された。Node.jsやDenoはJavaScriptエンジンとしてV8を利用しているが、BunはJavaScriptCoreを採用している
バンドル、縮小化、サーバーサイドレンダリング(SvelteKit、Nuxt.js、Vite) がサポートされている。
ランタイムではForeign function interface (FFI)、SQLite3、TLS 1.3、DNS解決がサポートされている。 また、ファイル編集、HTTPサーバー、WebSocket、ハッシュ関数などの一般的なツールも提供されている[5]

BunのWebsocketドキュメントは下記にあります

Bun>Websocket

このチャートの動作サンプル

動作サンプルURL
https://ccchart.com/bun/ws-8116.html
動画

環境と準備

環境:Ubuntu 20.04.6 LTS

  • Bunインストール
  • WebSocketサーバー側を作る
  • ccchartで受信する

Bunインストール

インストールガイド
https://bun.sh/docs/installation
ここでは、Ubuntuで試しますが、上記Installationには、macOS and Linux、WindowsやDockerの各ケースが書かれています。

ディレクトリ構成
.
├─server/
│   └─ws-8116.js
├─html/
│   ├─ws-8116.html
│   └─js/ccchart.js
≈
//TSL/wss用のパス
(/etc/letsencrypt/live/example.com/privkey.pem など)
├─/<PathTo>/privkey.pem
└─/<PathTo>/fullchain.pem
ファイル解凍用のunzipも無ければ用意しておく
sudo apt install unzip
Bunをインストールする
curl -fsSL https://bun.sh/install | bash

WebSocketサーバー側を作る

WebSocketは、常時接続後chatなどのようにメッセージのやり取りをするものが多いですが、ここでは、コネクションが成立した「open」後にブロードキャスト関数broadCastを起動して、データを配信するだけの放送型の使い方をしています。

WebSocketサーバー(データ配信用) ws-8116.js

const server = Bun.serve({
  hostname:'<IPやドメイン名>',
  port: 8116, //ポートは開いて無ければ開けておく
  fetch(req, server) {
    // upgrade the request to a WebSocket
    console.log('upgrade')
    if (server.upgrade(req)) {
      return; // do not return a Response
    }
    return new Response("Upgrade failed :(", { status: 500 });
  },
  websocket: {
    open(ws) {
      // ブロードキャスト
      broadCast(ws)
    },
    message(ws, message) {},
    close(ws) {},
  },
  tls: {
    key: Bun.file('/<PathTo>/privkey.pem'),
    cert: Bun.file('/<PathTo>/fullchain.pem'),
  }
});

// info 
console.log(`Listening on ${server.hostname}:${server.port}`);

// 全クライアントへ200ms毎にブロードキャストする
function broadCast(ws){
  const INTERVAL=200
  let tid = setInterval (function(){
    let dataAry = mkData();
    ws.send(JSON.stringify(dataAry));
  }, INTERVAL);
}

// データ作成
// チャート用の時分秒と2つのランダムデータをつくる
function mkData(){
  const data = [
      ["年度"],
      ["s2"],
      ["s3"]
  ];
  let now = new Date();
  let H = now.getHours();
  let M = now.getMinutes();
  let S = now.getSeconds();
  H = (H < 10)?'0'+H:H;
  M = (M < 10)?'0'+M:M;
  S = (S < 10)?'0'+S:S;

  data[0]=H +':' + M +':' + S;
  data[1]=18 + Math.floor(Math.random(10) * 75 );
  data[2]=32 + Math.floor(Math.random(10) * 18);

  return data;
}

サーバーを起動する

sudo bun run /server/ws-8116.js

bunの場所がわからなければwhich bunなどで探してね

ccchartで受信する

ここでは、WebSocketサーバーから200ms毎に配信されてくるデータをccchartで受信し、チャート描画しています。もちろん、他のチャートライブラリでの描画も可能です。

ccchartは、私が昔作ったチャートライブラリでWebSocketの受信が手軽にできます。
https://ccchart.com/

HTML

<!DOCTYPE html>
<html lang="ja">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<head>
<title>ccchart bun test</title>
</head>
<body>

<!-- ccchart -->
<!--script src="https://ccchart.com/js/ccchart.js" charset="utf-8"></script-->
<script src="./js/ccchart.js" charset="utf-8"></script>

<div class="chart">
    <canvas 
        id="hoge1" 
        class="-ccchart" 
        title="bg: '#eee'" 

        style="width:100%;height:100%;display: block; background-color: rgb(238, 238, 238);">
    </canvas>
</div>

<script>

/* =============================================
 * チャート設定
 */ 
let chartCfg1 = {
    "config": {
        "title" : "BunでWebSocket",
        "subTitle" : "BunでWebSocketサーバーを作ってみた",
        "type": "line",
        "minY": 0,
        "maxY": 100,
        "lineWidth": 1,
        "xScaleSkip": 5,
        "colorSet" : ["red","orange"],
        "useMarker": "maru",
        "xLines": [
          {"val":66,"color":"rgba(0,0,0,0.7)"}
        ],
         "bg": "#fff",
         "textColors": {
            "title":"#777",
            "subTitle":"#777",
            "x":"#999",
            "y":"#999",
            "hanrei":"#777",
            "unit":"#777",
            "memo":"#666"
        },
        "shadows": {
            "hanrei" : ['#aaa', 5, 5, 5],
            "xline": ['#888', 7, 7, 5],
            "line": ['#666', 5, 5, 5],
            "bar": ['#bbb', 5, 5, 5],
            "stacked": ['#bbb', 5, -5, 5],
            "stackedarea": ['#666', 5, 5, 5],
            "bezi": ['#666', 5, 5, 5],
            "bezi2": ['#666', 5, 5, 5]
        },
        "markerWidth" : 12,
        "lineWidth" : 2,
        "bg": "#eee"
    },
    "data": [
        ["時間"],
        ["データ1"],
        ["データ2"]
    ]
};

ccchart
  .init('hoge1', chartCfg1)
  .ws('wss://ccchart.com:8116') //←ここは御自身のアドレス:ポート
  .on('message', ccchart.wscase.oneColAtATime);
        //oneColAtATimeは、WebSocketの受信パターン関数
        // 一度に1列ずつ [["2013"],[435],[600]] といった配列で届く場合用

</script>
</body>
</html>

自己紹介

ここのCTOやってます
霊園ガイドサイト
https://reien.top/

Github https://github.com/toshirot
Qiita https://qiita.com/toshirot
ccchat https://ccchart.com/ javascript チャートライブラリ
霊園ガイド https://reien.top/ 霊園マッチングサイト
国会図書館 高橋著作 https://ndlonline.ndl.go.jp/#!/search?searchCode=SIMPLE&lang=jp&keyword=%E9%AB%98%E6%A9%8B%E7%99%BB%E5%8F%B2%E6%9C%97

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?