diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..b1dad4cbbe --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "crates/live_kit_server/protocol"] + path = crates/live_kit_server/protocol + url = https://github.com/livekit/protocol diff --git a/Cargo.lock b/Cargo.lock index 0e32c86091..16417f6906 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3203,7 +3203,11 @@ version = "0.1.0" dependencies = [ "anyhow", "hmac 0.12.1", + "hyper", "jwt", + "prost 0.8.0", + "prost-build", + "prost-types 0.8.0", "serde", "sha2 0.10.6", ] @@ -4363,7 +4367,7 @@ dependencies = [ "multimap", "petgraph", "prost 0.9.0", - "prost-types", + "prost-types 0.9.0", "regex", "tempfile", "which", @@ -4395,6 +4399,16 @@ dependencies = [ "syn", ] +[[package]] +name = "prost-types" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "603bbd6394701d13f3f25aada59c7de9d35a6a5887cfc156181234a44002771b" +dependencies = [ + "bytes 1.2.1", + "prost 0.8.0", +] + [[package]] name = "prost-types" version = "0.9.0" diff --git a/crates/capture/src/main.rs b/crates/capture/src/main.rs index 00f3eac2df..912e1e0be2 100644 --- a/crates/capture/src/main.rs +++ b/crates/capture/src/main.rs @@ -36,7 +36,7 @@ fn main() { let live_kit_secret = std::env::var("LIVE_KIT_SECRET").unwrap(); cx.spawn(|mut cx| async move { - let user1_token = live_kit_server::create_token( + let user1_token = live_kit_server::token::create( &live_kit_key, &live_kit_secret, "test-room", @@ -46,7 +46,7 @@ fn main() { let room1 = Room::new(); room1.connect(&live_kit_url, &user1_token).await.unwrap(); - let user2_token = live_kit_server::create_token( + let user2_token = live_kit_server::token::create( &live_kit_key, &live_kit_secret, "test-room", diff --git a/crates/live_kit_server/Cargo.toml b/crates/live_kit_server/Cargo.toml index dc9d56074e..17eb83f83e 100644 --- a/crates/live_kit_server/Cargo.toml +++ b/crates/live_kit_server/Cargo.toml @@ -12,5 +12,11 @@ doctest = false anyhow = "1.0.38" hmac = "0.12" jwt = "0.16" +hyper = "0.14" +prost = "0.8" +prost-types = "0.8" serde = { version = "1.0", features = ["derive", "rc"] } -sha2 = "0.10" \ No newline at end of file +sha2 = "0.10" + +[build-dependencies] +prost-build = "0.9" diff --git a/crates/live_kit_server/build.rs b/crates/live_kit_server/build.rs new file mode 100644 index 0000000000..fa1bde69d6 --- /dev/null +++ b/crates/live_kit_server/build.rs @@ -0,0 +1,5 @@ +fn main() { + prost_build::Config::new() + .compile_protos(&["protocol/livekit_room.proto"], &["protocol"]) + .unwrap(); +} diff --git a/crates/live_kit_server/protocol b/crates/live_kit_server/protocol new file mode 160000 index 0000000000..8645a138fb --- /dev/null +++ b/crates/live_kit_server/protocol @@ -0,0 +1 @@ +Subproject commit 8645a138fb2ea72c4dab13e739b1f3c9ea29ac84 diff --git a/crates/live_kit_server/src/api.rs b/crates/live_kit_server/src/api.rs new file mode 100644 index 0000000000..acdb80aaf9 --- /dev/null +++ b/crates/live_kit_server/src/api.rs @@ -0,0 +1,36 @@ +use crate::token; +use hyper::{client::HttpConnector, Request, Uri}; + +pub struct Client { + http: hyper::Client, + uri: Uri, + key: String, + secret: String, +} + +impl Client { + pub fn new(uri: Uri, key: String, secret: String) -> Self { + assert!(uri.scheme().is_some(), "base uri must have a scheme"); + assert!(uri.authority().is_some(), "base uri must have an authority"); + Self { + http: hyper::Client::new(), + uri: uri, + key, + secret, + } + } + + pub fn create_room(&self) { + // let mut uri = url.clone(); + // uri.set_path_and_query() + + let uri = Uri::builder() + .scheme(self.uri.scheme().unwrap().clone()) + .authority(self.uri.authority().unwrap().clone()) + .path_and_query("twirp/livekit.RoomService/CreateRoom") + .build(); + + // token::create(api_key, secret_key, room_name, participant_name) + self.http.request(req) + } +} diff --git a/crates/live_kit_server/src/live_kit_server.rs b/crates/live_kit_server/src/live_kit_server.rs index be4fc4f4a2..7b4a741355 100644 --- a/crates/live_kit_server/src/live_kit_server.rs +++ b/crates/live_kit_server/src/live_kit_server.rs @@ -1,71 +1,3 @@ -use anyhow::Result; -use hmac::{Hmac, Mac}; -use jwt::SignWithKey; -use serde::Serialize; -use sha2::Sha256; -use std::{ - ops::Add, - time::{Duration, SystemTime, UNIX_EPOCH}, -}; - -static DEFAULT_TTL: Duration = Duration::from_secs(6 * 60 * 60); // 6 hours - -#[derive(Default, Serialize)] -#[serde(rename_all = "camelCase")] -struct ClaimGrants<'a> { - iss: &'a str, - sub: &'a str, - iat: u64, - exp: u64, - nbf: u64, - jwtid: &'a str, - video: VideoGrant<'a>, -} - -#[derive(Default, Serialize)] -#[serde(rename_all = "camelCase")] -struct VideoGrant<'a> { - room_create: Option, - room_join: Option, - room_list: Option, - room_record: Option, - room_admin: Option, - room: Option<&'a str>, - can_publish: Option, - can_subscribe: Option, - can_publish_data: Option, - hidden: Option, - recorder: Option, -} - -pub fn create_token( - api_key: &str, - secret_key: &str, - room_name: &str, - participant_name: &str, -) -> Result { - let secret_key: Hmac = Hmac::new_from_slice(secret_key.as_bytes())?; - - let now = SystemTime::now(); - - let claims = ClaimGrants { - iss: api_key, - sub: participant_name, - iat: now.duration_since(UNIX_EPOCH).unwrap().as_secs(), - exp: now - .add(DEFAULT_TTL) - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(), - nbf: 0, - jwtid: participant_name, - video: VideoGrant { - room: Some(room_name), - room_join: Some(true), - can_publish: Some(true), - can_subscribe: Some(true), - ..Default::default() - }, - }; - Ok(claims.sign_with_key(&secret_key)?) -} +mod api; +mod proto; +mod token; diff --git a/crates/live_kit_server/src/proto.rs b/crates/live_kit_server/src/proto.rs new file mode 100644 index 0000000000..a304705c59 --- /dev/null +++ b/crates/live_kit_server/src/proto.rs @@ -0,0 +1 @@ +include!(concat!(env!("OUT_DIR"), "/livekit.rs")); diff --git a/crates/live_kit_server/src/token.rs b/crates/live_kit_server/src/token.rs new file mode 100644 index 0000000000..f6ac2945b5 --- /dev/null +++ b/crates/live_kit_server/src/token.rs @@ -0,0 +1,71 @@ +use anyhow::Result; +use hmac::{Hmac, Mac}; +use jwt::SignWithKey; +use serde::Serialize; +use sha2::Sha256; +use std::{ + ops::Add, + time::{Duration, SystemTime, UNIX_EPOCH}, +}; + +static DEFAULT_TTL: Duration = Duration::from_secs(6 * 60 * 60); // 6 hours + +#[derive(Default, Serialize)] +#[serde(rename_all = "camelCase")] +struct ClaimGrants<'a> { + iss: &'a str, + sub: &'a str, + iat: u64, + exp: u64, + nbf: u64, + jwtid: &'a str, + video: VideoGrant<'a>, +} + +#[derive(Default, Serialize)] +#[serde(rename_all = "camelCase")] +struct VideoGrant<'a> { + room_create: Option, + room_join: Option, + room_list: Option, + room_record: Option, + room_admin: Option, + room: Option<&'a str>, + can_publish: Option, + can_subscribe: Option, + can_publish_data: Option, + hidden: Option, + recorder: Option, +} + +pub fn create( + api_key: &str, + secret_key: &str, + room_name: &str, + participant_name: &str, +) -> Result { + let secret_key: Hmac = Hmac::new_from_slice(secret_key.as_bytes())?; + + let now = SystemTime::now(); + + let claims = ClaimGrants { + iss: api_key, + sub: participant_name, + iat: now.duration_since(UNIX_EPOCH).unwrap().as_secs(), + exp: now + .add(DEFAULT_TTL) + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(), + nbf: 0, + jwtid: participant_name, + video: VideoGrant { + room: Some(room_name), + room_join: Some(true), + can_publish: Some(true), + can_subscribe: Some(true), + ..Default::default() + }, + }; + Ok(claims.sign_with_key(&secret_key)?) +}