1#![doc = include_str!("../README.md")]
2use requestor::AnyRequestor;
3use stream::AnyStream;
4use t_types::Quotation;
5use tonic::codec::CompressionEncoding::Gzip as GZIP;
6use tonic::service::interceptor::InterceptedService;
7use tonic::service::Interceptor;
8use tonic::transport::{Channel, ClientTlsConfig};
9use tonic::{Request, Status};
10use uuid::Uuid;
11use tonic::client::Grpc;
12
13pub type Api = Grpc<IService>;
26
27pub use sandbox::Sandbox as SandboxApi;
42
43pub use pool::ApiPool;
44
45pub mod t_types;
46pub mod requestor;
47pub mod stream;
48pub mod stream_response;
49pub mod pool;
50
51mod sandbox;
52mod quotation;
53
54pub type IService = InterceptedService<Channel, TokenInterceptor>;
55pub trait InvestService: Sized {
57 fn create_invest_service(token: impl ToString) -> Result<Self, tonic::transport::Error>;
58}
59
60impl InvestService for IService {
61 fn create_invest_service(token: impl ToString) -> Result<Self, tonic::transport::Error> {
62 let tls = ClientTlsConfig::new().with_native_roots();
63 let channel = Channel::from_static("https://invest-public-api.tinkoff.ru").tls_config(tls)?.connect_lazy();
64 Ok(InterceptedService::new(channel, TokenInterceptor::new(token)))
65 }
66}
67impl InvestService for Grpc<IService> {
68 fn create_invest_service(token: impl ToString) -> Result<Self, tonic::transport::Error> {
69 let serv = InterceptedService::create_invest_service(token)?;
70 let res = Grpc::new(serv).accept_compressed(GZIP).send_compressed(GZIP);
71 Ok(res)
72 }
73}
74
75#[derive(Debug, Clone)]
76pub struct TokenInterceptor {
77 token: String,
78}
79
80impl TokenInterceptor {
81 pub fn new(token: impl ToString) -> Self {
82 Self { token: token.to_string() }
83 }
84}
85
86impl Interceptor for TokenInterceptor {
87 fn call(&mut self, mut req: Request<()>) -> Result<Request<()>, Status> {
88 req.metadata_mut().append(
89 "authorization",
90 format!("bearer {}", self.token).parse().unwrap(),
91 );
92 req.metadata_mut()
93 .append("x-tracking-id", Uuid::new_v4().to_string().parse().unwrap());
94 Ok(req)
95 }
96}
97
98pub use requestor::Requestor;
99pub use stream::StartStream;
100pub use stream_response::StreamResponse;
101
102pub trait InvestApi: AnyRequestor + AnyStream<StreamResponse> + Send + 'static {}
132impl<T> InvestApi for T where T: AnyRequestor + AnyStream<StreamResponse> + Send + 'static {}
133
134pub trait QuotationExt {
135 fn floor(&self, increment: Quotation) -> Self;
136 fn round(&self, increment: Quotation) -> Self;
137}