synology_apm_repo.sdk.units.saas.services module¶
Content inspection for embedded saas_obj objects.
The SaaS application layer locates a service-level DB snapshot via the
connector’s own object-name index (see object_name_index.py) — a top-down
lookup into fixed, connector-written bookkeeping, never a guess. This
module’s role is different: given an already-located object’s raw
bytes, determine (sniff) or read (inspect_object) what it is
— the corruption check every object-name-index caller still wants (confirm
it decompresses, confirm it’s really SQLite, confirm it defines the
expected table), never discovery of an unknown object’s location; every
provider locates objects by direct index lookup because a schema-only
scan couldn’t reliably tell apart schema-identical tables (Archive
Mail’s mail_table from regular Mail’s, say).
Raw bytes classify into one of ServiceKind’s members by a fixed
prefix rule: ZSTD-framed SQLite, then a JSON object, then an RFC822
header, else binary. (Real SnapshotDB reassembly is unavailable
offline.)
- class synology_apm_repo.sdk.units.saas.services.ServiceKind(value)¶
Bases:
EnumWhat one already-located object’s raw bytes turn out to be (
sniff’s classification).SERVICE_DB: ZSTD -> SQLite; the owning app is guessed from itssqlite_mastertable names (_SERVICE_TABLE_HINTS).INDEX: JSON matching thedb_objects/db_infos_in_snapshotshape (_index_entries) — extracted asIndexEntrytuples.META_JSON: any other JSON object (content-list fragments, Contact/Calendar client metadata, search-index documents).MAIL_SKELETON: an RFC822 header in the first few hundred bytes.BINARY: anything else — the common case for real Drive content.
- INDEX = 'index'¶
- SERVICE_DB = 'service_db'¶
- META_JSON = 'meta_json'¶
- MAIL_SKELETON = 'mail_skeleton'¶
- BINARY = 'binary'¶
- class synology_apm_repo.sdk.units.saas.services.IndexEntry(name, object_id)¶
Bases:
objectOne entry in a connector’s own index object: a display name paired with the backing object id.
- class synology_apm_repo.sdk.units.saas.services.SniffResult(kind, tables=frozenset({}), service_name=None, index_entries=())¶
Bases:
objectWhat sniffing a service-DB/index object’s bytes found: its
ServiceKind, plus whichever oftables/service_name/index_entriesthat kind actually carries.- kind: ServiceKind¶
- index_entries: tuple[IndexEntry, ...] = ()¶
- async synology_apm_repo.sdk.units.saas.services.decompress_service_db(data)¶
Decompress one service-level DB snapshot’s raw bytes to plain SQLite bytes — the half of
open_service_dbthat callers holding bytes directly need (TeamsChatProvider’s several short-lived connections).Deliberately unbounded, unlike
sniff’s capped speculative read: content here is already identified via the object-name index, so a resolved-but-wrong location is caught by the schema check every caller already does afterward, not by refusing to decompress upfront. Also deliberately unbounded in size – large real service DBs are expected – which is exactly why this isasyncand hops to a real OS thread for the decrypt+decompress itself:peel()itself is pure, synchronous bytes work with no I/O, but leaving a large decrypt+decompress on the event loop would stall every other Task (TUI redraws, a progress callback, a concurrent metadata read) for its duration — the same responsiveness reasoning behinddedup/pool/_bucket_reader.py’s own per-chunk-vs-per-run thread-hop split.- Raises:
DataCorruptError –
dataisn’t ZSTD-framed SQLite.
- async synology_apm_repo.sdk.units.saas.services.open_service_db(data)¶
Decompress and open one service-level DB snapshot’s raw bytes as a live, queryable connection — the counterpart to
snifffor callers (the application-layer providers) that need to actually run queries against the DB, not just inspect it.
- async synology_apm_repo.sdk.units.saas.services.sniff(data)¶
Classify one object’s raw bytes into one of
ServiceKind’s shapes. Pure function ofdata— touches no repository, no store, noDedupFile— so it’s cheap to unit test with synthetic bytes and is reused as-is byinspect_object; it isasyncbecause theSERVICE_DBbranch opens the decompressed payload as real SQLite to read its table names (that’s I/O), and because the speculative decompress attempt below hops to a real OS thread rather than blocking the event loop — up to_MAX_SNIFF_DECOMPRESS(128 MiB) of synchronous work otherwise, on data this function hasn’t even confirmed is real SQLite yet. Never raises: apeelfailure here means “not actually zstd-framed”, not “sniff itself failed”.
- async synology_apm_repo.sdk.units.saas.services.inspect_object(dedup_file, offset, length)¶
Read just enough of an already-located object’s bytes to classify (
sniff) and validate it — never a step in finding the object:offset/lengthalways come from the connector’s own object-name index or from an already-resolved INDEX object’s own entries. Applies_FULL_READ_CAP(magic-gated, not a blind size cutoff).