Files
zed/crates/livekit_api/src/livekit_api.rs
T
Kirill Bulatov f36284a155 Bump dependencies to dedupe the crate graph (#63231)
Deduplicates crates with different versions from the graph, drops unused
features.

`cargo tree -d duplicate` listing: 160 -> 112 lines.

<details>
<summary>Deduplicated list</summary>

```
base64 (v0.22.1, v0.21.7 -> v0.22.1)
convert_case (v0.11.0, v0.10.0, v0.8.0 -> v0.11.0, v0.10.0)
core-foundation (v0.10.0, v0.9.4 -> v0.10.0)
cssparser (v0.36.0, v0.35.0 -> v0.37.0, v0.36.0)
fancy-regex (v0.18.0, v0.16.2 -> v0.19.0)
fixedbitset (v0.5.7, v0.4.2 -> v0.5.7)
h2 (v0.4.12, v0.3.27 -> v0.4.12)
heck (v0.5.0, v0.4.1, v0.3.3 -> v0.5.0, v0.4.1)
html5ever (v0.39.0, v0.35.0 -> v0.39.0)
hyper (v1.7.0, v0.14.32 -> v1.7.0)
hyper-rustls (v0.27.9, v0.24.2 -> v0.27.9)
mach2 (v0.6.0, v0.5.0, v0.4.3 -> v0.6.0, v0.5.0)
markup5ever (v0.39.0, v0.35.0 -> v0.39.0)
phf (v0.13.1, v0.12.1, v0.11.3 -> v0.13.1, v0.11.3)
phf_codegen (v0.13.1, v0.11.3 -> v0.13.1)
phf_generator (v0.13.1, v0.12.1, v0.11.3 -> v0.13.1, v0.11.3)
phf_macros (v0.13.1, v0.12.1, v0.11.3 -> v0.13.1, v0.11.3)
phf_shared (v0.13.1, v0.12.1, v0.11.3 -> v0.13.1, v0.11.3)
prost (v0.12.6, v0.9.0 -> v0.14.4)
prost-build (v0.12.6, v0.9.0 -> v0.14.4)
prost-derive (v0.12.6, v0.9.0 -> v0.14.4)
prost-types (v0.12.6, v0.9.0 -> v0.14.4)
rustix (v1.1.4, v0.38.44 -> v1.1.4)
rustls (v0.23.40, v0.21.12 -> v0.23.40)
rustls-native-certs (v0.8.3, v0.6.3 -> v0.8.3)
rustls-pemfile (v2.2.0, v1.0.4 -> v2.2.0)
rustls-webpki (v0.103.13, v0.101.7 -> v0.103.13)
security-framework (v3.5.1, v2.11.1 -> v3.5.1)
socket2 (v0.6.3, v0.5.10 -> v0.6.3)
string_cache (v0.9.0, v0.8.9 -> v0.9.0)
string_cache_codegen (v0.6.1, v0.5.4 -> v0.6.1)
strum (v0.28.0, v0.27.2 -> v0.28.0)
strum_macros (v0.28.0, v0.27.2 -> v0.28.0)
tendril (v0.5.1, v0.4.3 -> v0.5.1)
tokio-rustls (v0.26.4, v0.24.1 -> v0.26.4)
tungstenite (v0.28.0, v0.27.0 -> v0.28.0)
web_atoms (v0.2.6, v0.1.3 -> v0.2.6)
which (v6.0.3, v4.4.2 -> v8.0.5)
```

</details>


Release Notes:

- N/A
2026-08-26 14:33:13 +00:00

207 lines
5.9 KiB
Rust

pub mod proto;
pub mod token;
use anyhow::Result;
use async_trait::async_trait;
use prost::Message;
use reqwest::header::CONTENT_TYPE;
use std::{future::Future, sync::Arc, time::Duration};
#[async_trait]
pub trait Client: Send + Sync {
fn url(&self) -> &str;
async fn create_room(&self, name: String) -> Result<()>;
async fn delete_room(&self, name: String) -> Result<()>;
async fn remove_participant(&self, room: String, identity: String) -> Result<()>;
async fn update_participant(
&self,
room: String,
identity: String,
permission: proto::ParticipantPermission,
) -> Result<()>;
fn room_token(&self, room: &str, identity: &str) -> Result<String>;
fn guest_token(&self, room: &str, identity: &str) -> Result<String>;
}
pub struct LiveKitParticipantUpdate {}
#[derive(Clone)]
pub struct LiveKitClient {
http: reqwest::Client,
url: Arc<str>,
key: Arc<str>,
secret: Arc<str>,
timestamp_source: Arc<dyn token::UnixTimestampSource>,
}
impl LiveKitClient {
pub fn new(url: String, key: String, secret: String) -> Self {
Self::new_with_timestamp_source(
url,
key,
secret,
Arc::new(token::SystemUnixTimestampSource),
)
}
pub(crate) fn new_with_timestamp_source(
mut url: String,
key: String,
secret: String,
timestamp_source: Arc<dyn token::UnixTimestampSource>,
) -> Self {
if url.ends_with('/') {
url.pop();
}
Self {
http: reqwest::ClientBuilder::new()
.timeout(Duration::from_secs(5))
.build()
.unwrap(),
url: url.into(),
key: key.into(),
secret: secret.into(),
timestamp_source,
}
}
fn request<Req, Res>(
&self,
path: &str,
grant: token::VideoGrant,
body: Req,
) -> impl Future<Output = Result<Res>>
where
Req: Message + std::fmt::Debug,
Res: Default + Message,
{
let client = self.http.clone();
let token = token::create_with_timestamp_source(
&self.key,
&self.secret,
None,
grant,
self.timestamp_source.as_ref(),
);
let url = format!("{}/{}", self.url, path);
log::info!("Request {}: {:?}", url, body);
async move {
let token = token?;
let response = client
.post(&url)
.header(CONTENT_TYPE, "application/protobuf")
.bearer_auth(token)
.body(body.encode_to_vec())
.send()
.await?;
if response.status().is_success() {
log::info!("Response {}: {:?}", url, response.status());
Ok(Res::decode(response.bytes().await?)?)
} else {
log::error!("Response {}: {:?}", url, response.status());
anyhow::bail!(
"POST {} failed with status code {:?}, {:?}",
url,
response.status(),
response.text().await
);
}
}
}
}
#[async_trait]
impl Client for LiveKitClient {
fn url(&self) -> &str {
&self.url
}
async fn create_room(&self, name: String) -> Result<()> {
let _: proto::Room = self
.request(
"twirp/livekit.RoomService/CreateRoom",
token::VideoGrant {
room_create: Some(true),
..Default::default()
},
proto::CreateRoomRequest {
name,
..Default::default()
},
)
.await?;
Ok(())
}
async fn delete_room(&self, name: String) -> Result<()> {
let _: proto::DeleteRoomResponse = self
.request(
"twirp/livekit.RoomService/DeleteRoom",
token::VideoGrant {
room_create: Some(true),
..Default::default()
},
proto::DeleteRoomRequest { room: name },
)
.await?;
Ok(())
}
async fn remove_participant(&self, room: String, identity: String) -> Result<()> {
let _: proto::RemoveParticipantResponse = self
.request(
"twirp/livekit.RoomService/RemoveParticipant",
token::VideoGrant::to_admin(&room),
proto::RoomParticipantIdentity {
room: room.clone(),
identity,
},
)
.await?;
Ok(())
}
async fn update_participant(
&self,
room: String,
identity: String,
permission: proto::ParticipantPermission,
) -> Result<()> {
let _: proto::ParticipantInfo = self
.request(
"twirp/livekit.RoomService/UpdateParticipant",
token::VideoGrant::to_admin(&room),
proto::UpdateParticipantRequest {
room: room.clone(),
identity,
metadata: "".to_string(),
permission: Some(permission),
},
)
.await?;
Ok(())
}
fn room_token(&self, room: &str, identity: &str) -> Result<String> {
token::create_with_timestamp_source(
&self.key,
&self.secret,
Some(identity),
token::VideoGrant::to_join(room),
self.timestamp_source.as_ref(),
)
}
fn guest_token(&self, room: &str, identity: &str) -> Result<String> {
token::create_with_timestamp_source(
&self.key,
&self.secret,
Some(identity),
token::VideoGrant::for_guest(room),
self.timestamp_source.as_ref(),
)
}
}