-
Notifications
You must be signed in to change notification settings - Fork 1
FCE-2708 Adds docs for data channels #219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Qizot
wants to merge
1
commit into
main
Choose a base branch
from
data-channels
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+196
−5
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Submodule fishjam-server
updated
from 65b3b4 to 4d7c55
Submodule protos
updated
14 files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,190 @@ | ||
| --- | ||
| type: explanation | ||
| sidebar_position: 7 | ||
| --- | ||
|
|
||
| import Tabs from "@theme/Tabs"; | ||
| import TabItem from "@theme/TabItem"; | ||
|
|
||
| # Data Channels | ||
|
|
||
| Data channels allow you to send and receive arbitrary binary data between peers in a room. This is useful for implementing features like text chat, file sharing, game state synchronization, or real-time cursor positions. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| Before using data channels, you must be [connected to a room](./connecting). Data channels only work after you have successfully joined a room. | ||
|
|
||
| ## Channel Types | ||
|
|
||
| The SDK provides two types of data channels, each optimized for different use cases: | ||
|
|
||
| ### Reliable Channel | ||
|
|
||
| - **Ordered delivery**: Messages arrive in the order they were sent | ||
| - **Guaranteed delivery**: All messages will be delivered, with automatic retransmission if needed | ||
| - **Use cases**: Chat messages, file transfers, commands, or any data that must not be lost | ||
|
|
||
| ### Lossy Channel | ||
|
|
||
| - **Unordered delivery**: Messages may arrive out of order | ||
| - **No retransmission**: Messages may be dropped if the network is congested | ||
| - **Lower latency**: Faster delivery since there's no waiting for retransmissions | ||
| - **Use cases**: Real-time cursor positions, game state updates, live sensor data, or any data where the latest value matters more than every value | ||
|
|
||
| ## Broadcast Communication | ||
|
|
||
| Data channels work in a **broadcast fashion** - when you publish data, it is sent to all other peers in the room. Additionally: | ||
|
|
||
| - Messages sent on the **reliable channel** are only received by peers subscribed to the **reliable channel** | ||
| - Messages sent on the **lossy channel** are only received by peers subscribed to the **lossy channel** | ||
|
|
||
| This separation allows you to use both channels simultaneously for different purposes without interference. | ||
|
|
||
| ## Using Data Channels | ||
|
|
||
| Use the [`useDataChannel`](../../api/web/functions/useDataChannel) hook to work with data channels. The typical flow is: | ||
|
|
||
| 1. Initialize the data channel after connecting to a room | ||
| 2. Subscribe to incoming messages | ||
| 3. Publish messages to other peers | ||
|
|
||
| ### Example: Simple Chat Messages | ||
|
|
||
| <Tabs groupId="platform"> | ||
| <TabItem value="web" label="React (Web)"> | ||
|
|
||
| ```tsx | ||
| import { useConnection, useDataChannel } from "@fishjam-cloud/react-client"; | ||
| import { useCallback, useEffect, useState } from "react"; | ||
|
|
||
| export function useChat() { | ||
| const { peerStatus } = useConnection(); | ||
| const { | ||
| initializeDataChannel, | ||
| publishData, | ||
| subscribeData, | ||
| dataChannelReady, | ||
| } = useDataChannel(); | ||
|
|
||
| const [messages, setMessages] = useState<string[]>([]); | ||
|
|
||
| // Step 1: Initialize data channel when connected | ||
| useEffect(() => { | ||
| if (peerStatus === "connected") { | ||
| initializeDataChannel(); | ||
| } | ||
| }, [peerStatus, initializeDataChannel]); | ||
|
|
||
| // Step 2: Subscribe to incoming messages | ||
| useEffect(() => { | ||
| if (!dataChannelReady) return; | ||
|
|
||
| const unsubscribe = subscribeData( | ||
| (data: Uint8Array) => { | ||
| const message = new TextDecoder().decode(data); | ||
| setMessages((prev) => [...prev, message]); | ||
| }, | ||
| { reliable: true }, | ||
| ); | ||
|
|
||
| return unsubscribe; | ||
| }, [subscribeData, dataChannelReady]); | ||
|
|
||
| // Step 3: Publish messages | ||
| const sendMessage = useCallback( | ||
| (text: string) => { | ||
| if (!dataChannelReady) return; | ||
|
|
||
| const encoded = new TextEncoder().encode(text); | ||
| publishData(encoded, { reliable: true }); | ||
| }, | ||
| [publishData, dataChannelReady], | ||
| ); | ||
|
|
||
| return { messages, sendMessage, ready: dataChannelReady }; | ||
| } | ||
| ``` | ||
|
|
||
| </TabItem> | ||
| <TabItem value="mobile" label="React Native (Mobile)" disabled> | ||
|
|
||
| Mobile SDK support for data channels will be available in a future release. | ||
|
|
||
| </TabItem> | ||
| </Tabs> | ||
|
|
||
| ### Example: Using the Lossy Channel | ||
|
|
||
| For real-time data where low latency is more important than guaranteed delivery: | ||
|
|
||
| <Tabs groupId="platform"> | ||
| <TabItem value="web" label="React (Web)"> | ||
|
|
||
| ```tsx | ||
| import { useConnection, useDataChannel } from "@fishjam-cloud/react-client"; | ||
| import { useCallback, useEffect, useState } from "react"; | ||
|
|
||
| interface CursorPosition { | ||
| peerId: string; | ||
| x: number; | ||
| y: number; | ||
| } | ||
|
|
||
| export function useCursorSharing(peerId: string) { | ||
| const { peerStatus } = useConnection(); | ||
| const { | ||
| initializeDataChannel, | ||
| publishData, | ||
| subscribeData, | ||
| dataChannelReady, | ||
| } = useDataChannel(); | ||
|
|
||
| const [cursors, setCursors] = useState<Map<string, CursorPosition>>( | ||
| new Map(), | ||
| ); | ||
|
|
||
| useEffect(() => { | ||
| if (peerStatus === "connected") { | ||
| initializeDataChannel(); | ||
| } | ||
| }, [peerStatus, initializeDataChannel]); | ||
|
|
||
| useEffect(() => { | ||
| if (!dataChannelReady) return; | ||
|
|
||
| const unsubscribe = subscribeData( | ||
| (data: Uint8Array) => { | ||
| const position: CursorPosition = JSON.parse( | ||
| new TextDecoder().decode(data), | ||
| ); | ||
| setCursors((prev) => new Map(prev).set(position.peerId, position)); | ||
| }, | ||
| { reliable: false }, // Lossy channel for low latency | ||
| ); | ||
|
|
||
| return unsubscribe; | ||
| }, [subscribeData, dataChannelReady]); | ||
|
|
||
| const updateCursor = useCallback( | ||
| (x: number, y: number) => { | ||
| if (!dataChannelReady) return; | ||
|
|
||
| const encoded = new TextEncoder().encode( | ||
| JSON.stringify({ peerId, x, y }), | ||
| ); | ||
| publishData(encoded, { reliable: false }); | ||
| }, | ||
| [publishData, dataChannelReady, peerId], | ||
| ); | ||
|
|
||
| return { cursors, updateCursor, ready: dataChannelReady }; | ||
| } | ||
| ``` | ||
|
|
||
| </TabItem> | ||
| <TabItem value="mobile" label="React Native (Mobile)" disabled> | ||
|
|
||
| Mobile SDK support for data channels will be available in a future release. | ||
|
|
||
| </TabItem> | ||
| </Tabs> | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Submodule js-server-sdk
updated
9 files
| +1 −1 | .github/workflows/release.yaml | |
| +1 −1 | .github/workflows/static.yaml | |
| +16 −0 | .husky/pre-commit | |
| +5 −0 | examples/room-manager/package.json | |
| +8 −2 | package.json | |
| +5 −0 | packages/js-server-sdk/package.json | |
| +26 −1 | packages/js-server-sdk/src/client.ts | |
| +1 −0 | packages/js-server-sdk/src/index.ts | |
| +232 −5 | yarn.lock |
Submodule python-server-sdk
updated
6 files
| +13 −0 | Caddyfile | |
| +44 −16 | docker-compose-test.yaml | |
| +6 −1 | fishjam/api/_client.py | |
| +2 −2 | tests/agent/test_agent.py | |
| +2 −2 | tests/test_notifier.py | |
| +43 −8 | tests/test_room_api.py |
Submodule web-client-sdk
updated
61 files
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: How about moving this section to "how-to/features" as a "text chat" article? Both articles should link to each other like: "see how to build a text-chat using data channel" and "we will use data channels to send messages, check out the explanation to learn more"