Skip to content

Commit 2bae7e2

Browse files
committed
feat(server)!: convert display traits to ServerResult, drop anyhow dep
Final step of the staged migration started in #1242, continued in Public API changes: RdpServerDisplay::updates -> Result<Box<dyn RdpServerDisplayUpdates>, anyhow::Error> => ServerResult<Box<dyn RdpServerDisplayUpdates>> RdpServerDisplayUpdates::next_update -> Result<Option<DisplayUpdate>, anyhow::Error> => ServerResult<Option<DisplayUpdate>> These are breaking changes for handler implementations of the two display traits. Internal changes: - The from_anyhow private bridge and the AnyhowError wrapper struct in error.rs are removed. - The anyhow dependency is removed from ironrdp-server/Cargo.toml. - builder.rs's NoopDisplayUpdates / NoopDisplay impls and the docstring example in display.rs and README.md are updated to match the new trait shapes. - The example in crates/ironrdp/examples/server.rs and the integration test in crates/ironrdp-testsuite-extra/tests/main.rs are updated to return ServerResult from their RdpServerDisplay/Updates impls. - benches/src/perfenc.rs is updated to construct ServerError variants instead of anyhow::Error and converts at its own anyhow::Result main boundary via .map_err(|e| anyhow::anyhow!(e)). After this commit, ironrdp-server has no anyhow dependency and the public surface is fully typed against ServerError. Closes #1209.
1 parent 32cecee commit 2bae7e2

10 files changed

Lines changed: 43 additions & 69 deletions

File tree

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

benches/src/perfenc.rs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,14 @@ async fn main() -> Result<(), anyhow::Error> {
6060
};
6161

6262
let mut encoder = UpdateEncoder::new(DesktopSize { width, height }, flags, update_codecs, 8 * 1024 * 1024)
63+
.map_err(|e| anyhow::anyhow!(e))
6364
.context("failed to initialize update encoder")?;
6465

6566
let mut total_raw = 0u64;
6667
let mut total_enc = 0u64;
6768
let mut n_updates = 0u64;
6869
let mut updates = DisplayUpdates::new(file, DesktopSize { width, height }, fps);
69-
while let Some(up) = updates.next_update().await? {
70+
while let Some(up) = updates.next_update().await.map_err(|e| anyhow::anyhow!(e))? {
7071
if let DisplayUpdate::Bitmap(ref up) = up {
7172
total_raw += u64::try_from(up.data.len())?;
7273
} else {
@@ -78,7 +79,7 @@ async fn main() -> Result<(), anyhow::Error> {
7879
let Some(frag) = iter.next().await else {
7980
break;
8081
};
81-
let len = u64::try_from(frag?.data.len())?;
82+
let len = u64::try_from(frag.map_err(|e| anyhow::anyhow!(e))?.data.len())?;
8283
total_enc += len;
8384
}
8485
n_updates += 1;
@@ -121,12 +122,17 @@ impl DisplayUpdates {
121122

122123
#[async_trait::async_trait]
123124
impl RdpServerDisplayUpdates for DisplayUpdates {
124-
async fn next_update(&mut self) -> anyhow::Result<Option<DisplayUpdate>> {
125+
async fn next_update(&mut self) -> ironrdp::server::ServerResult<Option<DisplayUpdate>> {
126+
use ironrdp::server::ServerErrorExt as _;
127+
125128
let stride = self.desktop_size.width as usize * 4;
126129
let frame_size = stride * self.desktop_size.height as usize;
127130
let mut buf = vec![0u8; frame_size];
128131
// FIXME: AsyncReadExt::read_exact is not cancellation safe.
129-
self.file.read_exact(&mut buf).await.context("read exact")?;
132+
self.file
133+
.read_exact(&mut buf)
134+
.await
135+
.map_err(|e| ironrdp::server::ServerError::io("read exact", e))?;
130136

131137
let now = Instant::now();
132138
if let Some(last_update_time) = self.last_update_time {
@@ -135,7 +141,7 @@ impl RdpServerDisplayUpdates for DisplayUpdates {
135141
sleep(Duration::from_millis(
136142
1000 / self.fps
137143
- u64::try_from(elapsed.as_millis())
138-
.context("invalid `elapsed millis`: out of range integral conversion")?,
144+
.map_err(|e| ironrdp::server::ServerError::custom("invalid `elapsed millis`", e))?,
139145
))
140146
.await;
141147
}
@@ -145,11 +151,14 @@ impl RdpServerDisplayUpdates for DisplayUpdates {
145151
let up = DisplayUpdate::Bitmap(BitmapUpdate {
146152
x: 0,
147153
y: 0,
148-
width: NonZeroU16::new(self.desktop_size.width).context("width cannot be zero")?,
149-
height: NonZeroU16::new(self.desktop_size.height).context("height cannot be zero")?,
154+
width: NonZeroU16::new(self.desktop_size.width)
155+
.ok_or_else(|| ironrdp::server::ServerError::reason("perfenc", "width cannot be zero"))?,
156+
height: NonZeroU16::new(self.desktop_size.height)
157+
.ok_or_else(|| ironrdp::server::ServerError::reason("perfenc", "height cannot be zero"))?,
150158
format: PixelFormat::RgbX32,
151159
data: buf.into(),
152-
stride: NonZeroUsize::new(stride).context("stride cannot be zero")?,
160+
stride: NonZeroUsize::new(stride)
161+
.ok_or_else(|| ironrdp::server::ServerError::reason("perfenc", "stride cannot be zero"))?,
153162
});
154163
Ok(Some(up))
155164
}

crates/ironrdp-server/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ nscodec = ["dep:ironrdp-nscodec"]
3333
__bench = ["dep:visibility"]
3434

3535
[dependencies]
36-
anyhow = "1.0"
3736
tokio = { version = "1", features = ["net", "macros", "sync", "rt"] } # public
3837
tokio-rustls = "0.26" # public
3938
async-trait = "0.1"

crates/ironrdp-server/README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ This crate is part of the [IronRDP] project.
3131
Enable the `echo` feature to use the ECHO dynamic virtual channel (`MS-RDPEECO`) and measure round-trip time.
3232

3333
```rust
34-
use ironrdp_server::RdpServer;
34+
use ironrdp_server::{RdpServer, ServerError, ServerErrorExt as _, ServerResult};
3535

36-
# async fn demo(mut server: RdpServer) -> anyhow::Result<()> {
36+
# async fn demo(mut server: RdpServer) -> ServerResult<()> {
3737
// Grab and clone the shared handle before moving the server into a task.
3838
let echo = server.echo_handle().clone();
3939

@@ -54,8 +54,10 @@ local
5454
}
5555
}
5656

57-
server_task.await??;
58-
Ok::<(), anyhow::Error>(())
57+
server_task
58+
.await
59+
.map_err(|e| ServerError::custom("server task", e))??;
60+
Ok::<(), ServerError>(())
5961
})
6062
.await?;
6163
# Ok(()) }

crates/ironrdp-server/src/builder.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use core::net::SocketAddr;
22
use core::sync::atomic::{AtomicBool, AtomicU32};
33
use std::sync::Arc;
44

5-
use anyhow::Result;
65
use ironrdp_pdu::rdp::capability_sets::{BitmapCodecs, server_codecs_capabilities};
76
use tokio_rustls::TlsAcceptor;
87

@@ -12,6 +11,7 @@ use super::display::{DesktopSize, RdpServerDisplay};
1211
use super::gfx::GfxServerFactory;
1312
use super::handler::{KeyboardEvent, MouseEvent, RdpServerInputHandler};
1413
use super::server::{ConnectionHandler, CredentialValidator, RdpServer, RdpServerOptions, RdpServerSecurity};
14+
use crate::error::ServerResult;
1515
use crate::{DisplayUpdate, RdpServerDisplayUpdates, SoundServerFactory};
1616

1717
pub struct WantsAddr {}
@@ -289,7 +289,7 @@ struct NoopDisplayUpdates;
289289

290290
#[async_trait::async_trait]
291291
impl RdpServerDisplayUpdates for NoopDisplayUpdates {
292-
async fn next_update(&mut self) -> Result<Option<DisplayUpdate>> {
292+
async fn next_update(&mut self) -> ServerResult<Option<DisplayUpdate>> {
293293
let () = core::future::pending().await;
294294
unreachable!()
295295
}
@@ -303,7 +303,7 @@ impl RdpServerDisplay for NoopDisplay {
303303
DesktopSize { width: 0, height: 0 }
304304
}
305305

306-
async fn updates(&mut self) -> Result<Box<dyn RdpServerDisplayUpdates>> {
306+
async fn updates(&mut self) -> ServerResult<Box<dyn RdpServerDisplayUpdates>> {
307307
Ok(Box::new(NoopDisplayUpdates {}))
308308
}
309309
}

crates/ironrdp-server/src/display.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use core::num::{NonZeroU16, NonZeroUsize};
22

3-
use anyhow::Result;
43
use bytes::{Bytes, BytesMut};
54
use ironrdp_displaycontrol::pdu::DisplayControlMonitorLayout;
65
use ironrdp_graphics::diff;
76
use ironrdp_pdu::pointer::PointerPositionAttribute;
87
use tracing::{debug, warn};
98

9+
use crate::error::ServerResult;
10+
1011
#[rustfmt::skip]
1112
pub use ironrdp_acceptor::DesktopSize;
1213
pub use ironrdp_graphics::image_processing::PixelFormat;
@@ -246,24 +247,23 @@ pub trait RdpServerDisplayUpdates {
246247
/// This method MUST be cancellation safe because it is used in a
247248
/// `tokio::select!` statement. If some other branch completes first, it
248249
/// MUST be guaranteed that no data is lost.
249-
async fn next_update(&mut self) -> Result<Option<DisplayUpdate>>;
250+
async fn next_update(&mut self) -> ServerResult<Option<DisplayUpdate>>;
250251
}
251252

252253
/// Display for an RDP server
253254
///
254255
/// # Example
255256
///
256257
/// ```
257-
///# use anyhow::Result;
258-
/// use ironrdp_server::{DesktopSize, DisplayUpdate, RdpServerDisplay, RdpServerDisplayUpdates};
258+
/// use ironrdp_server::{DesktopSize, DisplayUpdate, RdpServerDisplay, RdpServerDisplayUpdates, ServerResult};
259259
///
260260
/// pub struct DisplayUpdates {
261261
/// receiver: tokio::sync::mpsc::Receiver<DisplayUpdate>,
262262
/// }
263263
///
264264
/// #[async_trait::async_trait]
265265
/// impl RdpServerDisplayUpdates for DisplayUpdates {
266-
/// async fn next_update(&mut self) -> anyhow::Result<Option<DisplayUpdate>> {
266+
/// async fn next_update(&mut self) -> ServerResult<Option<DisplayUpdate>> {
267267
/// Ok(self.receiver.recv().await)
268268
/// }
269269
/// }
@@ -279,7 +279,7 @@ pub trait RdpServerDisplayUpdates {
279279
/// DesktopSize { width: self.width, height: self.height }
280280
/// }
281281
///
282-
/// async fn updates(&mut self) -> Result<Box<dyn RdpServerDisplayUpdates>> {
282+
/// async fn updates(&mut self) -> ServerResult<Box<dyn RdpServerDisplayUpdates>> {
283283
/// Ok(Box::new(DisplayUpdates { receiver: todo!() }))
284284
/// }
285285
/// }
@@ -298,7 +298,7 @@ pub trait RdpServerDisplay: Send {
298298
}
299299

300300
/// Return a display updates receiver
301-
async fn updates(&mut self) -> Result<Box<dyn RdpServerDisplayUpdates>>;
301+
async fn updates(&mut self) -> ServerResult<Box<dyn RdpServerDisplayUpdates>>;
302302

303303
/// Request a new size for the display
304304
fn request_layout(&mut self, layout: DisplayControlMonitorLayout) {

crates/ironrdp-server/src/error.rs

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -174,36 +174,3 @@ impl<T> ServerResultExt for ServerResult<T> {
174174
self.map_err(|e| e.with_source(source))
175175
}
176176
}
177-
178-
/// Bridges anyhow errors at the public API boundary while the migration to
179-
/// typed errors is staged.
180-
///
181-
/// Internal call sites still use `anyhow::Result`; conversion happens here so
182-
/// the public signatures can advertise [`ServerResult`] today without forcing
183-
/// every internal site to convert in this PR. PR #2 in the staged migration
184-
/// (see [#1209]) removes the remaining `anyhow` usage and this helper.
185-
///
186-
/// [#1209]: https://github.com/Devolutions/IronRDP/issues/1209
187-
pub(crate) fn from_anyhow(error: anyhow::Error) -> ServerError {
188-
ServerError::new("server error", ServerErrorKind::Custom).with_source(AnyhowError(error))
189-
}
190-
191-
/// Newtype wrapper that gives [`anyhow::Error`] a `core::error::Error` impl
192-
/// suitable for `ironrdp_error::Error::with_source`.
193-
#[derive(Debug)]
194-
struct AnyhowError(anyhow::Error);
195-
196-
impl fmt::Display for AnyhowError {
197-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198-
write!(f, "{:#}", self.0)
199-
}
200-
}
201-
202-
impl core::error::Error for AnyhowError {
203-
/// Forwards to the wrapped [`anyhow::Error`]'s cause chain so callers
204-
/// traversing [`core::error::Error::source`] reach the original root
205-
/// cause rather than stopping at this newtype.
206-
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
207-
self.0.source()
208-
}
209-
}

crates/ironrdp-server/src/server.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ use crate::clipboard::CliprdrServerFactory;
3838
use crate::display::{DisplayUpdate, RdpServerDisplay};
3939
use crate::echo::{EchoDvcBridge, EchoServerHandle, EchoServerMessage, build_echo_request};
4040
use crate::encoder::{UpdateEncoder, UpdateEncoderCodecs};
41-
use crate::error::{ServerError, ServerErrorExt as _, ServerResult, ServerResultExt as _, from_anyhow};
41+
use crate::error::{ServerError, ServerErrorExt as _, ServerResult, ServerResultExt as _};
4242
#[cfg(feature = "egfx")]
4343
use crate::gfx::{EgfxServerMessage, GfxServerFactory};
4444
use crate::handler::RdpServerInputHandler;
@@ -361,8 +361,7 @@ impl DisplayControlHandler for DisplayControlBackend {
361361
/// ```
362362
/// use ironrdp_server::{RdpServer, RdpServerInputHandler, RdpServerDisplay, RdpServerDisplayUpdates};
363363
///
364-
///# use anyhow::Result;
365-
///# use ironrdp_server::{DisplayUpdate, DesktopSize, KeyboardEvent, MouseEvent};
364+
///# use ironrdp_server::{DisplayUpdate, DesktopSize, KeyboardEvent, MouseEvent, ServerResult};
366365
///# use tokio_rustls::TlsAcceptor;
367366
///# struct NoopInputHandler;
368367
///# impl RdpServerInputHandler for NoopInputHandler {
@@ -375,11 +374,11 @@ impl DisplayControlHandler for DisplayControlBackend {
375374
///# async fn size(&mut self) -> DesktopSize {
376375
///# todo!()
377376
///# }
378-
///# async fn updates(&mut self) -> Result<Box<dyn RdpServerDisplayUpdates>> {
377+
///# async fn updates(&mut self) -> ServerResult<Box<dyn RdpServerDisplayUpdates>> {
379378
///# todo!()
380379
///# }
381380
///# }
382-
///# async fn stub() -> Result<()> {
381+
///# async fn stub() -> ServerResult<()> {
383382
/// fn make_tls_acceptor() -> TlsAcceptor {
384383
/// /* snip */
385384
///# todo!()
@@ -1127,7 +1126,7 @@ impl RdpServer {
11271126
W: FramedWrite,
11281127
{
11291128
debug!("Starting client loop");
1130-
let mut display_updates = self.display.lock().await.updates().await.map_err(from_anyhow)?;
1129+
let mut display_updates = self.display.lock().await.updates().await?;
11311130
let mut writer = SharedWriter::new(writer);
11321131
let mut display_writer = writer.clone();
11331132
let mut event_writer = writer.clone();

crates/ironrdp-testsuite-extra/tests/e2e.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@ use std::path::Path;
55
use std::sync::Arc;
66
use std::time::Instant;
77

8-
use anyhow::Result;
98
use ironrdp::connector;
109
use ironrdp::dvc::DrdynvcClient;
1110
use ironrdp::echo::client::EchoClient;
1211
use ironrdp::pdu::rdp::capability_sets::MajorPlatformType;
1312
use ironrdp::pdu::{self, gcc};
1413
use ironrdp::server::{
1514
self, DesktopSize, DisplayUpdate, KeyboardEvent, MouseEvent, PixelFormat, RdpServer, RdpServerDisplay,
16-
RdpServerDisplayUpdates, RdpServerInputHandler, ServerEvent, TlsIdentityCtx,
15+
RdpServerDisplayUpdates, RdpServerInputHandler, ServerEvent, ServerResult, TlsIdentityCtx,
1716
};
1817
use ironrdp::session::image::DecodedImage;
1918
use ironrdp::session::{self, ActiveStage, ActiveStageOutput};
@@ -183,7 +182,7 @@ struct TestDisplayUpdates {
183182

184183
#[async_trait::async_trait]
185184
impl RdpServerDisplayUpdates for TestDisplayUpdates {
186-
async fn next_update(&mut self) -> Result<Option<DisplayUpdate>> {
185+
async fn next_update(&mut self) -> ServerResult<Option<DisplayUpdate>> {
187186
let mut rx = self.rx.lock().await;
188187

189188
Ok(rx.recv().await)
@@ -203,7 +202,7 @@ impl RdpServerDisplay for TestDisplay {
203202
}
204203
}
205204

206-
async fn updates(&mut self) -> Result<Box<dyn RdpServerDisplayUpdates>> {
205+
async fn updates(&mut self) -> ServerResult<Box<dyn RdpServerDisplayUpdates>> {
207206
Ok(Box::new(TestDisplayUpdates {
208207
rx: Arc::clone(&self.rx),
209208
}))

crates/ironrdp/examples/server.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ struct DisplayUpdates;
153153

154154
#[async_trait::async_trait]
155155
impl RdpServerDisplayUpdates for DisplayUpdates {
156-
async fn next_update(&mut self) -> anyhow::Result<Option<DisplayUpdate>> {
156+
async fn next_update(&mut self) -> ironrdp::server::ServerResult<Option<DisplayUpdate>> {
157157
sleep(Duration::from_millis(100)).await;
158158
let mut rng = rand::rng();
159159

@@ -205,7 +205,7 @@ impl RdpServerDisplay for Handler {
205205
}
206206
}
207207

208-
async fn updates(&mut self) -> anyhow::Result<Box<dyn RdpServerDisplayUpdates>> {
208+
async fn updates(&mut self) -> ironrdp::server::ServerResult<Box<dyn RdpServerDisplayUpdates>> {
209209
Ok(Box::new(DisplayUpdates {}))
210210
}
211211
}

0 commit comments

Comments
 (0)