Skip to content

refactor(tracker): adopt asyncssh tracker_factory API#4

Merged
AlexMKX merged 1 commit into
mainfrom
feature/forward-tracker-factory
Jun 24, 2026
Merged

refactor(tracker): adopt asyncssh tracker_factory API#4
AlexMKX merged 1 commit into
mainfrom
feature/forward-tracker-factory

Conversation

@AlexMKX

@AlexMKX AlexMKX commented Jun 24, 2026

Copy link
Copy Markdown
Owner

What

Reworks the idle-auto-stop integration onto the redesigned asyncssh forward-tracker API. Externally observable behavior is unchanged — this is an integration-layer refactor to match the new upstream-agreed API shape.

Pairs with asyncssh fork v2.23.0+forward-tracker.3 (branch feat/forward-tracker), the API agreed with the upstream maintainer in ronf/asyncssh#807.

Why

The original ForwardTracker(Protocol) (single object per listener, connection_made(orig_host, orig_port) / connection_lost(orig_host, orig_port, exc), tracker= kwarg) was redesigned during upstream review into a class hierarchy with a per-connection factory:

  • asyncssh.SSHForwardTracker (parent, no-op connection_lost + forward_local_bytes + forward_remote_bytes)
  • asyncssh.SSHPortForwardTrackerconnection_made(forwarder, orig_host, orig_port) (TCP)
  • asyncssh.SSHPathForwardTrackerconnection_made(forwarder) (UNIX)
  • new tracker_factory= kwarg, invoked once per accepted connection

Changes

  • activity.pyActivityTracker is now the per-daemon aggregate and the factory via make_tracker(). The asyncssh-facing hooks move to a per-connection _IdleConnectionTracker(asyncssh.SSHPortForwardTracker) with _opened/_closed idempotency guards (a connection counts exactly once even if connection_lost fires twice). Public contract (make_tracker, note_connection_made, note_connection_lost, is_idle, seconds_since_activity) preserved.
  • ssh.pyopen_local_forwards(..., tracker_factory=...) (was tracker=), forwarded as forward_local_port(tracker_factory=...).
  • manager.py — passes tracker_factory=self.activity_tracker.make_tracker.
  • pyproject.toml — asyncssh fork pin bumped v2.23.0+forward-tracker.1.3.
  • teststest_activity / test_ssh_transport / test_idle_watchdog / test_manager_* fakes rewritten for the factory + per-connection pair.
  • docs/specs/2026-05-21-auto-stop-idle-design.md — revision-history note recording the API shift.

Verification

  • pytest tests/unit213 passed
  • ruff / black / mypy → clean; pylint activity.py 10.00/10
  • Independent passes: multi-delegate code review (critical double-connection_lost fixed) + RP/OP code-health-check → PASS (RP 32.3 / OP 29.0, max CC 4, MI grade A)

Note: the fork pin .3 only resolves once the fork branch/tag is published (already pushed to AlexMKX/asyncssh). CI here will install it from the VCS pin.

Rework the idle auto-stop integration onto the redesigned asyncssh
forward-tracker API (fork v2.23.0+forward-tracker.3, agreed in upstream
PR ronf/asyncssh#807). Externally observable behavior is unchanged.

- activity.py: ActivityTracker becomes the per-daemon aggregate and a
  tracker factory via make_tracker(); the asyncssh-facing hooks move to a
  per-connection _IdleConnectionTracker(asyncssh.SSHPortForwardTracker)
  with _opened/_closed idempotency guards so a connection counts exactly
  once even if connection_lost fires twice.
- ssh.py: open_local_forwards takes tracker_factory (was tracker) and
  forwards it as forward_local_port(tracker_factory=...).
- manager.py: pass tracker_factory=activity_tracker.make_tracker.
- pyproject.toml: bump asyncssh fork pin to v2.23.0+forward-tracker.3.
- tests: rewrite activity/ssh-transport/idle-watchdog/manager fakes for
  the factory + per-connection pair.
- docs/specs: add revision-history note recording the API shift.
@AlexMKX AlexMKX force-pushed the feature/forward-tracker-factory branch from b870cb0 to de380f3 Compare June 24, 2026 07:41
@AlexMKX AlexMKX merged commit 86c3569 into main Jun 24, 2026
21 checks passed
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