Skip to content

feat(server): convert encoder/helper/echo internals from anyhow to ServerError#1243

Open
Greg Lamberson (glamberson) wants to merge 2 commits into
Devolutions:masterfrom
lamco-admin:feat/server-typed-error-internal
Open

feat(server): convert encoder/helper/echo internals from anyhow to ServerError#1243
Greg Lamberson (glamberson) wants to merge 2 commits into
Devolutions:masterfrom
lamco-admin:feat/server-typed-error-internal

Conversation

@glamberson
Copy link
Copy Markdown
Contributor

Summary

Second step of the staged migration toward a typed public error story for ironrdp-server (#1209). Stacks on #1242.

Replaces anyhow construction sites in modules whose internal flow does not pass through the ConnectionHandler::on_disconnected callback (which still takes &anyhow::Error and is the subject of a separate follow-up PR):

  • encoder/mod.rs: ~15 anyhow! / .context() / bail! sites converted to typed ServerError variants (Encode, Reason, Custom). EncodeError sources go through ServerError::encode (matching ConnectorErrorExt::encode). spawn_blocking JoinError, qoi codec errors, and zstd error codes go through ServerError::custom or ServerError::reason as appropriate.
  • helper.rs: TLS cert/key loading paths construct ServerError::io for std::io::Error sources, ServerError::reason for missing-key cases, ServerError::custom for x509-cert and PEM parsing errors. Removes the from_anyhow bridge and the inner-fn split introduced in feat(server)!: introduce typed ServerError on the public API boundary #1242.
  • echo.rs: build_echo_request returns ServerResult, builds errors via ServerError::custom directly. send_request keeps its already-typed Channel and Reason variants.

What this PR does NOT touch

  • server.rs internals (the heavy .context() chain in run_inner and run_connection_inner) stay on anyhow because they propagate into ConnectionHandler::on_disconnected(error: Option<&anyhow::Error>). PR Panic in UserDataHeader::from_buffer due to integer overflow #3 in the staged migration will (a) change that parameter to Option<&ServerError>, and (b) convert the server.rs internal sites in the same change.
  • RdpServerDisplay / RdpServerDisplayUpdates traits (which return anyhow::Result) stay unchanged. PR Capset + fuzzing fixes #4 will convert those, drop the anyhow dependency entirely, and complete the migration.

Why split this way

server.rs and the display traits are both anyhow-flavored at the boundary; converting them in a single PR with on_disconnected keeps the type story coherent. Splitting them now would either require a temporary anyhow ↔ ServerError two-way bridge (ugly) or leave the public trait inconsistent with the rest of the crate (worse). Better to ship this batch (encoder + helper + echo all internal-only) and then take server.rs + on_disconnected as one coherent step.

Stacking note

Branch is stacked on feat/server-typed-error (#1242). Rebase onto master after #1242 merges.

Test plan

  • cargo xtask check fmt -v clean
  • cargo xtask check lints -v clean (workspace, all-targets, with helper + __bench features)
  • cargo xtask check tests -v passes
  • cargo build --workspace --all-targets clean

Tracking: #1209.

Introduces a typed error story for ironrdp-server, mirroring the shape
already used by ironrdp-connector and the rest of the connection-management
layer:

  pub type ServerError = ironrdp_error::Error<ServerErrorKind>;
  pub type ServerResult<T> = Result<T, ServerError>;

ServerErrorKind is a non-exhaustive enum with concretely typed variants
for the failure modes the crate surfaces (Encode, Decode, Io, Channel,
Unsupported, Reason, General, Custom). Sources are attached through
ironrdp_error::Error::with_source rather than embedded as Box<dyn Error>
in variant data, matching ConnectorErrorKind exactly.

This first PR converts public boundaries only:

  - RdpServer::run                -> ServerResult<()>
  - RdpServer::run_connection<S>  -> ServerResult<()>
  - TlsIdentityCtx::init_from_paths -> ServerResult<Self>
  - TlsIdentityCtx::make_acceptor   -> ServerResult<TlsAcceptor>
  - EchoServerHandle::send_request  -> ServerResult<()>

Internal call sites continue to use anyhow::Result during the staged
migration. A private  helper bridges at the public boundary.
A follow-up PR converts internal sites to use the typed kinds directly
and drops the anyhow dependency. A second follow-up changes the
ConnectionHandler::on_disconnected error parameter from
Option<&anyhow::Error> to Option<&ServerError>.

This is a breaking change to consumers of the listed public functions:
return types change from anyhow::Result<T> to ServerResult<T>.

Tracking: Devolutions#1209
…rverError

Second step of the staged migration started in the previous commit.
Replaces anyhow construction sites in modules whose internal flow does
not pass through the ConnectionHandler::on_disconnected callback (which
still takes &anyhow::Error and is the subject of a separate follow-up
PR per Devolutions#1209):

  - encoder/mod.rs: ~15 anyhow! / .context() / bail! sites converted
    to typed ServerError variants (Encode, Reason, Custom).
    EncodeError sources go through ServerError::encode (matching
    ConnectorErrorExt::encode). spawn_blocking JoinError, qoi codec
    errors, and zstd error codes go through ServerError::custom or
    ServerError::reason as appropriate.
  - helper.rs: TLS cert/key loading paths construct ServerError::io
    for std::io::Error sources, ServerError::reason for missing-key
    cases, ServerError::custom for x509-cert and PEM parsing errors.
    Removes the from_anyhow bridge and the inner-fn split introduced
    in the previous commit.
  - echo.rs: build_echo_request returns ServerResult, builds errors
    via ServerError::custom directly. send_request keeps its already-
    typed Channel and Reason variants.

server.rs internals stay on anyhow because they propagate into
ConnectionHandler::on_disconnected which still takes &anyhow::Error;
that conversion plus the remaining server.rs internal sites land in
PR Devolutions#3. The anyhow dep stays in Cargo.toml for now and will be dropped
when the public traits (ConnectionHandler, RdpServerDisplay, and
RdpServerDisplayUpdates) finish their typed migration.
@glamberson Greg Lamberson (glamberson) force-pushed the feat/server-typed-error-internal branch from b8f0df5 to 1dd0740 Compare May 13, 2026 00:18
Greg Lamberson (glamberson) pushed a commit to lamco-admin/IronRDP that referenced this pull request May 13, 2026
Final step of the staged migration started in Devolutions#1242, continued in
Devolutions#1243 and Devolutions#1244. Completes the typed error story for ironrdp-server.

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 Devolutions#1209.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants