ハートビート機構を用いた連携VCIの存在チェック

# はじめに
本記事はVCIアドベントカレンダーの17日目の記事です。
[第一回 1 WEEK VCI ハッカソン](https://hackathon.singularity-clock.com/detail/1310436572437778433)でアイデアとして出した『パッと変わる背景』4枚目の画像ハートビート機能について実現案を記載します。

# ハートビートとは
> 外部から機器が正常に動作しているか調べ続ける死活監視の手法の一つで、監視対象の機器にあらかじめ決まった周期で短いデータを送るよう設定しておき、監視側ではこれが途切れること無く着信しているかどうかを常に確認する。一定時間着信が途絶えると、相手側に何らかの障害が生じたと判断し、管理者への警報や待機系への切り替えなど準備された対応を実行する。[^1]

# ハートビートをVCIで実現する
ハートビート機構はRoomのカラオケVCI実験で実装しています。
ハートビートは以下のように実現しています。

<details><summary>ハートビート監視側</summary><div>

```
function heartbeat()
    while true do
        for i = 1, #songList do
                songList[i]["flag"] = false
        end
        vci.message.Emit('heartbaeatSYN', "")
        sleepMs(3000)
        local tail = #songList
        for i = 1, tail do
            if songList[i] ~= nil then
                if songList[i]["flag"] == false then
                    table.remove(songList, i)
                    i = 1
                end
            end
        end

        for i = 1, 3 do
            local text = "songText"..i
            if songList[i+3*(page-1)] ~= nil then
                vci.assets._ALL_SetText(text, songList[i]["name"])
            else
                vci.assets._ALL_SetText(text, "")
            end
        end
        sleepMs(2000)
    end
end

function chinng_karaoke_onMessage(sender, name, message) 
    print(name)
    print(message)
    if vci.assets.IsMine == true then
        if name == "heartbeatACK" then
            local msg = json.parse(message)
            local name = msg.name
            local find = false
            for i = 1, #songList do
                if songList[i]["name"] == name then
                    songList[i]["flag"] = true
                    find = true
                    break
                end
            end
            if find == false then
                local tbl = {["name"] = name, ["flag"] = true, }
                table.insert(songList, tbl)
            end
        end
    end
end

if vci.assets.IsMine == true then
    vci.message.On("heartbeatACK", chinng_karaoke_onMessage)
    vci.StartCoroutine( coroutine.create( heartbeat ) )
end
```
</div></details>

<details><summary>ハートビート応答側</summary><div>
```
function chinng_karaoke_onMessage(sender, name, message) 
    print(name)
    print(message)
    if vci.assets.IsMine == true then
        if name == "heartbaeatSYN" then
            local tbl = {}
            tbl.name  = thisName
            local msg = json.serialize(tbl)
            vci.message.Emit('heartbeatACK', msg)
        end
    end
end

if vci.assets.IsMine == true then
    vci.message.On("heartbaeatSYN", chinng_karaoke_onMessage)
end
```
</div></details>

**監視側**
1．現在応答を受けてるアイテム名についてフラグを全てfalseにする
2．heartbaeatSYNのメッセージを送信する
3．3秒待機する
その間heartbeatACKのメッセージで応答を受け付けたものを、登録済の場合フラグをtrueにする
未登録のものはテーブルに追加し、フラグをtrueにする
4. 応答がなかった(フラグがfalse)情報を削除する
5. 2秒待機する

上記を1サイクルとしたコルーチンで実装しています。

**応答側**
heartbaeatSYNのメッセージを受信した場合、自身のアイテム名をheartbeatACKで返送する

# まとめ
ハートビート機構を組み込むことで複数のVCIをUIで連携した際に、削除済みのアイテムが表示され続けることで操作時に操作が実行されない、異常な状態になることを防ぐことが可能です。
今回記載した方法では、同一アイテムが存在する場合正常に動作しませんが、**VirtualCast2.0.0b VCI更新**で追加された「送り先情報」やCytanbluaの仕組みを使うことで回避可能です。

[^1]: [ハートビート](http://e-words.jp/w/%E3%83%8F%E3%83%BC%E3%83%88%E3%83%93%E3%83%BC%E3%83%88.html)