videosdk/resources/
mod.rs1pub mod agents;
4pub mod alert_rules;
5pub mod batch_calls;
6pub mod connectors;
7pub mod egress;
8pub mod hls;
9pub mod ingress;
10pub mod participants;
11pub mod recordings;
12pub mod resource_pool;
13pub mod rooms;
14pub mod rtmp;
15pub mod sessions;
16pub mod sip;
17pub mod transcodings;
18pub mod transcription;
19
20mod session_utils;
21
22#[cfg(test)]
23mod egress_tests;
24#[cfg(test)]
25mod phase5_tests;
26#[cfg(test)]
27mod resource_tests;
28#[cfg(test)]
29mod sip_tests;
30
31use percent_encoding::{utf8_percent_encode, AsciiSet, NON_ALPHANUMERIC};
32
33use crate::client::Client;
34
35const PATH_SEGMENT: &AsciiSet = &NON_ALPHANUMERIC
39 .remove(b'-')
40 .remove(b'.')
41 .remove(b'_')
42 .remove(b'~');
43
44pub(crate) fn escape(segment: &str) -> String {
46 utf8_percent_encode(segment, PATH_SEGMENT).to_string()
47}
48
49pub(crate) fn random_uuid() -> String {
51 uuid::Uuid::new_v4().to_string()
52}
53
54pub(crate) fn slugify_name(name: &str) -> String {
57 let mut slug = String::with_capacity(name.len());
58 let mut previous_was_dash = false;
59
60 for character in name.chars().flat_map(char::to_lowercase) {
61 if character.is_ascii_alphanumeric() || character == '_' || character == '-' {
62 slug.push(character);
63 previous_was_dash = false;
64 } else if !previous_was_dash {
65 slug.push('-');
66 previous_was_dash = true;
67 }
68 }
69
70 let slug = slug.trim_matches('-');
71 let slug: String = slug.chars().take(40).collect();
72 if slug.is_empty() {
73 "agent".to_string()
74 } else {
75 slug
76 }
77}
78
79impl Client {
80 pub fn rooms(&self) -> rooms::RoomsResource<'_> {
82 rooms::RoomsResource::new(self)
83 }
84
85 pub fn sessions(&self) -> sessions::SessionsResource<'_> {
87 sessions::SessionsResource::new(self)
88 }
89
90 pub fn participants(&self) -> participants::ParticipantsResource<'_> {
92 participants::ParticipantsResource::new(self)
93 }
94
95 pub fn recordings(&self) -> recordings::RecordingsResource<'_> {
97 recordings::RecordingsResource::new(self)
98 }
99
100 pub fn hls(&self) -> hls::HlsResource<'_> {
102 hls::HlsResource::new(self)
103 }
104
105 pub fn rtmp(&self) -> rtmp::RtmpResource<'_> {
107 rtmp::RtmpResource::new(self)
108 }
109
110 pub fn sip(&self) -> sip::SipResource<'_> {
112 sip::SipResource::new(self)
113 }
114
115 pub fn agents(&self) -> agents::AgentsResource<'_> {
117 agents::AgentsResource::new(self)
118 }
119
120 pub fn alert_rules(&self) -> alert_rules::AlertRulesResource<'_> {
122 alert_rules::AlertRulesResource::new(self)
123 }
124
125 pub fn batch_call(&self) -> batch_calls::BatchCallsResource<'_> {
127 batch_calls::BatchCallsResource::new(self)
128 }
129
130 pub fn connectors(&self) -> connectors::ConnectorsResource<'_> {
132 connectors::ConnectorsResource::new(self)
133 }
134
135 pub fn resource_pool(&self) -> resource_pool::ResourcePoolResource<'_> {
137 resource_pool::ResourcePoolResource::new(self)
138 }
139
140 pub fn transcodings(&self) -> transcodings::TranscodingsResource<'_> {
142 transcodings::TranscodingsResource::new(self)
143 }
144
145 pub fn transcription(&self) -> transcription::TranscriptionResource<'_> {
147 transcription::TranscriptionResource::new(self)
148 }
149
150 pub fn whip(&self) -> ingress::WhipResource<'_> {
152 ingress::WhipResource::new(self)
153 }
154
155 pub fn whep(&self) -> ingress::WhepResource<'_> {
157 ingress::WhepResource::new(self)
158 }
159
160 pub fn socket_ingress(&self) -> ingress::SocketIngressResource<'_> {
162 ingress::SocketIngressResource::new(self)
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169
170 #[test]
171 fn escapes_path_segments_but_keeps_unreserved_characters() {
172 assert_eq!(escape("abcd-efgh-ijkl"), "abcd-efgh-ijkl");
173 assert_eq!(escape("a_b.c~d"), "a_b.c~d");
174 assert_eq!(escape("a/b"), "a%2Fb");
175 assert_eq!(escape("a b"), "a%20b");
176 assert_eq!(escape("../etc"), "..%2Fetc");
177 assert_eq!(escape("100%"), "100%25");
178 }
179
180 #[test]
181 fn slugify_constrains_names_to_the_secret_charset() {
182 assert_eq!(slugify_name("My Agent"), "my-agent");
183 assert_eq!(
184 slugify_name("keep_dashes-and_underscores"),
185 "keep_dashes-and_underscores"
186 );
187 assert_eq!(slugify_name("a!!!b"), "a-b", "runs collapse to one dash");
188 assert_eq!(slugify_name("--trim--"), "trim");
189 assert_eq!(slugify_name("!!!"), "agent", "an empty slug falls back");
190 assert_eq!(
191 slugify_name(&"x".repeat(60)).len(),
192 40,
193 "capped at 40 chars"
194 );
195 }
196
197 #[test]
198 fn random_uuids_are_distinct_and_well_formed() {
199 let uuid = random_uuid();
200 assert_eq!(uuid.len(), 36);
201 assert_ne!(uuid, random_uuid());
202 }
203}