pub struct TbankRaw { /* private fields */ }Expand description
Direct access to any T-Bank API method, made by MarketDataConnector::raw or
UserDataConnector::raw. See the module docs. Cheap to clone.
Reads go through call. Anything that changes the account goes through
call_command, which never lets a lost answer look like a refusal.
§Examples
A command that the broker refuses is [Error::Rejected]. Here the order does not exist.
use brokapi_core::Error;
use brokapi_runtime::BrokerLimiter;
use brokapi_tbank::limits::default_limits;
use brokapi_tbank::{UserDataConfig, UserDataConnector};
use brokapi_tbank_protocol::v1 as pb;
use tokio::sync::mpsc;
let (events_tx, _events) = mpsc::channel(64);
let limiter = BrokerLimiter::new(&default_limits());
let ud = UserDataConnector::start(UserDataConfig::new(cfg, "tbank-ud"), limiter, events_tx).await?;
let raw = ud.raw();
let account = raw.account_id().expect("a user data connector has an account").to_string();
let result = raw
.call_command("CancelOrder", |c| async move {
c.orders()
.cancel_order(pb::CancelOrderRequest {
account_id: account,
order_id: "no-such-order".into(),
order_id_type: Some(pb::OrderIdType::Request as i32),
})
.await
})
.await;
assert!(matches!(result, Err(Error::Rejected { .. })));Implementations§
Source§impl TbankRaw
impl TbankRaw
Sourcepub fn account_id(&self) -> Option<&str>
pub fn account_id(&self) -> Option<&str>
Account of the connector this came from (user data connector only).
None for a market data connector, which has no account. The raw layer does not add the
account to your requests: put it into the request yourself.
§Examples
use brokapi_runtime::BrokerLimiter;
use brokapi_tbank::limits::default_limits;
use brokapi_tbank::{MarketDataConfig, MarketDataConnector};
use tokio::sync::mpsc;
let (events_tx, _events) = mpsc::channel(64);
let md = MarketDataConnector::start(
MarketDataConfig::new(cfg, "tbank-md"),
BrokerLimiter::new(&default_limits()),
events_tx,
)
.await?;
assert_eq!(md.raw().account_id(), None);Sourcepub fn timeout(&self) -> Duration
pub fn timeout(&self) -> Duration
The deadline applied to every call: the request_timeout of the connector’s config (30 s by
default).
§Examples
use std::time::Duration;
use brokapi_runtime::BrokerLimiter;
use brokapi_tbank::limits::default_limits;
use brokapi_tbank::{MarketDataConfig, MarketDataConnector};
use tokio::sync::mpsc;
let (events_tx, _events) = mpsc::channel(64);
let md = MarketDataConnector::start(
MarketDataConfig::new(cfg, "tbank-md"),
BrokerLimiter::new(&default_limits()),
events_tx,
)
.await?;
assert_eq!(md.raw().timeout(), Duration::from_secs(5));Sourcepub async fn call<T, F, Fut>(&self, method: &str, f: F) -> Result<T, Error>
pub async fn call<T, F, Fut>(&self, method: &str, f: F) -> Result<T, Error>
Reads: takes quota for method, runs the call, maps errors.
For a server-streaming method the result type is tonic::Streaming<_>: the quota covers
opening the stream, the stream is then yours to read.
§Errors
- [
Error::RateLimited] when the limiter has no quota formethod. The request is not sent. Waitretry_afterand call again. - [
Error::Transport] on a timeout or a network status. A read may be repeated. - [
Error::Rejected] when the broker refuses the request (InvalidArgument,NotFound, which is the codenot_found,PermissionDenied, …). - [
Error::Config] when the token is not accepted (Unauthenticated).
§Examples
use brokapi_core::Error;
use brokapi_runtime::BrokerLimiter;
use brokapi_tbank::limits::limits_from_toml_str;
use brokapi_tbank::{MarketDataConfig, MarketDataConnector};
use brokapi_tbank_protocol::v1 as pb;
use tokio::sync::mpsc;
// A tiny quota for the demo: one call per minute for every method.
let limits = limits_from_toml_str(
r#"
[tbank.buckets.one]
rate = 1
per = "60s"
burst = 1
[tbank.route]
"*" = ["one"]
[tbank.conns]
max_conns = 1
max_subs_per_conn = 1
supports_multiplex = false
"#,
)?;
let (events_tx, _events) = mpsc::channel(64);
let md = MarketDataConnector::start(MarketDataConfig::new(cfg, "tbank-md"), BrokerLimiter::new(&limits), events_tx).await?;
let raw = md.raw();
let list = |c: brokapi_tbank_protocol::TbankClient| async move {
c.users().get_accounts(pb::GetAccountsRequest { status: None }).await
};
assert!(raw.call("GetAccounts", list).await.is_ok());
// The second call finds the bucket empty: it is refused locally and never sent.
assert!(matches!(raw.call("GetAccounts", list).await, Err(Error::RateLimited { .. })));Sourcepub async fn call_command<T, F, Fut>(
&self,
method: &str,
f: F,
) -> Result<T, Error>
pub async fn call_command<T, F, Fut>( &self, method: &str, f: F, ) -> Result<T, Error>
Commands: like call, but a timeout, a break or a server fault is
Error::Unknown, because the broker may have executed the command. Never retried.
§Errors
- [
Error::RateLimited] when the limiter has no quota. Nothing was sent. - [
Error::Rejected] when the broker refuses (InvalidArgument,NotFound,PermissionDenied,FailedPrecondition, …). The broker did not act. - [
Error::Config] when the token is not accepted. The broker did not act. - [
Error::Unknown] on a timeout, a broken connection or a server fault (Unavailable,Internal, …). The command may or may not have been done. Do not repeat it. Ask the broker for the state of the order or account first.
§Examples
use brokapi_core::Error;
use brokapi_runtime::BrokerLimiter;
use brokapi_tbank::limits::default_limits;
use brokapi_tbank::{UserDataConfig, UserDataConnector};
use brokapi_tbank_protocol::v1 as pb;
use tokio::sync::mpsc;
let (events_tx, _events) = mpsc::channel(64);
let limiter = BrokerLimiter::new(&default_limits());
let ud = UserDataConnector::start(UserDataConfig::new(cfg, "tbank-ud"), limiter, events_tx).await?;
// Cancelling an order the broker does not know is a definite refusal.
let outcome = ud
.raw()
.call_command("CancelOrder", |c| async move {
c.orders()
.cancel_order(pb::CancelOrderRequest {
account_id: ACCOUNT_A.into(),
order_id: "no-such-order".into(),
order_id_type: Some(pb::OrderIdType::Request as i32),
})
.await
})
.await;
match outcome {
Err(Error::Rejected { code, .. }) => assert_eq!(code, "not_found"),
other => panic!("expected a refusal, got {other:?}"),
}Trait Implementations§
Auto Trait Implementations§
impl !Freeze for TbankRaw
impl !RefUnwindSafe for TbankRaw
impl !UnwindSafe for TbankRaw
impl Send for TbankRaw
impl Sync for TbankRaw
impl Unpin for TbankRaw
impl UnsafeUnpin for TbankRaw
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request§impl<L> LayerExt<L> for L
impl<L> LayerExt<L> for L
§fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
Layered].