Skip to content

Add update_config write path (TWS 10.44 / server 221)#708

Merged
wboayue merged 3 commits into
mainfrom
config-update-write
Jul 17, 2026
Merged

Add update_config write path (TWS 10.44 / server 221)#708
wboayue merged 3 commits into
mainfrom
config-update-write

Conversation

@wboayue

@wboayue wboayue commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Summary

Implements Option 2 of the config feature — the update_config write path (IBKR added it in TWS 10.44). Adds a fluent Client::update_config() (sync + async) that pushes partial edits to the running gateway's configuration and returns an UpdateConfigResponse reporting changed fields, errors, and warnings.

Follows PR #707 (the read path); reuses the read-path domain types as the write-side input.

API shape

Fluent builder (chosen over a struct-input form), matching the house style:

let response = client
    .update_config()
    .api(ApiConfig {
        settings: Some(ApiSettings { socket_port: Some(7497), ..Default::default() }),
        ..Default::default()
    })
    .message(MessageSetting { id: Some(131), enabled: Some(false), ..Default::default() })
    .accept_warning(warning)      // echo a warning from a prior response
    .reset_api_order_sequence()
    .submit()                     // sync
    .await?;                      // async

Semantics

This is a one-shot request → one-shot response — there is no library-level re-submit loop (confirmed against C# EClient.updateConfig and the Python ConfigSamples). If the response's warnings are non-empty the edit was not applied; the caller re-submits the same edit with each warning echoed via .accept_warning(...) to proceed. That acknowledgement round-trip is application-level, so the library stays a thin one-shot.

What's included

  • Fluent UpdateConfigBuilder<'a, C> (src/config/builder/): generic over the client type, feature-agnostic setters, per-feature submit() in sync_impl.rs/async_impl.rs — the established dual-feature builder pattern (rule 12, mirrors OrderBuilder).
  • Reuses the read-path domain types (ApiConfig, ApiSettings, OrdersConfig, LockAndExit, MessageSetting) as write input — all Option fields with Default, so partial edits are ..Default::default().
  • New domain types: UpdateConfigResponse { status, message, changed_fields, errors, warnings } and ConfigWarning.
  • Domain→proto encoders (config/common/encoders.rs) mirror the read path's proto→domain decoders; decoder for UpdateConfigResponse.
  • Features::UPDATE_CONFIG (server 221); UpdateConfigResponse registered in text_request_id_field so it routes by request_id (rule 17).
  • Field-minimal testdata builder; sync + async examples registered in Cargo.toml; CHANGELOG.md entry.

Tests drive the real client API and verify the captured wire request by decoding proto::UpdateConfigRequest from the sent bytes (rule 10), plus response decode, server-version rejection, and empty-stream paths.

Verification

  • cargo fmt; clippy ×3 configs (-D warnings); rustdoc ×3 configs (-D warnings); sync + async doc-tests.
  • Full lib tests green: default (1319), sync-only (1335), all-features (1663); both integration crates build.
  • 100% line coverage on every new config file.
  • Live smoke test deferred: unlike the read path, update_config mutates gateway settings, so it was not run against the live paper gateway.

wboayue added 3 commits July 16, 2026 19:09
Fluent Client::update_config() (sync + async) returning an
UpdateConfigBuilder to push partial config edits back to the gateway.

- Builder: .api()/.orders()/.lock_and_exit()/.message()/.accept_warning()/
  .reset_api_order_sequence() -> .submit(); generic over client, per-feature
  submit() in sync_impl/async_impl (rule 12).
- Reuses the read-path domain types as write input (Option fields + Default).
- Domain->proto encoders mirror the proto->domain decoders; new
  UpdateConfigResponse + ConfigWarning domain types.
- Features::UPDATE_CONFIG gate (server 221); UpdateConfigResponse registered
  in text_request_id_field so it routes by request_id.
- One-shot request/response (no library re-submit loop); caller echoes
  warnings via .accept_warning() to proceed, mirroring C# EClient.updateConfig.
- Field-minimal testdata builder; 100% coverage on the new code.

Live smoke test deferred: the write path mutates gateway settings.
Closes the Vec-vs-singular composability gap so a caller can round-trip
Config.messages / UpdateConfigResponse.warnings in one call (precedent:
MarketDataBuilder generic_ticks + add_generic_tick).
Bring the async request-body test to full parity with the sync mirror
(adds lock_and_exit + per-element assertions); trim the sync
response-decode test to the wiring-critical fields since exhaustive
proto->domain mapping is owned by the decoder unit test.
@wboayue
wboayue merged commit a24ed32 into main Jul 17, 2026
3 checks passed
@wboayue
wboayue deleted the config-update-write branch July 17, 2026 02:35
wboayue added a commit that referenced this pull request Jul 17, 2026
* Add Order.deactivate field (TWS 10.48)

Since TWS 10.48, reqOpenOrders returns de-activated orders. Surface
Order.deactivate (bool) so callers can distinguish inactive orders from
active ones.

- Public Order.deactivate field + Default.
- Map both directions in proto encoders/decoders (some_bool / unwrap_or_default),
  matching the C# EDecoderUtils/EClientUtils round-trip. No server-version
  gate (Order.Deactivate predates the proto floor).
- Encode + decode unit tests; CHANGELOG Added.

Also prune completed C#-sync plan files (PRs #705/#706/#707/#708 shipped) and
refresh plans/csharp-sync-coverage.md.

* Fill PR number in changelog (#709)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant