Misskey: Streaming APIにおけるServer-Sent Eventsのサポート

Created on 11 Apr 2020  ·  14Comments  ·  Source: syuilo/misskey

Summary

Streaming APIにWebSocketに加え、Server-Sent Event(SSE)もサポートしていただきたいです。
Server-Sent Eventの概要としては

  • W3CによりHTML5の規格の一つとして標準化もされている
  • HTTPのコネクションを継続することでStreamingが行えるもの

です。

MastodonでもStreaming手段の一つとして、Timelineやhashtag、List、Direct Message、更新されたUser Status、の配信に利用しています。

SSEのデメリットとしては

  • 単方向通信のみのサポート
  • テキストのみでしか通信できない

というものが挙げられますが、
Streaming APIにSSEを採用することによるメリットとして、

  • WebSocketのライブラリがなく、HTTPのライブラリはあるといったプログラミング言語でのクライアント製作が容易になること
  • 著名なプログラミング言語でもクライアントの作成が簡単になる

と考えられます。

検討よろしくお願いします。

参考リンク

⚙️Server ✨Feature

Most helpful comment

@syuilo 久しくコードを触ってないのでリハビリを兼ねてやってみてもいいですか?(もしかしたら諦めるかもしれない)

All 14 comments

SSEはサーバーからのイベント送信のみであるため、そのセッションに対して設定をするようなAPIが必要になると思った

@syuilo 久しくコードを触ってないのでリハビリを兼ねてやってみてもいいですか?(もしかしたら諦めるかもしれない)

再接続が仕様に標準で含まれていて実装されているのは大きいメリットかと。

旧Edgeのサポートなんてあんまりしなくていいと思うし、MisskeyのWebSocketは今のところバイナリデータを含まないのでWebSocketから完全移行しても問題はなさそう(極端な話ですが)。

https://uhyohyo.net/javascript/13_2.html

WS の方がオーバーヘッド的に強そうだし別にどっちも共存していいとは思う。

これは1ユーザの勝手なボヤキなのですが、SSEによるStreaming APIでアンテナの新着とかが配信できると便利そうだなと思いました。

久しくコードを触ってないのでリハビリを兼ねてやってみてもいいですか?

👍 @acid-chicken

Draft #​001

ツッコミ歓迎

仮策定済

  • GET /streaming で流す

    • リクエストには次のクエリをつける

    • i クエリで認証トークンを渡す(任意)

    • events クエリで欲しいイベントの種類を指定する



      • 書式は次の通り


      • イベントを表すトークンの組み合わせ(一つ以上)によって構成される





        • トークンは , で区切られる



        • トークンは先頭から順番に解析され、後続のトークンはそれまでの指定に副作用をもたらす可能性がある



        • トークンはセクション(一つ以上)に分けられる



        • セクションの正規表現は /[\d\w]+|-[\d\w-]+/







          • 先頭が - でない場合、文字列全体をそのままセクションとしてみなす




          • 文字列には英数字と _ が使用可能 (/[\d\w]/)




          • 先頭が - の場合、後続の文字列全体を base64url エンコーディングされたセクションとしてみなす




          • パーセントエンコーディングだと二重になるし、punycode は比較的実装が乏しいので base64url にした







        • セクションは : で区切られる



        • 先頭セクションのみ空にしてもよい







          • この場合、スペシャルトークンになる




          • トークン :all は全てのイベントを表すスペシャルトークン







        • トークンが表すイベントが存在しない場合、そのトークンは無視される



        • 先頭トークン以外のトークンの先頭に ! をつけてもよい



        • この場合、トークンが指定したイベントを既存の指定から除外する



        • トークンの末尾に ! をつけてもよい



        • この場合、トークンがサポートされない場合(そのバージョンで存在しないイベントなど)にリクエストをエラーにする





      • 全体の正規表現は /^(?:(?:(?:[\d\w]+|-[\d\w-]+)|(?:(?:[\d\w]+|-[\d\w-]+)?(?::(?:[\d\w]+|-[\d\w-]+))+))!?)(?:,!?(?:(?:[\d\w]+|-[\d\w-]+)|(?:(?:[\d\w]+|-[\d\w-]+)?(?::(?:[\d\w]+|-[\d\w-]+))+))!?)*$/ になるが、このバリデーションの前に空白文字 (/\s/g) は除去される


      • HTTP GET で指定できるクエリ長の制限に達する可能性が考えられるが、それはもはや DoS みたいなものなので、回避策はとりあえず実装しない


      • ### 例





        • timeline:local: LTL 投稿イベントが流れてくる



        • timeline:home,notification: HTL 投稿イベントと全ての通知イベントが流れてくる



        • timeline,!timeline:global: GTL 以外の全てのタイムライン投稿イベントが流れてくる



        • timeline:tag:-44OQ44Kt44OQ44Kt57K-57Gz5qmf: #バキバキ精米機 タグタイムライン投稿イベントが流れてくる



        • :all: 全てのイベントが流れてくる






    • レスポンスは次のようなイベントを流す

    • data を擬似的に Data URI のようにみなし、MIME-Type 部分でイベントの種類を表現する



      • ### 例


      • data:application/vnd.misskey.sse+json;event="timeline:local",{...: LTL 投稿イベント



未策定(意見求)

  • イベント名
  • イベント ID の書式
  • イベントをどこにどこまでキャッシュしておくか(イベントの再送に必要)
  • イベントでファイルを流せるようにするかどうか(ノートの添付画像など)

特定の子サーバーにストリーミングが集中してきたらサーバーからわざとコネクションを切って再接続を促すことでよりきちんと負荷分散できそうなので、現状の WebSocket エンドポイントが抱える負荷偏重問題の代替策になりうるかもしれない。

Slackの rtm.start みたいに受け取りたいデータを与えると一時URLが発行されるとかでもいいかもしれない

あとリバースプロキシが変にレスポンスをバッファするかもしれないけどそれへの対策はどうするんだろう

nginx は X-Accel-Buffering: no で切れるはず(ただし fastcgi_pass_header "X-Accel-Buffering"; を nginx の .conf 側で予め記述しておく必要あり)。
他はあまり知らない

Slackの rtm.start みたいに受け取りたいデータを与えると一時URLが発行されるとかでもいいかもしれない

ストリームの管理が Last-Event-ID と URL で二重になってしまうので、初回接続は POST で Last-Event-ID もらってくるとかがむしろ綺麗っぽそう?

初期値として Last-Event-ID を指定できなさそう https://developer.mozilla.org/en-US/docs/Web/API/EventSource

  • A last event ID string. This must initially be the empty string.

Apart from url these are not currently exposed on the EventSource object.
— 9.2.2 The EventSource interface • HTML Living Standard

ふーむ

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tosuke picture tosuke  ·  3Comments

ibrokemypie picture ibrokemypie  ·  3Comments

ibrokemypie picture ibrokemypie  ·  3Comments

syuilo picture syuilo  ·  3Comments

tamaina picture tamaina  ·  3Comments