Bot Framework と Microsoft Graph で DevOps その 22 : ダイレクトライン

今回はダイレクトラインについて。一応これでシリーズは終わりにします。まだまだネタはありますが、きりがない。。

概要

ボットコネクターは Skype、Facebook、電子メールなど複数のチャネルとの接続を提供しますが、LINE や独自アプリなどネイティブにサポートされていないアプリを接続する仕組みとして、REST 形式でアクセスできるダイレクトラインが提供されます。DevOps 観点でこのダイレクトラインが重要なのは、ファンクションテストで使っているからです。

機能

以下のことが出来ます。API 詳細はこちら

  • REST API に対する認証
  • 会話の開始と終了
  • メッセージの送受信

また接続方法は通常の HTTP 要求またはWebSocket が利用できます。

制限

WebSocket を使わない場合、ボットアプリからの通知をリアルタイムに順次受けることはできません。動作としては以下のようになります。

1. 会話を開始して、メッセージを送信。

2. ボットアプリ内ですべての処理が終わった時点でメッセージ送信処理が完了とみなされる。処理内でボットアプリからメッセージを返信していても、この時点では取得できない。

3. メッセージの受信を要求。キューされたすべてのメッセージを受信する。尚、自分が送信したメッセージも同時に受信。

差分受信

同一会話内でメッセージを送受信する場合は、Watermark と呼ばれる値をリクエストに付与することで、前回受信した以降のメッセージだけを受信可能。

ファンクションテスト

DirectLineHelper.cs でダイレクトラインの機能を使っています。会話の開始とメッセージの送受信だけを行う、非常にシンプルな仕組みです。

WebSocket での利用

ファンクションテストは通常の HTTP 要求しか使っていないため、WebSocket のサンプルを作ってみましょう。

1. ボットアプリソリューションに新しくコンソールアプリプロジェクトを追加。O365Bot.StreamClient としました。

2. NuGet より DirectLine と WebSocketSharpモジュールを追加。また System.Configuration を参照に追加。

image

image

3. App.config に DirectLine と UserId のキーを設定。

image

4. Program.cs を以下のコードで差し替え。

using Microsoft.Bot.Connector.DirectLine;
using Newtonsoft.Json;
using System;
using System.Configuration;
using System.Linq;
using System.Threading.Tasks;
using WebSocketSharp;

namespace O365Bot.StreamClient
{
    class Program
    {
        static string userId = ConfigurationManager.AppSettings["UserId"];
        static void Main(string[] args)
        {
            Run().Wait();
        }

        private static async Task Run()
        {
          
            var client = new DirectLineClient(ConfigurationManager.AppSettings["DirectLineSecret"]);
            // 会話の作成
            var conversation = await client.Conversations.StartConversationAsync();
            using (var webSocketClient = new WebSocket(conversation.StreamUrl))
            {
                // メッセージ受信時の処理
                webSocketClient.OnMessage += WebSocketClient_OnMessage;
                webSocketClient.Connect();

                while(true)
                {
                    var input = Console.ReadLine();
                    if (input == ConsoleKey.Enter.ToString())
                        break;

                    Activity activity = new Activity()
                    {
                        From = new ChannelAccount(userId, userId),
                        Text = input,
                        Locale = "en-US",
                        Type = ActivityTypes.Message
                    };

                    await client.Conversations.PostActivityAsync(conversation.ConversationId, activity);
                }
            }
        }

        private static void WebSocketClient_OnMessage(object sender, MessageEventArgs e)
        {
            if (string.IsNullOrWhiteSpace(e.Data))
                return;
            var activitySet = JsonConvert.DeserializeObject<ActivitySet>(e.Data);
        
            foreach (var activity in activitySet.Activities.Where(x=>x.From.Id != userId))
            {
                // メッセージの処理
                Console.WriteLine(activity.Text);
            }
        }
    }
}

テスト実行

アプリを実行してテキストを入力。結果を確認。

image

基本的な動作は同じように見えますが、メッセージがリアルタイムに返ってくるようになっています。

まとめ

ダイレクトラインは簡単に利用できる API ですが、応答のタイミングや WebSocket サポートなど知っておくとより便利に使えます。

今回で Bot Framework で DevOps シリーズは一旦終わりにしますが、少しでも雰囲気をつかんでもらえると嬉しいです。