···77use clap::Parser;
88use jetstream::{
99 events::{
1010- commit::{
1111- CommitEvent,
1212- CommitType,
1313- },
1414- JetstreamEvent::Commit,
1010+ CommitEvent,
1111+ CommitOp,
1212+ EventKind,
1313+ JetstreamEvent,
1514 },
1615 DefaultJetstreamEndpoints,
1716 JetstreamCompression,
···2524 /// The DIDs to listen for events on, if not provided we will listen for all DIDs.
2625 #[arg(short, long)]
2726 did: Option<Vec<string::Did>>,
2828- /// The NSID for the collection to listen for (e.g. `app.bsky.feed.post`).
2929- #[arg(short, long)]
3030- nsid: string::Nsid,
3127}
32283329#[tokio::main]
···3733 let dids = args.did.unwrap_or_default();
3834 let config = JetstreamConfig {
3935 endpoint: DefaultJetstreamEndpoints::USEastOne.into(),
4040- wanted_collections: vec![args.nsid.clone()],
3636+ wanted_collections: vec![string::Nsid::new("app.bsky.feed.post".to_string()).unwrap()],
4137 wanted_dids: dids.clone(),
4238 compression: JetstreamCompression::Zstd,
4339 ..Default::default()
···4642 let jetstream = JetstreamConnector::new(config)?;
4743 let mut receiver = jetstream.connect().await?;
48444949- println!(
5050- "Listening for '{}' events on DIDs: {:?}",
5151- args.nsid.as_str(),
5252- dids
5353- );
4545+ println!("Listening for 'app.bsky.feed.post' events on DIDs: {dids:?}");
54465547 while let Some(event) = receiver.recv().await {
5656- if let Commit(commit) = event {
5757- match commit {
5858- CommitEvent::CreateOrUpdate { info: _, commit }
5959- if commit.info.operation == CommitType::Create =>
6060- {
6161- if let AppBskyFeedPost(record) = commit.record {
6262- println!(
6363- "New post created! ({})\n\n'{}'",
6464- commit.info.rkey.as_str(),
6565- record.text
6666- );
6767- }
6868- }
6969- CommitEvent::Delete { info: _, commit } => {
7070- println!("A post has been deleted. ({})", commit.rkey.as_str());
7171- }
7272- _ => {}
4848+ if let JetstreamEvent {
4949+ kind: EventKind::Commit,
5050+ commit:
5151+ Some(CommitEvent {
5252+ operation: CommitOp::Create,
5353+ rkey,
5454+ record: Some(record),
5555+ ..
5656+ }),
5757+ ..
5858+ } = event
5959+ {
6060+ if let Ok(AppBskyFeedPost(rec)) = serde_json::from_str(record.get()) {
6161+ println!("New post created! ({})\n{:?}\n", rkey.as_str(), rec.text);
7362 }
7463 }
7564 }
-40
jetstream/src/events/account.rs
···11-use chrono::Utc;
22-use serde::Deserialize;
33-44-use crate::{
55- events::EventInfo,
66- exports,
77-};
88-99-/// An event representing a change to an account.
1010-#[derive(Deserialize, Debug)]
1111-pub struct AccountEvent {
1212- /// Basic metadata included with every event.
1313- #[serde(flatten)]
1414- pub info: EventInfo,
1515- /// Account specific data bundled with this event.
1616- pub account: AccountData,
1717-}
1818-1919-/// Account specific data bundled with an account event.
2020-#[derive(Deserialize, Debug)]
2121-pub struct AccountData {
2222- /// Whether the account is currently active.
2323- pub active: bool,
2424- /// The DID of the account.
2525- pub did: exports::Did,
2626- pub seq: u64,
2727- pub time: chrono::DateTime<Utc>,
2828- /// If `active` is `false` this will be present to explain why the account is inactive.
2929- pub status: Option<AccountStatus>,
3030-}
3131-3232-/// The possible reasons an account might be listed as inactive.
3333-#[derive(Deserialize, Debug)]
3434-#[serde(rename_all = "lowercase")]
3535-pub enum AccountStatus {
3636- Deactivated,
3737- Deleted,
3838- Suspended,
3939- TakenDown,
4040-}
-55
jetstream/src/events/commit.rs
···11-use serde::Deserialize;
22-33-use crate::{
44- events::EventInfo,
55- exports,
66-};
77-88-/// An event representing a repo commit, which can be a `create`, `update`, or `delete` operation.
99-#[derive(Deserialize, Debug)]
1010-#[serde(untagged, rename_all = "snake_case")]
1111-pub enum CommitEvent<R> {
1212- CreateOrUpdate {
1313- #[serde(flatten)]
1414- info: EventInfo,
1515- commit: CommitData<R>,
1616- },
1717- Delete {
1818- #[serde(flatten)]
1919- info: EventInfo,
2020- commit: CommitInfo,
2121- },
2222-}
2323-2424-/// The type of commit operation that was performed.
2525-#[derive(Deserialize, Debug, PartialEq)]
2626-#[serde(rename_all = "snake_case")]
2727-pub enum CommitType {
2828- Create,
2929- Update,
3030- Delete,
3131-}
3232-3333-/// Basic commit specific info bundled with every event, also the only data included with a `delete`
3434-/// operation.
3535-#[derive(Deserialize, Debug)]
3636-pub struct CommitInfo {
3737- /// The type of commit operation that was performed.
3838- pub operation: CommitType,
3939- pub rev: String,
4040- pub rkey: exports::RecordKey,
4141- /// The NSID of the record type that this commit is associated with.
4242- pub collection: exports::Nsid,
4343-}
4444-4545-/// Detailed data bundled with a commit event. This data is only included when the event is
4646-/// `create` or `update`.
4747-#[derive(Deserialize, Debug)]
4848-pub struct CommitData<R> {
4949- #[serde(flatten)]
5050- pub info: CommitInfo,
5151- /// The CID of the record that was operated on.
5252- pub cid: exports::Cid,
5353- /// The record that was operated on.
5454- pub record: R,
5555-}
-28
jetstream/src/events/identity.rs
···11-use chrono::Utc;
22-use serde::Deserialize;
33-44-use crate::{
55- events::EventInfo,
66- exports,
77-};
88-99-/// An event representing a change to an identity.
1010-#[derive(Deserialize, Debug)]
1111-pub struct IdentityEvent {
1212- /// Basic metadata included with every event.
1313- #[serde(flatten)]
1414- pub info: EventInfo,
1515- /// Identity specific data bundled with this event.
1616- pub identity: IdentityData,
1717-}
1818-1919-/// Identity specific data bundled with an identity event.
2020-#[derive(Deserialize, Debug)]
2121-pub struct IdentityData {
2222- /// The DID of the identity.
2323- pub did: exports::Did,
2424- /// The handle associated with the identity.
2525- pub handle: Option<exports::Handle>,
2626- pub seq: u64,
2727- pub time: chrono::DateTime<Utc>,
2828-}
···77 Cursor as IoCursor,
88 Read,
99 },
1010- marker::PhantomData,
1110 time::{
1211 Duration,
1312 Instant,
1413 },
1514};
16151717-use atrium_api::record::KnownRecord;
1816use futures_util::{
1917 stream::StreamExt,
2018 SinkExt,
2119};
2222-use serde::de::DeserializeOwned;
2320use tokio::{
2421 net::TcpStream,
2522 sync::mpsc::{
···124121const JETSTREAM_ZSTD_DICTIONARY: &[u8] = include_bytes!("../zstd/dictionary");
125122126123/// A receiver channel for consuming Jetstream events.
127127-pub type JetstreamReceiver<R> = Receiver<JetstreamEvent<R>>;
124124+pub type JetstreamReceiver = Receiver<JetstreamEvent>;
128125129126/// An internal sender channel for sending Jetstream events to [JetstreamReceiver]'s.
130130-type JetstreamSender<R> = Sender<JetstreamEvent<R>>;
127127+type JetstreamSender = Sender<JetstreamEvent>;
131128132129/// A wrapper connector type for working with a WebSocket connection to a Jetstream instance to
133130/// receive and consume events. See [JetstreamConnector::connect] for more info.
134134-pub struct JetstreamConnector<R: DeserializeOwned> {
131131+pub struct JetstreamConnector {
135132 /// The configuration for the Jetstream connection.
136136- config: JetstreamConfig<R>,
133133+ config: JetstreamConfig,
137134}
138135139136pub enum JetstreamCompression {
···163160 }
164161}
165162166166-pub struct JetstreamConfig<R: DeserializeOwned = KnownRecord> {
163163+pub struct JetstreamConfig {
167164 /// A Jetstream endpoint to connect to with a WebSocket Scheme i.e.
168165 /// `wss://jetstream1.us-east.bsky.network/subscribe`.
169166 pub endpoint: String,
···200197 /// can help prevent that if your consumer sometimes pauses, at a cost of higher memory
201198 /// usage while events are buffered.
202199 pub channel_size: usize,
203203- /// Marker for record deserializable type.
204204- ///
205205- /// See examples/arbitrary_record.rs for an example using serde_json::Value
206206- ///
207207- /// You can omit this if you construct `JetstreamConfig { a: b, ..Default::default() }.
208208- /// If you have to specify it, use `std::marker::PhantomData` with no type parameters.
209209- pub record_type: PhantomData<R>,
210200}
211201212212-impl<R: DeserializeOwned> Default for JetstreamConfig<R> {
202202+impl Default for JetstreamConfig {
213203 fn default() -> Self {
214204 JetstreamConfig {
215205 endpoint: DefaultJetstreamEndpoints::USEastOne.into(),
···220210 omit_user_agent_jetstream_info: false,
221211 replay_on_reconnect: false,
222212 channel_size: 4096, // a few seconds of firehose buffer
223223- record_type: PhantomData,
224213 }
225214 }
226215}
227216228228-impl<R: DeserializeOwned> JetstreamConfig<R> {
217217+impl JetstreamConfig {
229218 /// Constructs a new endpoint URL with the given [JetstreamConfig] applied.
230219 pub fn get_request_builder(
231220 &self,
···313302 }
314303}
315304316316-impl<R: DeserializeOwned + Send + 'static> JetstreamConnector<R> {
305305+impl JetstreamConnector {
317306 /// Create a Jetstream connector with a valid [JetstreamConfig].
318307 ///
319308 /// After creation, you can call [connect] to connect to the provided Jetstream instance.
320320- pub fn new(config: JetstreamConfig<R>) -> Result<Self, ConfigValidationError> {
309309+ pub fn new(config: JetstreamConfig) -> Result<Self, ConfigValidationError> {
321310 // We validate the configuration here so any issues are caught early.
322311 config.validate()?;
323312 Ok(JetstreamConnector { config })
···327316 ///
328317 /// A [JetstreamReceiver] is returned which can be used to respond to events. When all instances
329318 /// of this receiver are dropped, the connection and task are automatically closed.
330330- pub async fn connect(&self) -> Result<JetstreamReceiver<R>, ConnectionError> {
319319+ pub async fn connect(&self) -> Result<JetstreamReceiver, ConnectionError> {
331320 self.connect_cursor(None).await
332321 }
333322···343332 pub async fn connect_cursor(
344333 &self,
345334 cursor: Option<Cursor>,
346346- ) -> Result<JetstreamReceiver<R>, ConnectionError> {
335335+ ) -> Result<JetstreamReceiver, ConnectionError> {
347336 // We validate the config again for good measure. Probably not necessary but it can't hurt.
348337 self.config
349338 .validate()
···424413425414/// The main task that handles the WebSocket connection and sends [JetstreamEvent]'s to any
426415/// receivers that are listening for them.
427427-async fn websocket_task<R: DeserializeOwned>(
416416+async fn websocket_task(
428417 dictionary: DecoderDictionary<'_>,
429418 ws: WebSocketStream<MaybeTlsStream<TcpStream>>,
430430- send_channel: JetstreamSender<R>,
419419+ send_channel: JetstreamSender,
431420 last_cursor: &mut Option<Cursor>,
432421) -> Result<(), JetstreamEventError> {
433422 // TODO: Use the write half to allow the user to change configuration settings on the fly.
···439428 Some(Ok(message)) => {
440429 match message {
441430 Message::Text(json) => {
442442- let event: JetstreamEvent<R> = serde_json::from_str(&json)
431431+ let event: JetstreamEvent = serde_json::from_str(&json)
443432 .map_err(JetstreamEventError::ReceivedMalformedJSON)?;
444444- let event_cursor = event.cursor();
433433+ let event_cursor = event.cursor.clone();
445434446435 if let Some(last) = last_cursor {
447436 if event_cursor <= *last {
···475464 .read_to_string(&mut json)
476465 .map_err(JetstreamEventError::CompressionDecoderError)?;
477466478478- let event: JetstreamEvent<R> = serde_json::from_str(&json)
479479- .map_err(JetstreamEventError::ReceivedMalformedJSON)?;
480480- let event_cursor = event.cursor();
467467+ let event: JetstreamEvent = serde_json::from_str(&json).map_err(|e| {
468468+ eprintln!("lkasjdflkajsd {e:?} {json}");
469469+ JetstreamEventError::ReceivedMalformedJSON(e)
470470+ })?;
471471+ let event_cursor = event.cursor.clone();
481472482473 if let Some(last) = last_cursor {
483474 if event_cursor <= *last {
···11pub mod consumer;
22pub mod db_types;
33pub mod server;
44-pub mod store;
44+// pub mod storage;
55+pub mod storage_fjall;
56pub mod store_types;
6778use jetstream::events::Cursor;
+2-2
ufos/src/main.rs
···11use clap::Parser;
22use std::path::PathBuf;
33-use ufos::{consumer, server, store};
33+use ufos::{consumer, server, storage_fjall};
4455#[cfg(not(target_env = "msvc"))]
66use tikv_jemallocator::Jemalloc;
···43434444 let args = Args::parse();
4545 let (storage, cursor) =
4646- store::Storage::open(args.data, &args.jetstream, args.jetstream_force).await?;
4646+ storage_fjall::Storage::open(args.data, &args.jetstream, args.jetstream_force).await?;
47474848 println!("starting server with storage...");
4949 let serving = server::serve(storage.clone());