synology_apm_repo.sdk.api.session module¶
Session: repository discovery, key material, and the store/repository
lifetime it owns, part of the Repository Layer (the Session/
Repository/Catalog split CLI/TUI code imports directly). Hands out
Repository instances (api.repository) it discovered/opened;
never the other way around.
- class synology_apm_repo.sdk.api.session.Session¶
Bases:
objectUse as a context manager, or call
closeexplicitly when done – orclose_repoto release just one repository (and its store, if unshared) ahead of the rest of a longer-running session.- async discover(path, key=None, *, progress=None, trace=None)¶
Walk
pathfor repositories, yielding each as it’s found — an indeterminate-progress generator (discovery has an unknowable total), not a blocking call; seeopenfor that convenience wrapper.A layout
iter_repository_layoutsfinds that then failsRepository._confirm_real()’s own cheap, marker-only check is skipped rather than aborting the whole scan — forOBJECT_STOREthis only catches a bucket with zero valid catalog ids; forVAULTthis check never actually fails (its one marker check already ran when the layout was built). Neither kind’s own corruptrepo_infois caught here — that surfaces later instead, scoped to the one broken catalog, the first timeRepository.catalogs()actually opens it.Local paths only — see
discover_remotefor an already-constructedObjectStore(S3/Azure/…).- Parameters:
key (str | None) – When omitted, each yielded repository’s encryption status is still resolved eagerly via
dedup.keys.probe_encrypted(seeKeyStatus); skipped when a key is given, sinceRepository.key_verificationalready answers it.trace (Callable[[TraceEvent], None] | None) – When given, every
ObjectStorecall any repository found here ever makes, for that repository’s entire lifetime, is reported as aTraceEvent.
- async discover_remote(store, key=None, *, root='', progress=None, trace=None)¶
Same as
discover, against an already-constructedObjectStore(S3/Azure/…) instead of building aLocalFsStorefrom a filesystem path — for a caller that already knows which backend and bucket/container it wants (the TUI’s connect dialog). This session takes ownership ofstorethe same waydiscoverdoes its ownLocalFsStore, released byclose.rootnarrows the scan to a store-relative sub-path, the same role a deeper local directory plays fordiscover— needed because S3/Azure stores are scoped to a whole bucket/container with no “sub-root” constructor argument, so a bucket holding several sibling repositories otherwise has no way to be narrowed to one.
- async open(path, key=None, *, progress=None, trace=None)¶
discover, fully drained — the blocking convenience form for callers that don’t need incremental results but still want progress/cancel support: every CLI command that opens a repository needs the final list, but discovery can still take a while on a directory tree with many candidate layouts, so there’s no reason to give up incremental feedback just because the caller is going to wait for the whole list anyway.
- async open_remote(store, key=None, *, root='', progress=None, trace=None)¶
discover_remote, fully drained — the blocking convenience form for a caller that wants the final list but still needs progress/cancel support during a possibly slow scan.
- async resolve(ref)¶
Turn a
NodeRef(or its string form) back into a live node, re-derived from cheap catalog lookups and provider tree calls rather than stored anywhere.This is two jobs stacked: which open
Repositoryrefbelongs to (this method’s own job — matchesref.repo_pathagainst each open repository’s own catalogs, viaRepository.owns_repo_path, relevant once several repositories are open in one long-livedSession, e.g. a TUI), then what node inside itrefnames (Repository.resolve’s job — see its docstring for the canonical/raw/human dispatch). A caller that already has the rightRepositoryin hand (the common case for a one-shot CLI invocation, which opens exactly one repository per run) should callRepository.resolvedirectly and skip this matching step entirely.
- async close_repo(repo)¶
Close and forget one repository this session tracks, releasing its own store too if no other still-tracked repository shares it.
Unlike a bare
repo.close()(idempotent, safe ahead ofSession.close()), this also removesrepofrom this session’s bookkeeping and, when its store isn’t shared with another repository this session still tracks, actually releases that store’s connector/session instead of waiting forSession.close()at process end. For a caller that discards one repository at a time from a longer-running session — the TUI reconnecting to a different profile, or a tool walking many repositories sequentially — rather than tearing the whole session down at once.The caller must have finished draining the
discover()/discover_remote()call that yieldedrepobefore calling this — a not-yet-yielded sibling repository sharing the same store isn’t inself._reposyet, so the shared-store check below would false-negative and close the store out from under it. Both of this session’s real callers (a fully-drained sample loop, a fully-drained reconnect scan) already satisfy this.Every tracked store sharing
repo’s own backing store (there can be more than one distinctTracingStorewrapper around the same backing, from separatediscover()/discover_remote()calls) is released together once nothing inself._reposstill references it, not just the one wrapperrepoitself used — otherwise a sibling wrapper from an earlier call would sit inself._storesforever, never reachable by identity again.
- async close()¶
Close every repository this session opened, then release any backend client it owns.
S3Store/AzureStoreown anaiohttpconnector that must be released; local stores have noaclose()and are skipped.