Skip to content

Commit 575884b

Browse files
committed
return both sse and ws urls for client to connect
1 parent eed30a3 commit 575884b

6 files changed

Lines changed: 39 additions & 19 deletions

File tree

‎Cargo.lock‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎api/Cargo.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "tinistream"
3-
version = "0.1.4"
3+
version = "0.1.5"
44
edition = "2021"
55
publish = false
66

‎api/src/api/stream.rs‎

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rocket::{get, post, serde::json::Json, Route, State};
22
use rocket_okapi::{okapi::openapi3::OpenApi, openapi, openapi_get_routes_spec};
33
use schemars::JsonSchema;
44
use serde::{Deserialize, Serialize};
5-
use time::{ext::NumericalDuration, format_description::well_known, UtcDateTime};
5+
use time::{format_description::well_known, UtcDateTime};
66

77
use crate::{
88
auth::{create_client_token, ApiKeyAuth, Crypto},
@@ -107,11 +107,14 @@ async fn create_stream(
107107
}
108108
redis.start_stream(&input.key, config.ttl).await?;
109109

110-
let url = stream_sse_url(&input.key, &config.server_address);
111-
let plaintext_token = create_client_token(&input.key, 10.minutes());
110+
let plaintext_token = create_client_token(&input.key, config.ttl);
112111
let token = crypto.encrypt_base64(&plaintext_token)?;
113112

114-
Ok(Json(StreamAccessResponse { url, token }))
113+
Ok(Json(StreamAccessResponse {
114+
sse_url: stream_sse_url(&input.key, &config.server_address),
115+
ws_url: stream_ws_url(&input.key, &config.server_address),
116+
token,
117+
}))
115118
}
116119

117120
/// # Create stream token
@@ -124,11 +127,14 @@ async fn create_token(
124127
crypto: &State<Crypto>,
125128
config: &State<AppConfig>,
126129
) -> Result<Json<StreamAccessResponse>, ApiError> {
127-
let url = stream_sse_url(&input.key, &config.server_address);
128-
let plaintext_token = create_client_token(&input.key, 10.minutes());
130+
let plaintext_token = create_client_token(&input.key, config.ttl);
129131
let token = crypto.encrypt_base64(&plaintext_token)?;
130132

131-
Ok(Json(StreamAccessResponse { url, token }))
133+
Ok(Json(StreamAccessResponse {
134+
sse_url: stream_sse_url(&input.key, &config.server_address),
135+
ws_url: stream_ws_url(&input.key, &config.server_address),
136+
token,
137+
}))
132138
}
133139

134140
/// # Cancel stream
@@ -198,9 +204,12 @@ struct StreamRequest {
198204

199205
#[derive(JsonSchema, Serialize, Deserialize)]
200206
struct StreamAccessResponse {
201-
/// URL to connect to the stream
202-
url: String,
203-
/// Bearer token to access the stream
207+
/// URL for the client to connect to the stream via SSE
208+
sse_url: String,
209+
/// URL for the client to connect to the stream via WebSocket
210+
ws_url: String,
211+
/// Client token to access the stream. Can be used as a Bearer token
212+
/// in the Authorization header (recommended) or as the `token` query parameter.
204213
token: String,
205214
}
206215

‎api/src/auth/client_token.rs‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@ impl<'r> FromRequest<'r> for ClientTokenAuth {
5454

5555
/// Create a plaintext client token that gives access to the given stream key
5656
/// and is valid for the given length of time
57-
pub fn create_client_token(key: &str, ttl: Duration) -> String {
58-
let unix_expires = (UtcDateTime::now() + ttl).unix_timestamp();
57+
pub fn create_client_token(key: &str, ttl: u32) -> String {
58+
let ttl_duration = Duration::seconds(ttl.into());
59+
let unix_expires = (UtcDateTime::now() + ttl_duration).unix_timestamp();
5960
format!("{unix_expires}:{key}")
6061
}
6162

‎api/src/redis/util.rs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ pub fn stream_sse_url(key: &str, base_url: &str) -> String {
2020
format!("{base_url}/api/client/sse?key={}", urlencoding::encode(key))
2121
}
2222

23+
/// Get the URL for streaming WebSocket events from the given Redis stream
24+
pub fn stream_ws_url(key: &str, base_url: &str) -> String {
25+
format!("{base_url}/api/client/ws?key={}", urlencoding::encode(key))
26+
}
27+
2328
/// Convert a Redis stream event into a Rocket SSE event. Expects the event data to contain
2429
/// an "event" and "data" field.
2530
pub fn stream_event_to_sse((id, fields): RedisEntry) -> rocket::response::stream::Event {

‎spec/openapi.json‎

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"openapi": "3.0.0",
33
"info": {
44
"title": "tinistream",
5-
"version": "0.1.4"
5+
"version": "0.1.5"
66
},
77
"paths": {
88
"/api/health": {
@@ -1050,16 +1050,21 @@
10501050
"StreamAccessResponse": {
10511051
"type": "object",
10521052
"required": [
1053+
"sse_url",
10531054
"token",
1054-
"url"
1055+
"ws_url"
10551056
],
10561057
"properties": {
1057-
"url": {
1058-
"description": "URL to connect to the stream",
1058+
"sse_url": {
1059+
"description": "URL for the client to connect to the stream via SSE",
1060+
"type": "string"
1061+
},
1062+
"ws_url": {
1063+
"description": "URL for the client to connect to the stream via WebSocket",
10591064
"type": "string"
10601065
},
10611066
"token": {
1062-
"description": "Bearer token to access the stream",
1067+
"description": "Client token to access the stream. Can be used as a Bearer token in the Authorization header (recommended) or as the `token` query parameter.",
10631068
"type": "string"
10641069
}
10651070
}

0 commit comments

Comments
 (0)