Commit 5aefd17
committed
feat(audience): add ImmutableAudience singleton + GDPR (SDK-147)
Adds the ImmutableAudience static entry point that ties DiskStore,
EventQueue, HttpTransport, ConsentStore, and Identity together into
the public SDK surface for track/identify/alias plus the GDPR
lifecycle (SetConsent, Reset, DeleteData).
Public API: Init, Track (IEvent + string overloads), Identify,
Alias, Reset, DeleteData, SetConsent, FlushAsync, Shutdown.
Behavioural guarantees:
- Concurrency: all public methods are thread-safe. Track is the
allocation-light hot path - it enqueues a dictionary and returns;
serialisation runs on the drain thread.
- Consent state machine: None drops everything; Anonymous
discards userId from track messages and drops identify/alias;
Full sends everything. Downgrades rewrite the on-disk queue.
- Never-throw: public methods catch and route every exception to
the OnError callback, including background drain failures and
shutdown flush errors.
- Shutdown hygiene: final synchronous drain, drain-thread join
with timeout, HttpTransport disposal, idempotent (safe to call
from application exit + Unity quit).
- Persistence round-trip: identity, consent, and queued events
all survive process restart via atomic write-temp-then-move.
Code changes:
- ImmutableAudience.cs: 549-line rewrite of the stub (Init wiring,
public API surface, consent state machine, backend sync loop).
- AudienceConfig.cs: adds OnError, PersistentDataPath,
PackageVersion, ShutdownFlushTimeoutMs, HttpHandler (test seam).
- ConsentLevel.cs: ConsentLevelExtensions.ToWireString for the
tracking-consent backend audit payload.
- Transport/EventQueue.cs: swaps ConcurrentQueue<string> for
ConcurrentQueue<Dictionary<string,object>> so Json.Serialize
runs on the drain thread; adds _drainLock to serialise drain
against PurgeAll / ApplyAnonymousDowngrade so a TryDequeue'd
event cannot hit disk after consent revocation wiped it;
EnqueueChecked closes the same window for new Track calls that
race SetConsent(None). See _drainLock comment for full race.
- Transport/DiskStore.cs: DeleteAll and ApplyAnonymousDowngrade
for the queued-event side of consent revocation. The latter
strips userId from queued track messages via JsonReader ->
Json.Serialize round-trip (numeric-precision caveat documented
in-file - exact for realistic Purchase.Value amounts).
Tests:
- ImmutableAudienceTests.cs: 737 lines covering Init/Shutdown
lifecycle, the Track/Identify/Alias/Reset/DeleteData/FlushAsync
public surface, the consent state machine transitions, the
never-throw contract, and the privacy invariants.
- ConsentSyncTests.cs: backend consent audit round-trip.
- DeleteDataTests.cs: queue-purge + backend-call + Identity cache
clearing interaction.
- Transport/DiskStoreTests.cs, Transport/EventQueueTests.cs:
coverage for the new GDPR ops.
The preceding four peels (remove duplicate IdentityTests, mirror
Runtime layout onto Tests, SSOT constants + scaffolding, ConsentStore)
were carved out of this commit to keep the singleton diff focused on
the parts that only make sense together.1 parent 2cbe87f commit 5aefd17
10 files changed
Lines changed: 1915 additions & 29 deletions
File tree
- src/Packages/Audience
- Runtime
- Transport
- Tests/Runtime
- Transport
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
1 | 3 | | |
2 | 4 | | |
3 | 5 | | |
| |||
20 | 22 | | |
21 | 23 | | |
22 | 24 | | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
23 | 40 | | |
24 | 41 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
13 | 27 | | |
0 commit comments