Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/theforestvn88/p2p_streams_channel

Allow to setup one-to-many P2P stream connections (WebRTC) between clients through Rails server (ActionCable) as the signaling server.
https://github.com/theforestvn88/p2p_streams_channel

p2p rails webrtc

Last synced: 5 days ago
JSON representation

Allow to setup one-to-many P2P stream connections (WebRTC) between clients through Rails server (ActionCable) as the signaling server.

Awesome Lists containing this project

README

        

# P2pStreamsChannel

Allow to setup one-to-many P2P stream connections ([WebRTC](https://webrtc.org/)) between clients through Rails server (ActionCable) as the signaling server.

## Work Flow

```
===================================
Connect to Signaling Server (Rails)
===================================

host-user -------------------------------------> Rails server
host-user <-----views/chat_room----------------- Rails server
(session: chat_room, peer_id: host_user)
host-user ---turbo-connect-stream--------------> Rails server/ActionCable

client-user -----------------------------------> Rails server
client-user <-----views/chat_room--------------- Rails server
(session: chat_room, peer_id: client_user)
client-user ---turbo-connect-stream------------> Rails server/ActionCable

...
other clients
...

===========
Negotiation
===========

host-user ------SessionReady--> Rails Server --> client-user
client-user ----SessionReady--> Rails Server --> host-user
host-user --setupRTCPeerConnection --+
<-----------------------------+

host-user ------SdpOffer -----> Rails Server --> client-user
client-user --setupRTCPeerConnection --+
<------------------------------+

client-user ----SdpAnswer ----> Rails Server --> host-user

iceServers --ice-candidate----> host-user ----> client-user
iceServers --ice-candidate----> client-user --> host-user

=========
Connected
=========

After a client-user connected to the host-user, it'll be disconnected to the signaling server (in order to save memory).
Only the host-user keep connect to Rails server.
In case you want keep client connection, you could set params `keepCableConnection: true` to the p2p-frame.

client-user1 ----X disconnect from -----> Rails server Action cable
client-user2 ----X disconnect from -----> Rails server Action cable
...
host-user <-------keep connect to ------> Rails server Action cable

This is one-to-many p2p connections:
client-user1 --- send message 'hi' ---> host-user
host-user --- send message {user1: 'hi'} to --> others

============
Disconnected
============

client-user1 ---X disconnect ---> host-user
host-user ---> send client-user1 status ---> others

client-user1 ----reload --------> Rails server
host-user <--- start re-negotiating through Rails server ----> client-user1

host-user ---X disconnect ---> Rails server
all client-users will be disconnected
the first client-user re-connect to Rails server will become the new host
and start work-flow again

```

## Installation

```ruby
$ gem "p2p_streams_channel"
$ bundle isntall
$ rails g p2p_streams_channel:install
```

## Usage

Render a p2p-frame-tag
```ruby
# views/chat_rooms/_chat_room.html.erb
<%= p2p_frame_tag(
session_id: dom_id(chat_room),
peer_id: dom_id(current_user),
expires_in: 1.hour,
# config: {
# ice_servers: [
# { urls: ["stun:stun.l.google.com:19302", "stun:stun1.l.google.com:19302", "stun:stun2.l.google.com:19302"] },
# ],
# heartbeat: {
# interval_mls: 100,
# idle_timeout_mls: 200
# },
# keepCableConnection: false
# }
) do %>


# chat room views

<% end %>
```

Create a Stimulus P2pController in which you will receive other p2p-connections status, data and send back your data to others.
```ruby
$ rails g p2p_streams_channel:controller chat
# it will create js file `app/javascript/controllers/chat_controller.js`
```

```js
// app/javascript/controllers/chat_controller.js
import { P2pController } from "p2p"
export default class extends P2pController {
//
// p2p callbacks
//
p2pNegotiating() {
// your peer start to negotiate with the host through ActionCable
console.log("NEGOTIATING ...")
this.showConnecting()
}

p2pConnecting() {
// your peer is connecting directly with the host peer
console.log("CONNECTING ...")
}

p2pConnected() {
// your peer's connected to the host peer
// from now you could start send message to the other through the host peer
console.log("CONNECTED ...")
this.hideConnecting()
this.showChatBox()
}

p2pDisconnected() {
// your peer's disconnected from the host peer
this.showConnecting()
}

p2pClosed() {}

p2pError() {}

// receiving message from the other through the host peer
p2pReceivedMessage(message) {
switch(message["type"]) {
case "Data":
// message["data"]: the text message
const chatLine = document.createElement("div")
chatLine.innerText = `${message["senderId"]}: ${message["data"]}`
this.chatBoxTarget.append(chatLine)
break
case "Data.Connection.State":
// message["data"]: the current connection state of other peers
for (let [peer, state] of Object.entries(message["data"])) {
this.updatePeerState(peer, state)
}
break
default:
break
}
}

//
// send message to the others through the host peer:
// for example:
// send-button in message box will trigger this action
send() {
this.p2pSendMessage(this.messageBoxTarget.value)
this.messageBoxTarget.value = ""
}

// others:
// this.iamHost: your peer is the host or not
// this.peerId: your peer id
// this.hostPeerId: the host peer id
//
}
```

### Session Store

Session Store will cache p2p session (with `session_id` key you provide in p2p_frame_tag),
this session contains peers infomation, especially the current host peer which will automatically negotiate with the new peers or re-connect peers.

`Rails.cache` is the default store.
You could implement store by yourself, make sure your store can `fetch`, `write`, and `read`.
Then set up in initializer:
```ruby
# config/initializers/p2p_streams_channel.rb
P2pStreamsChannel.config do |config|
config.store = YourStore.new
end
```

## Development

run test:
```ruby
$ rake spec
```

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/p2p_streams_channel.