+12
spacedust/src/error.rs
+12
spacedust/src/error.rs
···
23
23
}
24
24
25
25
#[derive(Debug, Error)]
26
+
pub enum SubscriberUpdateError {
27
+
#[error("failed to parse json for subscriber update: {0}")]
28
+
FailedToParseMessage(serde_json::Error),
29
+
#[error("more wantedSources were requested than allowed (max 1,000)")]
30
+
TooManySourcesWanted,
31
+
#[error("more wantedSubjectDids were requested than allowed (max 10,000)")]
32
+
TooManyDidsWanted,
33
+
#[error("more wantedSubjects were requested than allowed (max 50,000)")]
34
+
TooManySubjectsWanted,
35
+
}
36
+
37
+
#[derive(Debug, Error)]
26
38
pub enum DelayError {
27
39
#[error("delay ended")]
28
40
DelayEnded,
+8
-1
spacedust/src/lib.rs
+8
-1
spacedust/src/lib.rs
···
8
8
use links::CollectedLink;
9
9
use jetstream::events::CommitEvent;
10
10
use tokio_tungstenite::tungstenite::Message;
11
-
use serde::Serialize;
11
+
use serde::{Deserialize, Serialize};
12
+
use server::MultiSubscribeQuery;
12
13
13
14
#[derive(Debug)]
14
15
pub struct FilterableProperties {
···
84
85
// TODO: include the record too? would save clients a level of hydration
85
86
// ^^ no, not for now. until we backfill + support broader deletes at *least*.
86
87
}
88
+
89
+
#[derive(Debug, Deserialize)]
90
+
#[serde(tag = "type", content = "payload", rename_all = "snake_case")]
91
+
pub enum SubscriberSourcedMessage {
92
+
OptionsUpdate(MultiSubscribeQuery),
93
+
}
+4
-2
spacedust/src/server.rs
+4
-2
spacedust/src/server.rs
···
19
19
use serde::{Deserialize, Serialize};
20
20
use tokio::sync::broadcast;
21
21
use tokio::time::Instant;
22
-
use tokio_tungstenite::tungstenite::protocol::Role;
22
+
use tokio_tungstenite::tungstenite::protocol::{Role, WebSocketConfig};
23
23
use tokio_util::sync::CancellationToken;
24
24
use async_trait::async_trait;
25
25
use std::collections::HashSet;
···
315
315
let ws = tokio_tungstenite::WebSocketStream::from_raw_socket(
316
316
upgraded.into_inner(),
317
317
Role::Server,
318
-
None,
318
+
Some(WebSocketConfig::default().max_message_size(
319
+
Some(10 * 2_usize.pow(20)) // 10MiB, matching jetstream
320
+
)),
319
321
)
320
322
.await;
321
323
+30
-2
spacedust/src/subscriber.rs
+30
-2
spacedust/src/subscriber.rs
···
1
+
use crate::error::SubscriberUpdateError;
1
2
use std::sync::Arc;
2
3
use tokio::time::interval;
3
4
use std::time::Duration;
4
5
use futures::StreamExt;
5
-
use crate::{ClientMessage, FilterableProperties};
6
+
use crate::{ClientMessage, FilterableProperties, SubscriberSourcedMessage};
6
7
use crate::server::MultiSubscribeQuery;
7
8
use futures::SinkExt;
8
9
use std::error::Error;
···
27
28
}
28
29
29
30
pub async fn start(
30
-
self,
31
+
mut self,
31
32
ws: WebSocketStream<WebsocketConnectionRaw>,
32
33
mut receiver: broadcast::Receiver<Arc<ClientMessage>>
33
34
) -> Result<(), Box<dyn Error>> {
···
76
77
self.shutdown.cancel();
77
78
}
78
79
}
80
+
Some(Ok(Message::Text(raw))) => {
81
+
if let Err(e) = self.query.update_from_raw(&raw) {
82
+
log::error!("subscriber options could not be updated, dropping: {e:?}");
83
+
// TODO: send client an explanation
84
+
self.shutdown.cancel();
85
+
}
86
+
},
79
87
Some(Ok(m)) => log::trace!("subscriber sent an unexpected message: {m:?}"),
80
88
Some(Err(e)) => {
81
89
log::error!("failed to receive subscriber message: {e:?}");
···
137
145
true
138
146
}
139
147
}
148
+
149
+
150
+
151
+
impl MultiSubscribeQuery {
152
+
pub fn update_from_raw(&mut self, s: &str) -> Result<(), SubscriberUpdateError> {
153
+
let SubscriberSourcedMessage::OptionsUpdate(opts) = serde_json::from_str(s)
154
+
.map_err(SubscriberUpdateError::FailedToParseMessage)?;
155
+
if opts.wanted_sources.len() > 1_000 {
156
+
return Err(SubscriberUpdateError::TooManySourcesWanted);
157
+
}
158
+
if opts.wanted_subject_dids.len() > 10_000 {
159
+
return Err(SubscriberUpdateError::TooManyDidsWanted);
160
+
}
161
+
if opts.wanted_subjects.len() > 50_000 {
162
+
return Err(SubscriberUpdateError::TooManySubjectsWanted);
163
+
}
164
+
*self = opts;
165
+
Ok(())
166
+
}
167
+
}