api.rs

 1use crate::{proto, token};
 2use anyhow::{anyhow, Result};
 3use prost::Message;
 4use reqwest::header::CONTENT_TYPE;
 5use std::future::Future;
 6
 7pub struct Client {
 8    http: reqwest::Client,
 9    uri: String,
10    key: String,
11    secret: String,
12}
13
14impl Client {
15    pub fn new(mut uri: String, key: String, secret: String) -> Self {
16        if uri.ends_with('/') {
17            uri.pop();
18        }
19
20        Self {
21            http: reqwest::Client::new(),
22            uri,
23            key,
24            secret,
25        }
26    }
27
28    pub fn create_room(&self, name: String) -> impl Future<Output = Result<proto::Room>> {
29        self.request(
30            "twirp/livekit.RoomService/CreateRoom",
31            token::VideoGrant {
32                room_create: Some(true),
33                ..Default::default()
34            },
35            proto::CreateRoomRequest {
36                name,
37                ..Default::default()
38            },
39        )
40    }
41
42    pub fn delete_room(&self, name: String) -> impl Future<Output = Result<()>> {
43        let response = self.request(
44            "twirp/livekit.RoomService/DeleteRoom",
45            token::VideoGrant {
46                room_create: Some(true),
47                ..Default::default()
48            },
49            proto::DeleteRoomRequest { room: name },
50        );
51        async move {
52            response.await?;
53            Ok(())
54        }
55    }
56
57    fn request<Req, Res>(
58        &self,
59        path: &str,
60        grant: token::VideoGrant,
61        body: Req,
62    ) -> impl Future<Output = Result<Res>>
63    where
64        Req: Message,
65        Res: Default + Message,
66    {
67        let client = self.http.clone();
68        let token = token::create(&self.key, &self.secret, None, grant);
69        let uri = format!("{}/{}", self.uri, path);
70        async move {
71            let token = token?;
72            let response = client
73                .post(&uri)
74                .header(CONTENT_TYPE, "application/protobuf")
75                .bearer_auth(token)
76                .body(body.encode_to_vec())
77                .send()
78                .await?;
79            if response.status().is_success() {
80                Ok(Res::decode(response.bytes().await?)?)
81            } else {
82                Err(anyhow!(
83                    "POST {} failed with status code {:?}, {:?}",
84                    uri,
85                    response.status(),
86                    response.text().await
87                ))
88            }
89        }
90    }
91}