1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
//! A synchronous façade over the async clients.
//!
//! # Why this is one type and not a mirrored API
//!
//! The obvious shape for this feature is a `BlockingTradingClient` with a
//! synchronous copy of every method, which is what most SDKs do. This crate
//! covers 251 routes; mirroring them would double the surface that has to stay
//! correct, and the copy would drift from the original the first time a route
//! was added to one and not the other.
//!
//! [`Blocking`] wraps any of the clients instead and runs one call at a time.
//! Every route is reachable through it the day it is added to the async client,
//! and there is nothing to keep in sync:
//!
//! ```no_run
//! use alpaca_sdk::blocking::Blocking;
//! use alpaca_sdk::trading::TradingClient;
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let credentials = alpaca_sdk::Credentials::from_env()?;
//! let client = Blocking::new(TradingClient::new(&credentials, true)?)?;
//!
//! let account = client.call(|client| client.get_account())?;
//! println!("{}", account.id);
//! # Ok(())
//! # }
//! ```
//!
//! # Streams stay async
//!
//! This wraps request/response calls. The websocket and SSE streams are
//! [`Stream`](futures_util::Stream)s with no synchronous equivalent worth
//! pretending to — a blocking iterator over a live market data feed would
//! deadlock the moment the caller took longer than the socket's read buffer.
use Future;
use ;
use crate;
/// Whether a caught panic is tokio's "runtime inside a runtime" complaint.
///
/// Matched on the message rather than a type, because that is all tokio gives:
/// it panics with a `&str`/`String` payload beginning
/// `Cannot start a runtime from within a runtime`. Matching on a substring is
/// fragile against a tokio reword, and the failure mode of a reword is that a
/// misuse resurfaces as the original panic — loud and accurate — rather than as
/// a wrong error. That is the right direction to fail in.
///
/// Takes `&(dyn Any + Send)` and must be called as `&*panic`, not `&panic`:
/// `Box<dyn Any + Send>` itself implements `Any`, so passing the box by
/// reference downcasts *the box* and never matches.
/// Runs an async client's calls to completion on a runtime it owns.
///
/// See the [module documentation](self) for why this is one wrapper rather than
/// a synchronous copy of every method.
///
/// # The async-context trap
///
/// Tokio panics in *two* places when a runtime meets an async context, and both
/// are reachable by a caller who tries this inside an `#[tokio::main]` fn:
///
/// - Blocking on a runtime from inside another runtime's thread.
/// [`call`](Self::call) catches that panic and returns
/// [`Error::InvalidRequest`] instead. In an async context, use the async
/// client directly — it is what this is wrapping.
///
/// Two consequences worth knowing. Tokio's panic hook runs *before* the
/// panic is caught, so a misuse prints "Cannot start a runtime from within a
/// runtime" and a backtrace to stderr and then returns the error — where the
/// old pre-check returned quietly. And **under `panic = "abort"` the recovery
/// does not exist at all**: `catch_unwind` catches nothing there, so the
/// misuse aborts the process rather than returning an error. That is a deliberate trade: the alternative is a
/// pre-check that cannot distinguish an async fn from a `spawn_blocking`
/// closure, and so rejects the supported bridge below. Calling the façade
/// from an async context is a programming error either way; on an abort
/// profile it is a loud one.
///
/// The exception is [`tokio::task::spawn_blocking`], which is the supported
/// bridge from an async program into this façade: those threads are not
/// driving the reactor, so blocking on them is allowed and a call made there
/// succeeds. They do carry an ambient runtime handle, which is why the check
/// is tokio's rather than a test for one.
/// - *Dropping* a runtime from inside one. This is the easier of the two to hit
/// by accident, because it needs no call at all: constructing a `Blocking` in
/// an async fn and letting it fall out of scope is enough. The runtime is shut
/// down in the background on drop, which is allowed anywhere, so this one
/// cannot happen.