Transmit
Transmitは、AdonisJS向けに作られたネイティブな意見のあるServer-Sent-Event(SSE)モジュールです。通知、ライブチャットメッセージ、またはその他のリアルタイムデータなど、クライアントへのリアルタイムの更新を送信するためのシンプルで効率的な方法です。
データの送信はサーバーからクライアントへのみ行われます。クライアントからサーバーへの通信にはフォームまたはフェッチリクエストを使用する必要があります。
インストール
次のコマンドを使用してパッケージをインストールおよび設定します:
node ace add @adonisjs/transmit
-
検出されたパッケージマネージャを使用して
@adonisjs/transmit
パッケージをインストールします。 -
adonisrc.ts
ファイル内で@adonisjs/transmit/transmit_provider
サービスプロバイダを登録します。 -
config
ディレクトリ内に新しいtransmit.ts
ファイルを作成します。
また、クライアント側でイベントを受信するためにTransmitクライアントパッケージもインストールする必要があります。
npm install @adonisjs/transmit-client
設定
Transmitパッケージの設定はconfig/transmit.ts
ファイルに保存されます。
参照:Config stub
import { defineConfig } from '@adonisjs/transmit'
export default defineConfig({
pingInterval: false,
transport: null,
})
-
pingInterval
-
クライアントにpingメッセージを送信するために使用される間隔です。値はミリ秒または文字列の
Duration
形式(例:10s
)で指定します。pingメッセージを無効にするにはfalse
に設定します。 -
transport
-
Transmitは複数のサーバーやインスタンス間でイベントを同期できます。この機能を有効にするには、必要なトランスポートレイヤー(現在は
redis
のみサポート)を参照するように設定します。同期を無効にするにはnull
に設定します。import env from '#start/env'import { defineConfig } from '@adonisjs/transmit'import { redis } from '@adonisjs/transmit/transports'export default defineConfig({transport: {driver: redis({host: env.get('REDIS_HOST'),port: env.get('REDIS_PORT'),password: env.get('REDIS_PASSWORD'),keyPrefix: 'transmit',})}})redis
トランスポートを使用する場合は、ioredis
がインストールされていることを確認してください。
Register Routes
クライアントがサーバーに接続できるようにするためには、transmitルートを登録する必要があります。ルートは手動で登録されます。
import transmit from '@adonisjs/transmit/services/main'
transmit.registerRoutes()
各ルートを手動でコントローラーにバインドして手動で登録することもできます。
const EventStreamController = () => import('@adonisjs/transmit/controllers/event_stream_controller')
const SubscribeController = () => import('@adonisjs/transmit/controllers/subscribe_controller')
const UnsubscribeController = () => import('@adonisjs/transmit/controllers/unsubscribe_controller')
router.get('/__transmit/events', [EventStreamController])
router.post('/__transmit/subscribe', [SubscribeController])
router.post('/__transmit/unsubscribe', [UnsubscribeController])
ルート定義を変更して、たとえばRate Limiter
や認証ミドルウェアを使用して一部のtransmitルートの乱用を防ぎたい場合は、ルート定義を変更するか、transmit.registerRoutes
メソッドにコールバックを渡すことができます。
import transmit from '@adonisjs/transmit/services/main'
transmit.registerRoutes((route) => {
// クライアントを登録するために認証されていることを確認します
if (route.getPattern() === '__transmit/events') {
route.middleware(middleware.auth())
return
}
// 他のtransmitルートにスロットルミドルウェアを追加できます
route.use(throttle)
})
チャンネル
チャンネルはイベントをグループ化するために使用されます。たとえば、通知用のチャンネル、チャットメッセージ用の別のチャンネルなどがあります。クライアントがチャンネルに登録すると、チャンネルが動的に作成されます。
チャンネル名
チャンネル名はチャンネルを識別するために使用されます。大文字と小文字が区別され、文字列である必要があります。チャンネル名には/
以外の特殊文字やスペースは使用できません。以下は有効なチャンネル名の例です:
import transmit from '@adonisjs/transmit/services/main'
transmit.broadcast('global', { message: 'Hello' })
transmit.broadcast('chats/1/messages', { message: 'Hello' })
transmit.broadcast('users/1', { message: 'Hello' })
チャンネル名はAdonisJSのルートと同じ構文を使用しますが、それらとは関係ありません。同じキーでHTTPルートとチャンネルを自由に定義できます。
チャンネルの認証
authorize
メソッドを使用して、チャンネルへの接続を承認または拒否できます。このメソッドはチャンネル名とHttpContext
を受け取り、真偽値を返す必要があります。
import transmit from '@adonisjs/transmit/services/main'
import Chat from '#models/chat'
import type { HttpContext } from '@adonisjs/core/http'
transmit.authorize<{ id: string }>('users/:id', (ctx: HttpContext, { id }) => {
return ctx.auth.user?.id === +id
})
transmit.authorize<{ id: string }>('chats/:id/messages', async (ctx: HttpContext, { id }) => {
const chat = await Chat.findOrFail(+id)
return ctx.bouncer.allows('accessChat', chat)
})
イベントのブロードキャスト
broadcast
メソッドを使用して、チャンネルにイベントをブロードキャストできます。このメソッドはチャンネル名と送信するデータを受け取ります。
import transmit from '@adonisjs/transmit/services/main'
transmit.broadcast('global', { message: 'Hello' })
また、broadcastExcept
メソッドを使用して、特定のUIDを除くすべてのチャンネルにイベントをブロードキャストすることもできます。このメソッドはチャンネル名、送信するデータ、および無視するUIDを受け取ります。
transmit.broadcastExcept('global', { message: 'Hello' }, 'uid-of-sender')
複数のサーバーやインスタンス間での同期
デフォルトでは、イベントのブロードキャストはHTTPリクエストのコンテキスト内でのみ動作します。ただし、設定でtransport
を登録することで、バックグラウンドからイベントをブロードキャストすることもできます。
トランスポートレイヤーは、複数のサーバーやインスタンス間でイベントを同期する責任を持ちます。これは、ブロードキャストされたイベント、サブスクリプション、およびアンサブスクリプションなどのイベントを、接続されているすべてのサーバーやインスタンスに対してMessage Bus
を使用してブロードキャストすることによって機能します。
クライアント接続に対して責任を持つサーバーまたはインスタンスは、イベントを受信し、クライアントにブロードキャストします。
Transmitクライアント
@adonisjs/transmit-client
パッケージを使用して、クライアント側でイベントを受信できます。このパッケージはTransmit
クラスを提供します。クライアントはデフォルトでEventSource
APIを使用してサーバーに接続します。
import { Transmit } from '@adonisjs/transmit-client'
export const transmit = new Transmit({
baseUrl: window.location.origin
})
Transmit
クラスのインスタンスは1つだけ作成し、アプリケーション全体で再利用するべきです。
Transmitインスタンスの設定
Transmit
クラスは、次のプロパティを持つオブジェクトを受け入れます:
-
baseUrl
-
サーバーのベースURLです。URLにはプロトコル(httpまたはhttps)とドメイン名を含める必要があります。
-
uidGenerator
-
クライアントのための一意の識別子を生成する関数です。関数は文字列を返す必要があります。デフォルトでは
crypto.randomUUID
です。 -
eventSourceFactory
-
新しい
EventSource
インスタンスを作成する関数です。デフォルトではWebAPIのEventSource
を使用します。EventSource
APIをサポートしていないNode.js
、React Native
、または他の環境でクライアントを使用する場合は、カスタムの実装を提供する必要があります。 -
eventTargetFactory
-
新しい
EventTarget
インスタンスを作成する関数です。デフォルトではWebAPIのEventTarget
を使用します。EventTarget
APIをサポートしていないNode.js
、React Native
、または他の環境でクライアントを使用する場合は、カスタムの実装を提供する必要があります。EventTarget
APIを無効にするにはnull
を返します。 -
httpClientFactory
-
新しい
HttpClient
インスタンスを作成する関数です。主にテスト目的で使用されます。 -
beforeSubscribe
-
チャンネルに登録する前に呼び出される関数です。チャンネル名とサーバーに送信される
Request
オブジェクトが渡されます。この関数を使用してカスタムヘッダーを追加したり、リクエストオブジェクトを変更したりするために使用します。 -
beforeUnsubscribe
-
チャンネルから登録解除する前に呼び出される関数です。チャンネル名とサーバーに送信される
Request
オブジェクトが渡されます。この関数を使用してカスタムヘッダーを追加したり、リクエストオブジェクトを変更したりするために使用します。 -
maxReconnectAttempts
-
再接続試行の最大回数です。デフォルトは
5
です。 -
onReconnectAttempt
-
各再接続試行の前に呼び出される関数で、これまでに行われた試行回数が渡されます。カスタムロジックを追加するためにこの関数を使用します。
-
onReconnectFailed
-
再接続試行が失敗したときに呼び出される関数です。カスタムロジックを追加するためにこの関数を使用します。
-
onSubscribeFailed
-
サブスクリプションが失敗したときに呼び出される関数です。
Response
オブジェクトが渡されます。カスタムロジックを追加するためにこの関数を使用します。 -
onSubscription
-
サブスクリプションが成功したときに呼び出される関数です。チャンネル名が渡されます。カスタムロジックを追加するためにこの関数を使用します。
-
onUnsubscription
-
アンサブスクリプションが成功したときに呼び出される関数です。チャンネル名が渡されます。カスタムロジックを追加するためにこの関数を使用します。
サブスクリプションの作成
subscription
メソッドを使用して、チャンネルに対するサブスクリプションを作成できます。このメソッドはチャンネル名を受け取ります。
const subscription = transmit.subscription('chats/1/messages')
await subscription.create()
create
メソッドはサブスクリプションをサーバーに登録します。await
またはvoid
できるプロミスを返します。
create
メソッドを呼び出さない場合、サブスクリプションはサーバーに登録されず、イベントを受信しません。
イベントのリスニング
onMessage
メソッドを使用して、サブスクリプションでイベントをリスンできます。このメソッドはコールバック関数を受け取ります。異なるコールバックを追加するために、onMessage
メソッドを複数回呼び出すことができます。
subscription.onMessage((data) => {
console.log(data)
})
また、onMessageOnce
メソッドを使用して、コールバック関数を受け取ることで、チャンネルを一度だけリスンすることもできます。
subscription.onMessageOnce(() => {
console.log('一度だけ呼び出されます')
})
イベントのリスニングを停止する
onMessage
およびonMessageOnce
メソッドは、特定のコールバックのリスニングを停止するために呼び出すことができる関数を返します。
const stopListening = subscription.onMessage((data) => {
console.log(data)
})
// リスニングを停止する
stopListening()
サブスクリプションの削除
delete
メソッドを使用して、サブスクリプションを削除できます。このメソッドはawait
またはvoid
できるプロミスを返します。このメソッドはサーバー上でサブスクリプションの登録を解除します。
await subscription.delete()