WIP: Start integrating with LiveKit when creating/joining rooms
This commit is contained in:
parent
75c339851f
commit
c9225bb87c
9 changed files with 120 additions and 24 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1100,6 +1100,7 @@ dependencies = [
|
||||||
"language",
|
"language",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"lipsum",
|
"lipsum",
|
||||||
|
"live_kit_server",
|
||||||
"log",
|
"log",
|
||||||
"lsp",
|
"lsp",
|
||||||
"nanoid",
|
"nanoid",
|
||||||
|
|
|
@ -94,7 +94,8 @@ impl Room {
|
||||||
) -> Task<Result<ModelHandle<Self>>> {
|
) -> Task<Result<ModelHandle<Self>>> {
|
||||||
cx.spawn(|mut cx| async move {
|
cx.spawn(|mut cx| async move {
|
||||||
let response = client.request(proto::CreateRoom {}).await?;
|
let response = client.request(proto::CreateRoom {}).await?;
|
||||||
let room = cx.add_model(|cx| Self::new(response.id, client, user_store, cx));
|
let room_proto = response.room.ok_or_else(|| anyhow!("invalid room"))?;
|
||||||
|
let room = cx.add_model(|cx| Self::new(room_proto.id, client, user_store, cx));
|
||||||
|
|
||||||
let initial_project_id = if let Some(initial_project) = initial_project {
|
let initial_project_id = if let Some(initial_project) = initial_project {
|
||||||
let initial_project_id = room
|
let initial_project_id = room
|
||||||
|
|
|
@ -14,8 +14,10 @@ required-features = ["seed-support"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
collections = { path = "../collections" }
|
collections = { path = "../collections" }
|
||||||
|
live_kit_server = { path = "../live_kit_server" }
|
||||||
rpc = { path = "../rpc" }
|
rpc = { path = "../rpc" }
|
||||||
util = { path = "../util" }
|
util = { path = "../util" }
|
||||||
|
|
||||||
anyhow = "1.0.40"
|
anyhow = "1.0.40"
|
||||||
async-trait = "0.1.50"
|
async-trait = "0.1.50"
|
||||||
async-tungstenite = "0.16"
|
async-tungstenite = "0.16"
|
||||||
|
|
|
@ -6321,6 +6321,7 @@ impl TestServer {
|
||||||
async fn build_app_state(test_db: &TestDb) -> Arc<AppState> {
|
async fn build_app_state(test_db: &TestDb) -> Arc<AppState> {
|
||||||
Arc::new(AppState {
|
Arc::new(AppState {
|
||||||
db: test_db.db().clone(),
|
db: test_db.db().clone(),
|
||||||
|
live_kit_client: None,
|
||||||
api_token: Default::default(),
|
api_token: Default::default(),
|
||||||
invite_link_prefix: Default::default(),
|
invite_link_prefix: Default::default(),
|
||||||
})
|
})
|
||||||
|
|
|
@ -30,6 +30,9 @@ pub struct Config {
|
||||||
pub invite_link_prefix: String,
|
pub invite_link_prefix: String,
|
||||||
pub honeycomb_api_key: Option<String>,
|
pub honeycomb_api_key: Option<String>,
|
||||||
pub honeycomb_dataset: Option<String>,
|
pub honeycomb_dataset: Option<String>,
|
||||||
|
pub live_kit_server: Option<String>,
|
||||||
|
pub live_kit_key: Option<String>,
|
||||||
|
pub live_kit_secret: Option<String>,
|
||||||
pub rust_log: Option<String>,
|
pub rust_log: Option<String>,
|
||||||
pub log_json: Option<bool>,
|
pub log_json: Option<bool>,
|
||||||
}
|
}
|
||||||
|
@ -38,13 +41,30 @@ pub struct AppState {
|
||||||
db: Arc<dyn Db>,
|
db: Arc<dyn Db>,
|
||||||
api_token: String,
|
api_token: String,
|
||||||
invite_link_prefix: String,
|
invite_link_prefix: String,
|
||||||
|
live_kit_client: Option<live_kit_server::api::Client>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppState {
|
impl AppState {
|
||||||
async fn new(config: &Config) -> Result<Arc<Self>> {
|
async fn new(config: &Config) -> Result<Arc<Self>> {
|
||||||
let db = PostgresDb::new(&config.database_url, 5).await?;
|
let db = PostgresDb::new(&config.database_url, 5).await?;
|
||||||
|
let live_kit_client = if let Some(((server, key), secret)) = config
|
||||||
|
.live_kit_server
|
||||||
|
.as_ref()
|
||||||
|
.zip(config.live_kit_key.as_ref())
|
||||||
|
.zip(config.live_kit_secret.as_ref())
|
||||||
|
{
|
||||||
|
Some(live_kit_server::api::Client::new(
|
||||||
|
server.clone(),
|
||||||
|
key.clone(),
|
||||||
|
secret.clone(),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let this = Self {
|
let this = Self {
|
||||||
db: Arc::new(db),
|
db: Arc::new(db),
|
||||||
|
live_kit_client,
|
||||||
api_token: config.api_token.clone(),
|
api_token: config.api_token.clone(),
|
||||||
invite_link_prefix: config.invite_link_prefix.clone(),
|
invite_link_prefix: config.invite_link_prefix.clone(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
||||||
db::{self, ChannelId, MessageId, ProjectId, User, UserId},
|
db::{self, ChannelId, MessageId, ProjectId, User, UserId},
|
||||||
AppState, Result,
|
AppState, Result,
|
||||||
};
|
};
|
||||||
use anyhow::anyhow;
|
use anyhow::{anyhow, Context};
|
||||||
use async_tungstenite::tungstenite::{
|
use async_tungstenite::tungstenite::{
|
||||||
protocol::CloseFrame as TungsteniteCloseFrame, Message as TungsteniteMessage,
|
protocol::CloseFrame as TungsteniteCloseFrame, Message as TungsteniteMessage,
|
||||||
};
|
};
|
||||||
|
@ -49,6 +49,7 @@ use std::{
|
||||||
},
|
},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
pub use store::{Store, Worktree};
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
sync::{Mutex, MutexGuard},
|
sync::{Mutex, MutexGuard},
|
||||||
|
@ -57,8 +58,6 @@ use tokio::{
|
||||||
use tower::ServiceBuilder;
|
use tower::ServiceBuilder;
|
||||||
use tracing::{info_span, instrument, Instrument};
|
use tracing::{info_span, instrument, Instrument};
|
||||||
|
|
||||||
pub use store::{Store, Worktree};
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref METRIC_CONNECTIONS: IntGauge =
|
static ref METRIC_CONNECTIONS: IntGauge =
|
||||||
register_int_gauge!("connections", "number of connections").unwrap();
|
register_int_gauge!("connections", "number of connections").unwrap();
|
||||||
|
@ -597,13 +596,45 @@ impl Server {
|
||||||
response: Response<proto::CreateRoom>,
|
response: Response<proto::CreateRoom>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let user_id;
|
let user_id;
|
||||||
let room_id;
|
let room;
|
||||||
{
|
{
|
||||||
let mut store = self.store().await;
|
let mut store = self.store().await;
|
||||||
user_id = store.user_id_for_connection(request.sender_id)?;
|
user_id = store.user_id_for_connection(request.sender_id)?;
|
||||||
room_id = store.create_room(request.sender_id)?;
|
room = store.create_room(request.sender_id)?.clone();
|
||||||
}
|
}
|
||||||
response.send(proto::CreateRoomResponse { id: room_id })?;
|
|
||||||
|
let live_kit_token = if let Some(live_kit) = self.app_state.live_kit_client.as_ref() {
|
||||||
|
if let Some(_) = live_kit
|
||||||
|
.create_room(room.live_kit_room.clone())
|
||||||
|
.await
|
||||||
|
.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"error creating LiveKit room (LiveKit room: {}, Zed room: {})",
|
||||||
|
room.live_kit_room, room.id
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.trace_err()
|
||||||
|
{
|
||||||
|
live_kit
|
||||||
|
.room_token_for_user(&room.live_kit_room, &user_id.to_string())
|
||||||
|
.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"error creating LiveKit access token (LiveKit room: {}, Zed room: {})",
|
||||||
|
room.live_kit_room, room.id
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.trace_err()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
response.send(proto::CreateRoomResponse {
|
||||||
|
room: Some(room),
|
||||||
|
live_kit_token,
|
||||||
|
})?;
|
||||||
self.update_user_contacts(user_id).await?;
|
self.update_user_contacts(user_id).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -624,8 +655,24 @@ impl Server {
|
||||||
.send(recipient_id, proto::CallCanceled {})
|
.send(recipient_id, proto::CallCanceled {})
|
||||||
.trace_err();
|
.trace_err();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let live_kit_token = if let Some(live_kit) = self.app_state.live_kit_client.as_ref() {
|
||||||
|
live_kit
|
||||||
|
.room_token_for_user(&room.live_kit_room, &user_id.to_string())
|
||||||
|
.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"error creating LiveKit access token (LiveKit room: {}, Zed room: {})",
|
||||||
|
room.live_kit_room, room.id
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.trace_err()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
response.send(proto::JoinRoomResponse {
|
response.send(proto::JoinRoomResponse {
|
||||||
room: Some(room.clone()),
|
room: Some(room.clone()),
|
||||||
|
live_kit_token,
|
||||||
})?;
|
})?;
|
||||||
self.room_updated(room);
|
self.room_updated(room);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::db::{self, ChannelId, ProjectId, UserId};
|
use crate::db::{self, ChannelId, ProjectId, UserId};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use collections::{btree_map, BTreeMap, BTreeSet, HashMap, HashSet};
|
use collections::{btree_map, BTreeMap, BTreeSet, HashMap, HashSet};
|
||||||
|
use nanoid::nanoid;
|
||||||
use rpc::{proto, ConnectionId};
|
use rpc::{proto, ConnectionId};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::{mem, path::PathBuf, str, time::Duration};
|
use std::{mem, path::PathBuf, str, time::Duration};
|
||||||
|
@ -339,7 +340,7 @@ impl Store {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_room(&mut self, creator_connection_id: ConnectionId) -> Result<RoomId> {
|
pub fn create_room(&mut self, creator_connection_id: ConnectionId) -> Result<&proto::Room> {
|
||||||
let connection = self
|
let connection = self
|
||||||
.connections
|
.connections
|
||||||
.get_mut(&creator_connection_id)
|
.get_mut(&creator_connection_id)
|
||||||
|
@ -353,19 +354,23 @@ impl Store {
|
||||||
"can't create a room with an active call"
|
"can't create a room with an active call"
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut room = proto::Room::default();
|
|
||||||
room.participants.push(proto::Participant {
|
|
||||||
user_id: connection.user_id.to_proto(),
|
|
||||||
peer_id: creator_connection_id.0,
|
|
||||||
projects: Default::default(),
|
|
||||||
location: Some(proto::ParticipantLocation {
|
|
||||||
variant: Some(proto::participant_location::Variant::External(
|
|
||||||
proto::participant_location::External {},
|
|
||||||
)),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
let room_id = post_inc(&mut self.next_room_id);
|
let room_id = post_inc(&mut self.next_room_id);
|
||||||
|
let room = proto::Room {
|
||||||
|
id: room_id,
|
||||||
|
participants: vec![proto::Participant {
|
||||||
|
user_id: connection.user_id.to_proto(),
|
||||||
|
peer_id: creator_connection_id.0,
|
||||||
|
projects: Default::default(),
|
||||||
|
location: Some(proto::ParticipantLocation {
|
||||||
|
variant: Some(proto::participant_location::Variant::External(
|
||||||
|
proto::participant_location::External {},
|
||||||
|
)),
|
||||||
|
}),
|
||||||
|
}],
|
||||||
|
pending_participant_user_ids: Default::default(),
|
||||||
|
live_kit_room: nanoid!(30),
|
||||||
|
};
|
||||||
|
|
||||||
self.rooms.insert(room_id, room);
|
self.rooms.insert(room_id, room);
|
||||||
connected_user.active_call = Some(Call {
|
connected_user.active_call = Some(Call {
|
||||||
caller_user_id: connection.user_id,
|
caller_user_id: connection.user_id,
|
||||||
|
@ -373,7 +378,7 @@ impl Store {
|
||||||
connection_id: Some(creator_connection_id),
|
connection_id: Some(creator_connection_id),
|
||||||
initial_project_id: None,
|
initial_project_id: None,
|
||||||
});
|
});
|
||||||
Ok(room_id)
|
Ok(self.rooms.get(&room_id).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn join_room(
|
pub fn join_room(
|
||||||
|
|
|
@ -54,6 +54,21 @@ impl Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn room_token_for_user(&self, room: &str, identity: &str) -> Result<String> {
|
||||||
|
token::create(
|
||||||
|
&self.key,
|
||||||
|
&self.secret,
|
||||||
|
Some(identity),
|
||||||
|
token::VideoGrant {
|
||||||
|
room: Some(room),
|
||||||
|
room_join: Some(true),
|
||||||
|
can_publish: Some(true),
|
||||||
|
can_subscribe: Some(true),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn request<Req, Res>(
|
fn request<Req, Res>(
|
||||||
&self,
|
&self,
|
||||||
path: &str,
|
path: &str,
|
||||||
|
|
|
@ -140,7 +140,8 @@ message Test {
|
||||||
message CreateRoom {}
|
message CreateRoom {}
|
||||||
|
|
||||||
message CreateRoomResponse {
|
message CreateRoomResponse {
|
||||||
uint64 id = 1;
|
Room room = 1;
|
||||||
|
optional string live_kit_token = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message JoinRoom {
|
message JoinRoom {
|
||||||
|
@ -149,6 +150,7 @@ message JoinRoom {
|
||||||
|
|
||||||
message JoinRoomResponse {
|
message JoinRoomResponse {
|
||||||
Room room = 1;
|
Room room = 1;
|
||||||
|
optional string live_kit_token = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LeaveRoom {
|
message LeaveRoom {
|
||||||
|
@ -156,8 +158,10 @@ message LeaveRoom {
|
||||||
}
|
}
|
||||||
|
|
||||||
message Room {
|
message Room {
|
||||||
repeated Participant participants = 1;
|
uint64 id = 1;
|
||||||
repeated uint64 pending_participant_user_ids = 2;
|
repeated Participant participants = 2;
|
||||||
|
repeated uint64 pending_participant_user_ids = 3;
|
||||||
|
string live_kit_room = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Participant {
|
message Participant {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue