Поток доступен через IXrplClient: события на клиенте, проброс к соединению - #108
Conversation
The raw bytes this release puts on stream events exist so a wallet can show a person what a node actually sent before they sign it. Transactions arrive by stream - and the only way to receive one was client.connection.OnTransaction, a property of a concrete class. Code written against IXrplClient could neither subscribe nor be exercised against a substitute client, so the feature had no contract to reach it through. All 16 events Connection raises are now declared on IXrplClient. The existing client.connection.OnX form keeps working; this adds a surface rather than moving one. Forwarded, not relayed, and that is the design rather than an implementation detail: add/remove reach the same Connection directly, so the client holds no delegates, no subscriber list of its own, and no subscription that nothing ever removes. A relaying version would introduce all three plus a second place to keep in sync. Safe because the Connection outlives the client - assigned once in the constructor, and ChangeServer swaps the session inside it rather than the object, so subscriptions survive a server change. IXrplClient.connection loses its setter (breaking, though nothing in the tree assigned it). With handlers attached through these events, replacing the connection would strand every one of them on the old object and the stream would go quiet with nothing to show for it. The forwarding shape is pinned by a test that crosses surfaces - subscribe through the client, remove through the connection - because removing through the surface it was added to passes either way. Proven by mutation: a relaying implementation turns it red. FeeTestClient now declares the events, which is the tell that this was the missing piece: a substitute client could not carry them while they lived only on Connection.
…piler hold the invariant Review found the forwarding tests never executed the client's remove accessor: the existing case subscribes through the interface but removes through the connection, so turning `connection.OnX -= value` into `+=` left the entire suite green. Half the unsubscribe contract was unverified. Added the mirror case - subscribe through the connection, remove through the client - which turns that mutation red. Renamed the existing test to say what it actually does rather than what its name claimed. connection is get-only now instead of `private set`. The one-assignment invariant that forwarding depends on was held only by convention inside an 1100-line class; a second assignment would have compiled and stranded every handler on the old object. The compiler checks it now.
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
Included review availability: 3 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 4 reviews per hour. 📝 WalkthroughWalkthrough
ChangesStream event contract
Estimated code review effort: 3 (Moderate) | ~20 minutes Merge Risk: ⚪ Minimal · up to The PR exposes existing connection events through the client interface while preserving direct connection usage; no actionable merge-blocking risk remains beyond normal checks and review. Sequence Diagram(s)sequenceDiagram
participant Consumer
participant IXrplClient
participant Connection
Consumer->>IXrplClient: subscribe to OnTransaction
IXrplClient->>Connection: add event handler
Connection->>Consumer: deliver transaction event
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Закрывает #103.
Зачем
Предыдущий релиз дал стрим-событиям
RawиRawTransaction— байты, которые прислал узел. Смысл этого — кошелёк показывает человеку транзакцию перед тем, как он её подпишет. Транзакции приходят потоком.А добраться до потока можно было только так:
connection— свойство конкретного класса. Код, написанный противIXrplClient, не мог ни подписаться, ни быть покрыт тестом с подставным клиентом. Получалась возможность без контракта, через который её взять.Что сделано
Все 16 событий, которые поднимает
Connection, объявлены наIXrplClient:Прежняя форма
client.connection.OnXработает без изменений — поверхность добавлена, а не перенесена.Проброс, а не ретрансляция
Это главное решение, и оно намеренное:
Подписчик регистрируется на том же самом
Connection, к которому обратился бы напрямую. Клиент не хранит ни делегатов, ни своего списка подписчиков, ни подписки, которую никто не снимает — ссылок ровно столько же, сколько было раньше.Ретранслирующая версия (локальное событие плюс подписка на
connection, которая его перевыбрасывает) добавила бы всё перечисленное и второе место, которое нужно держать в согласии с первым.Предпосылка безопасности проверена по коду:
Connectionприсваивается один раз, в конструкторе, аChangeServerменяет сессию внутри объекта, а не сам объект — подписки переживают смену сервера и реконнект.Ломающее
IXrplClient.connectionпотерял сеттер и стал get-only. С обработчиками, привязанными через события, подмена соединения оставила бы их все на старом объекте, и поток замолчал бы без единого признака. В дереве сеттер снаружи не использовался.Get-only, а не
private set: инвариант «присваивается один раз» теперь проверяет компилятор, а не соглашение внутри класса на 1100 строк.Проверка
dotnet build XrplCSharp.sln— 0 ошибок;connection, и обратно. Это не педантизм: первая версия теста снимала подписку той же поверхностью, которой ставила, и ретрансляцию не отличала — мутация это показала;removeне исполнялся ни одним тестом: замена-=на+=в нём проходила весь набор.Показательная деталь:
FeeTestClientв тестах пришлось дополнить объявлениями событий. Это и есть признак того, что не хватало именно контракта — пока события жили только наConnection, подставной клиент их нести не мог.Что не входит
Восстановление подписок после переподключения (#104) и наблюдаемость вытеснения событий из канала (#105) — отдельные задачи, контракт не меняют и в мажорный релиз не обязаны.
Summary by CodeRabbit
New Features
Bug Fixes