Skip to content

Commit b593a80

Browse files
committed
feat: event subscriptions
1 parent 9216fd6 commit b593a80

File tree

9 files changed

+405
-253
lines changed

9 files changed

+405
-253
lines changed

iroh-willow/src/engine/actor.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ use crate::{
2222
},
2323
session::{intents::Intent, run_session, Error, EventSender, SessionHandle},
2424
store::{
25-
entry::EntryOrigin,
26-
traits::{EntryReader, SecretStorage, Storage},
25+
traits::{EntryOrigin, EntryReader, EntryStorage, SecretStorage, Storage},
2726
Store,
2827
},
2928
};
@@ -445,7 +444,7 @@ impl<S: Storage> Actor<S> {
445444
origin,
446445
reply,
447446
} => {
448-
let res = self.store.entries().ingest(&authorised_entry, origin);
447+
let res = self.store.entries().ingest_entry(&authorised_entry, origin);
449448
send_reply(reply, res)
450449
}
451450
Input::InsertEntry { entry, auth, reply } => {

iroh-willow/src/proto/grouping.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub type AreaOfInterest = willow_data_model::grouping::AreaOfInterest<
3737
>;
3838

3939
/// Extension methods for [`AreaOfInterest`].
40+
// TODO: Upstream to willow-rs as methods on [`AreaOfInterest].
4041
pub trait AreaOfInterestExt {
4142
/// Creates a new area of interest with the specified area and no other limits.
4243
fn with_area(area: Area) -> AreaOfInterest;
@@ -53,6 +54,7 @@ impl AreaOfInterestExt for AreaOfInterest {
5354
}
5455

5556
/// Extension methods for [`Area`].
57+
// TODO: Upstream to willow-rs as methods on [`Area`].
5658
pub trait AreaExt {
5759
/// Returns `true` if the area contains `point`.
5860
fn includes_point(&self, point: &Point) -> bool;
@@ -93,6 +95,7 @@ impl AreaExt for Area {
9395
/// A single point in the 3D range space.
9496
///
9597
/// I.e. an entry.
98+
// TODO: Upstream to willow-rs.
9699
#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
97100
pub struct Point {
98101
#[serde(with = "data_model::serde_encoding::path")]

iroh-willow/src/session/data.rs

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use futures_lite::StreamExt;
2-
use tokio::sync::broadcast;
32

43
use crate::{
54
proto::{
@@ -8,8 +7,7 @@ use crate::{
87
},
98
session::{channels::ChannelSenders, static_tokens::StaticTokens, Error, SessionId},
109
store::{
11-
entry::{EntryChannel, EntryOrigin},
12-
traits::Storage,
10+
traits::{EntryOrigin, EntryStorage, Storage, StoreEvent, SubscribeParams},
1311
Store,
1412
},
1513
util::stream::CancelableReceiver,
@@ -51,29 +49,36 @@ impl<S: Storage> DataSender<S> {
5149
}
5250
}
5351
pub async fn run(mut self) -> Result<(), Error> {
54-
let mut entry_stream = self.store.entries().subscribe(self.session_id);
52+
let mut entry_stream = futures_concurrency::stream::StreamGroup::new();
5553
loop {
5654
tokio::select! {
5755
input = self.inbox.next() => {
5856
let Some(input) = input else {
5957
break;
6058
};
6159
let Input::AoiIntersection(intersection) = input;
62-
self.store.entries().watch_area(
63-
self.session_id,
64-
intersection.namespace,
65-
intersection.intersection.area.clone(),
66-
);
60+
let params = SubscribeParams::default().ingest_only().ignore_remote(self.session_id);
61+
// TODO: We could start at the progress id at the beginning of the session.
62+
let stream = self
63+
.store
64+
.entries()
65+
.subscribe_area(
66+
intersection.namespace,
67+
intersection.intersection.area.clone(),
68+
params,
69+
)
70+
.filter_map(|event| match event {
71+
StoreEvent::Ingested(_id, entry, _origin) => Some(entry),
72+
// We get only Ingested events because we set ingest_only() param above.
73+
_ => unreachable!("expected only Ingested event but got another event"),
74+
});
75+
entry_stream.insert(stream);
6776
},
68-
entry = entry_stream.recv() => {
77+
entry = entry_stream.next(), if !entry_stream.is_empty() => {
6978
match entry {
70-
Ok(entry) => self.send_entry(entry).await?,
71-
Err(broadcast::error::RecvError::Closed) => break,
72-
Err(broadcast::error::RecvError::Lagged(_count)) => {
73-
// TODO: Queue another reconciliation
74-
}
79+
Some(entry) => self.send_entry(entry).await?,
80+
None => break,
7581
}
76-
7782
}
7883
}
7984
}
@@ -149,13 +154,9 @@ impl<S: Storage> DataReceiver<S> {
149154
message.dynamic_token,
150155
)
151156
.await?;
152-
self.store.entries().ingest(
153-
&authorised_entry,
154-
EntryOrigin::Remote {
155-
session: self.session_id,
156-
channel: EntryChannel::Data,
157-
},
158-
)?;
157+
self.store
158+
.entries()
159+
.ingest_entry(&authorised_entry, EntryOrigin::Remote(self.session_id))?;
159160
let (entry, _token) = authorised_entry.into_parts();
160161
// TODO: handle offset
161162
self.current_payload.set(

iroh-willow/src/session/reconciler.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ use crate::{
2929
Error, Role, SessionId,
3030
},
3131
store::{
32-
entry::{EntryChannel, EntryOrigin},
33-
traits::{EntryReader, EntryStorage, SplitAction, SplitOpts, Storage},
32+
traits::{EntryOrigin, EntryReader, EntryStorage, SplitAction, SplitOpts, Storage},
3433
Store,
3534
},
3635
util::{
@@ -164,12 +163,9 @@ impl<S: Storage> Reconciler<S> {
164163
authorised_entry.entry().payload_length(),
165164
message.entry.available,
166165
)?;
167-
self.shared.store.entries().ingest(
166+
self.shared.store.entries().ingest_entry(
168167
&authorised_entry,
169-
EntryOrigin::Remote {
170-
session: self.shared.session_id,
171-
channel: EntryChannel::Reconciliation,
172-
},
168+
EntryOrigin::Remote(self.shared.session_id),
173169
)?;
174170
}
175171
ReconciliationMessage::SendPayload(message) => {

iroh-willow/src/session/run.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -386,9 +386,6 @@ pub(crate) async fn run_session<S: Storage>(
386386
.try_join()
387387
.await;
388388

389-
// Unsubscribe from the store.
390-
store.entries().unsubscribe(&session_id);
391-
392389
// Track if we closed the session by triggering the cancel token, or if the remote peer closed
393390
// the session by closing the control channel.
394391
let we_cancelled = close_session_token.is_cancelled();

iroh-willow/src/store.rs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
77
use anyhow::{anyhow, Context, Result};
88
use rand_core::CryptoRngCore;
9+
use traits::EntryStorage;
910

1011
use crate::{
1112
form::{AuthForm, EntryForm, EntryOrForm, SubspaceForm, TimestampForm},
@@ -22,42 +23,40 @@ use crate::{
2223
use self::auth::{Auth, AuthError};
2324
use self::traits::Storage;
2425

25-
pub(crate) use self::entry::{EntryOrigin, WatchableEntryStore};
26+
pub(crate) use self::traits::EntryOrigin;
2627

2728
pub(crate) mod auth;
28-
pub(crate) mod entry;
2929
pub mod memory;
3030
pub mod traits;
3131

3232
/// Storage for the Willow engine.
33+
///
34+
/// Wraps a `Storage` instance and adds the [`Auth`] struct that uses the secret and caps storage to provide
35+
/// authentication when inserting entries.
3336
#[derive(Debug, Clone)]
3437
pub(crate) struct Store<S: Storage> {
35-
entries: WatchableEntryStore<S::Entries>,
36-
secrets: S::Secrets,
37-
payloads: S::Payloads,
38+
storage: S,
3839
auth: Auth<S>,
3940
}
4041

4142
impl<S: Storage> Store<S> {
4243
pub fn new(storage: S) -> Self {
4344
Self {
44-
entries: WatchableEntryStore::new(storage.entries().clone()),
45-
secrets: storage.secrets().clone(),
46-
payloads: storage.payloads().clone(),
4745
auth: Auth::new(storage.secrets().clone(), storage.caps().clone()),
46+
storage,
4847
}
4948
}
5049

51-
pub fn entries(&self) -> &WatchableEntryStore<S::Entries> {
52-
&self.entries
50+
pub fn entries(&self) -> &S::Entries {
51+
self.storage.entries()
5352
}
5453

5554
pub fn secrets(&self) -> &S::Secrets {
56-
&self.secrets
55+
self.storage.secrets()
5756
}
5857

5958
pub fn payloads(&self) -> &S::Payloads {
60-
&self.payloads
59+
self.storage.payloads()
6160
}
6261

6362
pub fn auth(&self) -> &Auth<S> {
@@ -97,7 +96,7 @@ impl<S: Storage> Store<S> {
9796
let authorised_entry = AuthorisedEntry::new_unchecked(entry, token);
9897
let inserted = self
9998
.entries()
100-
.ingest(&authorised_entry, EntryOrigin::Local)?;
99+
.ingest_entry(&authorised_entry, EntryOrigin::Local)?;
101100
Ok((authorised_entry, inserted))
102101
}
103102

@@ -118,7 +117,7 @@ impl<S: Storage> Store<S> {
118117
/// the provided [`Store`].
119118
///
120119
/// `user_id` must be set to the user who is authenticating the entry.
121-
pub async fn form_to_entry(
120+
async fn form_to_entry(
122121
&self,
123122
form: EntryForm,
124123
user_id: UserId, // auth: AuthForm,

0 commit comments

Comments
 (0)