Skip to main content

LseSubscriber

Struct LseSubscriber 

Source
pub struct LseSubscriber { /* private fields */ }
Expand description

The London Strategic Edge WebSocket subscriber.

§Why this provider needs a subscriber of its own

Authentication is a message, not a header, and subscriptions are only accepted after the server answers it — so Connector::requests alone cannot express the flow.

The handshake also produces something the guards below need: the authenticated frame enumerates every symbol the key may subscribe to. That list is the only defence against this surface’s quietest failure — see Self::subscribe.

§⚠️ One connection per key: clone the subscriber, do not build a second one

The provider allows a key one WebSocket, so every stream this subscriber and its clones open shares one socket — whatever the dataset, the kind or the option underlying, and across every subscribe call. StreamBuilder::subscribe clones the subscriber it is given, so passing one subscriber, or clones of it, to every call is all sharing takes. See connection for how the socket is shared, how a reconnect is coordinated across the streams on it, and what the shared subscription cap means for a batch.

A subscriber built separately — a second LseSubscriber::new or LseSubscriber::from_env for the same key — opens a socket of its own, and the provider refuses it with TOO_MANY_CONNECTIONS.

§Example

ⓘ
use rustrade_data::exchange::lse::{LseCrypto, live::LseSubscriber};
use rustrade_data::streams::Streams;
use rustrade_data::subscription::trade::PublicTrades;
use rustrade_instrument::instrument::market_data::kind::MarketDataInstrumentKind;

let subscriber = LseSubscriber::from_env()?;

let streams = Streams::<PublicTrades>::builder()
    .subscribe(subscriber, [(
        LseCrypto::default(), "btc", "usd", MarketDataInstrumentKind::Spot, PublicTrades,
    )])
    .init()
    .await?;

Implementations§

Source§

impl LseSubscriber

Source

pub fn new(credentials: LseCredentials) -> Self

Construct a subscriber with the provided credentials, without resumption.

Each call opens a connection of its own when first used; clone the result to share it.

Source

pub fn from_env() -> Result<Self, SocketError>

Construct a subscriber from the LSE_API_KEY environment variable.

§Errors

See LseCredentials::from_env.

Source

pub fn with_resume(self, state: Arc<LseResumeState>) -> Self

Resume from the last delivered event when a reconnect re-subscribes.

Every stream opened by this subscriber shares state, and the same subscriber instance is cloned into each reconnect attempt, so the watermark it accumulates survives the reconnect that consults it.

§⚠️ Replay is not free, which is why this is opt-in

A resumed subscription is served its historical window before a single live tick. That window is large: one hour of a single busy crypto symbol replayed 107,395 ticks before going live, and a 24-hour window had not drained after 30 seconds. A consumer that must stay current will prefer the gap; a consumer recording a continuous tape will prefer the replay. Choosing between those is the caller’s business, so the default is off.

§⚠️ The provider retains only 24 hours, and clamps silently

A resume point older than that is moved forward with no error. The stream compares what the provider says it will replay from against what was asked for and warns on a mismatch; see LseMessage::ReplayStarted.

§⚠️ One state per duplicated subscription

Watermarks are keyed by dataset, subscription and subscription kind, so one state serves any set of streams that differ in any of those three. Two streams that duplicate all three share one watermark and advance it independently, which resumes the trailing one past events it never delivered — see LseResumeState for the obligation in full.

§⚠️ The replayed prefix is skipped by position, not by the replay flag

The provider re-serves every tick sharing the resume instant, and the ones already delivered are dropped by counting rather than by trusting each tick’s replay stamp — a provider that stopped stamping them would otherwise turn every reconnect into a duplicate flood. The cost is a narrow one: if the replay under-delivers at that instant, a genuinely live tick arriving there while the count is still open is dropped as though it were one of the missing duplicates. It requires the whole reconnect to land inside one timestamp quantum of the resume instant, so it is unlikely rather than impossible, and it is reported by a warn! naming the subscription and the instant rather than passing silently.

§Streams sharing a symbol share its replay window

Streams on one connection that hold one symbol — two kinds, or two datasets spelling it alike — hold one provider subscription to it, and the provider opens one replay window per subscription. A reconnect therefore opens each symbol’s window at the earliest watermark among the streams holding it, and every stream drops, silently, the replayed ticks before its own watermark: it delivered them before the connection was lost. Replayed ticks reach only the streams that resume that symbol. See connection.

A clone made before this call shares the connection but not the state. That is supported — each stream resumes from its own subscriber’s state — but it is rarely what was meant.

Covers reconnects, not process restarts; see LseResumeState.

Trait Implementations§

Source§

impl Clone for LseSubscriber

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for LseSubscriber

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Subscriber for LseSubscriber

Source§

async fn subscribe<Exchange, Instrument, Kind>( &self, subscriptions: &[Subscription<Exchange, Instrument, Kind>], ) -> Result<Subscribed<Instrument::Key, Self::Transport>, SocketError>
where Exchange: Connector + Send + Sync, Kind: SubscriptionKind + Send + Sync, Instrument: InstrumentData, Subscription<Exchange, Instrument, Kind>: Identifier<Exchange::Channel> + Identifier<Exchange::Market>,

Attach the batch to this subscriber’s shared connection — connecting and authenticating first if nothing is attached yet — check it, then subscribe whatever the connection does not already hold.

§⚠️ Every guard runs before the first subscribe leaves the client, deliberately

This surface confirms a subscription to a symbol it has never heard of: it answers subscribed, never errors, never ticks, and holds one of the connection’s slots until it is unsubscribed — which nothing would prompt, since a confirmation is all the client ever sees. So the requested symbols are checked against the list the authenticated frame supplies first, and a batch that fails costs nothing.

Two checks run over that list:

  • Membership is enforced. A symbol the provider does not offer fails the batch.
  • The category is only cross-checked when the provider supplies a label this integration recognises. Roughly half the published entries carry no category key at all — and some carry neither category nor name — so absence is normal and can never be treated as a mismatch. Neither can a label we do not know: only one we recognise as belonging to a different dataset is evidence of anything.

The subscription cap is enforced in the same pass, because an over-cap batch is rejected anonymously: the provider’s rejection does not name the symbol it refused, leaving no partial recovery. Failing the whole batch before sending is the only outcome that does not leave the caller guessing which subscriptions survived.

§⚠️ The cap is the connection’s, not the batch’s

Every stream sharing the connection draws on one subscription cap, so a batch is checked against what the connection would hold with it: the symbols and underlyings already held by other streams count, and a symbol one of them already holds costs nothing more. A batch that fits on its own can therefore be refused here.

Should the provider reject a subscribe anyway, the batch fails and whatever it sent is unsubscribed again, so a failed batch still holds no slot.

§Option contracts subscribe per underlying

On LseOptions one subscribe covers an underlying’s whole chain, so the batch is reduced to its distinct underlyings: that is what is sent, what the cap counts, and what the provider confirms. Every contract must spell an OSI symbol, checked before connecting. The offered-symbol check does not apply: the handshake’s list does not hold every underlying that has options (index roots are absent from it), and an underlying with no options is rejected by the provider by name rather than confirmed.

§Errors

Returns SocketError::Subscribe if the batch is empty, the key is rejected, the handshake times out, the batch would take the connection over its subscription cap, any requested symbol is not offered, or — on the options dataset — any contract has no OSI symbol or names an underlying with no options.

Source§

type SubMapper = LseSubMapper

Source§

type Transport = LseAttachment

What a successful subscribe hands the stream to read from. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> AttachedTransformer<()> for T

Source§

fn attached(&mut self, _: ())

Take what the connection handed the stream on attaching.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Conv for T

Source§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
Source§

impl<T> FmtForward for T

Source§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
Source§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
Source§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
Source§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
Source§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
Source§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
Source§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
Source§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
Source§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> JsonSchemaMaybe for T

Source§

impl<T> Pipe for T
where T: ?Sized,

Source§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
Source§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
Source§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
Source§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows self, then passes self.as_ref() into the pipe function.
Source§

fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.as_mut() into the pipe function.
Source§

fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
Source§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> Tap for T

Source§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
Source§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
Source§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
Source§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
Source§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
Source§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
Source§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
Source§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
Source§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
Source§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .tap_borrow() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Calls .tap_ref() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> TryConv for T

Source§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more