diff --git a/.direnv/flake-inputs/clgnapkqpby0ida8dkg5915w8x64l9ds-source b/.direnv/flake-inputs/clgnapkqpby0ida8dkg5915w8x64l9ds-source new file mode 120000 index 0000000..a19521b --- /dev/null +++ b/.direnv/flake-inputs/clgnapkqpby0ida8dkg5915w8x64l9ds-source @@ -0,0 +1 @@ +/nix/store/clgnapkqpby0ida8dkg5915w8x64l9ds-source \ No newline at end of file diff --git a/.direnv/flake-inputs/lvg59dwzvw3q6l1kpf4mirnzv2fflmra-source b/.direnv/flake-inputs/lvg59dwzvw3q6l1kpf4mirnzv2fflmra-source deleted file mode 120000 index afcf2c4..0000000 --- a/.direnv/flake-inputs/lvg59dwzvw3q6l1kpf4mirnzv2fflmra-source +++ /dev/null @@ -1 +0,0 @@ -/nix/store/lvg59dwzvw3q6l1kpf4mirnzv2fflmra-source \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 6c7edf5..08ae76b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "crates/tinkoff_invest/investapi"] path = crates/tinkoff_invest/investapi - url = https://github.com/tinkoff/investapi + url = https://github.com/russianinvestments/investapi diff --git a/Cargo.lock b/Cargo.lock index 50a73df..1a61380 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -206,6 +206,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bitflags" version = "1.3.2" @@ -1087,7 +1093,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", @@ -1103,6 +1109,21 @@ dependencies = [ "winreg", ] +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -1122,6 +1143,33 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.1.2", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -1131,6 +1179,33 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" + +[[package]] +name = "rustls-webpki" +version = "0.102.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.17" @@ -1287,12 +1362,24 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.66" @@ -1431,6 +1518,7 @@ dependencies = [ "mio", "pin-project-lite", "socket2", + "tokio-macros", "windows-sys 0.48.0", ] @@ -1444,6 +1532,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-macros" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tokio-native-tls" version = "0.3.1" @@ -1454,6 +1553,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.15" @@ -1497,7 +1607,11 @@ dependencies = [ "percent-encoding", "pin-project", "prost", + "rustls-native-certs", + "rustls-pemfile 2.1.2", + "rustls-pki-types", "tokio", + "tokio-rustls", "tokio-stream", "tower", "tower-layer", @@ -1623,6 +1737,12 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.0" @@ -1905,6 +2025,32 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[patch.unused]] +name = "careless" +version = "0.1.0" + +[[patch.unused]] +name = "photon" +version = "0.1.0" + +[[patch.unused]] +name = "photon_effects" +version = "0.1.0" + +[[patch.unused]] +name = "photon_wire" +version = "0.1.0" + +[[patch.unused]] +name = "photon_wire_derive" +version = "0.1.0" + [[patch.unused]] name = "funnylog" version = "0.1.0" @@ -1916,7 +2062,3 @@ version = "0.1.0" [[patch.unused]] name = "funnylog_macros" version = "0.1.0" - -[[patch.unused]] -name = "careless" -version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 81b1bc1..66b0a18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,6 @@ tinkoff_invest.path = "crates/tinkoff_invest" ## deps tokio = { version = "1", features = ["sync", "rt"] } futures-core = { version = "0.3", features = ["std"], default-features = false } -tonic = "0.11" +tonic = { version = "0.11", features = ["channel", "codegen", "prost", "tls", "tls-roots"] } prost = "0.12" prost-types = "0.12" diff --git a/crates/sanetrade/src/tinkoff.rs b/crates/sanetrade/src/tinkoff.rs index f48ba0c..ca2b9e1 100644 --- a/crates/sanetrade/src/tinkoff.rs +++ b/crates/sanetrade/src/tinkoff.rs @@ -1,14 +1,18 @@ +pub use tinkoff_invest::Account; use tinkoff_invest::{ instruments_service_client::InstrumentsServiceClient, - operations_service_client::OperationsServiceClient, users_service_client::UsersServiceClient, GetAccountsRequest, + market_data_service_client::MarketDataServiceClient, + market_data_stream_service_client::MarketDataStreamServiceClient, + operations_service_client::OperationsServiceClient, users_service_client::UsersServiceClient, + GetAccountsRequest, }; -pub use tinkoff_invest::Account; use tonic::{ service::{interceptor::InterceptedService, Interceptor}, transport::Channel, *, }; +use transport::ClientTlsConfig; #[derive(Debug)] pub struct TinkoffInterceptor { @@ -20,14 +24,14 @@ impl Interceptor for TinkoffInterceptor { let mut req = request; req.metadata_mut().append( "authorization", - format!("bearer {}", self.token).parse().unwrap(), + format!("bearer {}", self.token).parse().expect("failed to token"), ); req.metadata_mut().append( "x-tracking-id", uuid::Uuid::new_v4().to_string().parse().unwrap(), ); req.metadata_mut() - .append("x-app-name", "sanetrade".parse().unwrap()); + .append("x-app-name", "minky.sanetrade".parse().unwrap()); Ok(req) } @@ -52,11 +56,15 @@ impl TinkoffGenericClient { } pub async fn create_channel(&self) -> Result { + let tls = ClientTlsConfig::new(); + Ok(Channel::from_static(if self.sandbox { "https://sandbox-invest-public-api.tinkoff.ru:443" } else { "https://invest-public-api.tinkoff.ru:443" }) + .tls_config(tls) + .expect("tls?? hello??") .connect() .await?) } @@ -91,6 +99,28 @@ impl TinkoffGenericClient { }, ))) } + + pub async fn market_data(&self) -> Result { + Ok(TinkoffMarketDataClient( + MarketDataServiceClient::with_interceptor( + self.create_channel().await?, + TinkoffInterceptor { + token: self.token.clone(), + }, + ), + )) + } + + pub async fn market_data_stream(&self) -> Result { + Ok(TinkoffMarketDataStreamClient( + MarketDataStreamServiceClient::with_interceptor( + self.create_channel().await?, + TinkoffInterceptor { + token: self.token.clone(), + }, + ), + )) + } } pub struct TinkoffOperationsClient( @@ -105,8 +135,21 @@ pub struct TinkoffUsersClient( pub UsersServiceClient>, ); +pub struct TinkoffMarketDataClient( + pub MarketDataServiceClient>, +); + +pub struct TinkoffMarketDataStreamClient( + pub MarketDataStreamServiceClient>, +); + impl TinkoffUsersClient { pub async fn accounts(&mut self) -> Result, TinkoffError> { - Ok(self.0.get_accounts(GetAccountsRequest {}).await?.into_inner().accounts) + Ok(self + .0 + .get_accounts(GetAccountsRequest {}) + .await? + .into_inner() + .accounts) } }