Skip to content

Commit 0f93ad9

Browse files
refactor(audience-sdk): expand MessageFields with envelope keys
Adds the 15 wire-format envelope keys callers reach for (eventName, anonymousId, identityType, traits, messageId, eventTimestamp, context, surface, library, libraryVersion, fromId, fromType, toId, toType, properties), and routes runtime emit and downstream callers through the new constants. - Constants.cs: MessageFields gains the new envelope keys, grouped by section (envelope / track / identity / alias / context). - MessageBuilder.cs: BuildBase, Track, Identify, Alias all read keys from MessageFields. - ImmutableAudience.cs: DeleteData query string and consent-sync body anonymousId go through MessageFields; context-overlay TryGetValue reads MessageFields.Context. - AudienceSample.cs: typed/string/custom event echo, identify form, and alias form go through MessageFields.Properties / IdentityType / Traits. - Test suite (MessageBuilderTests, ImmutableAudienceTests, ConsentSyncTests, JsonReaderTests, JsonTests, EventQueueTests, DeleteDataTests): bracket-style envelope key access reads from MessageFields.
1 parent e0b6dbe commit 0f93ad9

9 files changed

Lines changed: 107 additions & 81 deletions

File tree

examples/audience/Assets/SampleApp/Scripts/AudienceSample.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ private void OnSendCatalogueEvent(EventSpec spec, Dictionary<string, VisualEleme
132132
{
133133
["event"] = spec.Name,
134134
["overload"] = "typed",
135-
["properties"] = typed.ToProperties(),
135+
[MessageFields.Properties] = typed.ToProperties(),
136136
}, 2);
137137
}
138138

@@ -141,7 +141,7 @@ private void OnSendCatalogueEvent(EventSpec spec, Dictionary<string, VisualEleme
141141
{
142142
["event"] = spec.Name,
143143
["overload"] = "string",
144-
["properties"] = props,
144+
[MessageFields.Properties] = props,
145145
}, 2);
146146
});
147147

@@ -155,7 +155,7 @@ private void OnSendCustomEvent() => RunAndLog("track()", () =>
155155
var props = string.IsNullOrEmpty(f.RawProps) ? null : JsonReader.DeserializeObject(f.RawProps);
156156
ImmutableAudience.Track(f.Name, props);
157157
var echo = new Dictionary<string, object> { ["event"] = f.Name };
158-
if (props != null) echo["properties"] = props;
158+
if (props != null) echo[MessageFields.Properties] = props;
159159
return Json.Serialize(echo, 2);
160160
});
161161

@@ -199,10 +199,10 @@ private void OnIdentify() => RunAndLog("identify()", () =>
199199
var payload = new Dictionary<string, object>
200200
{
201201
["id"] = f.Id,
202-
["identityType"] = f.Type,
202+
[MessageFields.IdentityType] = f.Type,
203203
["accepted"] = accepted,
204204
};
205-
if (traits != null) payload["traits"] = traits;
205+
if (traits != null) payload[MessageFields.Traits] = traits;
206206
return Json.Serialize(payload, 2);
207207
});
208208

@@ -233,8 +233,8 @@ private void OnAlias() => RunAndLog("alias()", () =>
233233
}
234234
return Json.Serialize(new Dictionary<string, object>
235235
{
236-
["from"] = new Dictionary<string, object> { ["id"] = f.FromId, ["identityType"] = f.FromType },
237-
["to"] = new Dictionary<string, object> { ["id"] = f.ToId, ["identityType"] = f.ToType },
236+
["from"] = new Dictionary<string, object> { ["id"] = f.FromId, [MessageFields.IdentityType] = f.FromType },
237+
["to"] = new Dictionary<string, object> { ["id"] = f.ToId, [MessageFields.IdentityType] = f.ToType },
238238
["accepted"] = accepted,
239239
}, 2);
240240
});

src/Packages/Audience/Runtime/Core/Constants.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,34 @@ internal static class ResponseFields
8080
// (read by one module, written by another).
8181
internal static class MessageFields
8282
{
83+
// Envelope keys present on every message
8384
internal const string Type = "type";
85+
internal const string MessageId = "messageId";
86+
internal const string EventTimestamp = "eventTimestamp";
87+
internal const string Context = "context";
88+
internal const string Surface = "surface";
89+
90+
// Track envelope
91+
internal const string EventName = "eventName";
92+
internal const string Properties = "properties";
93+
94+
// Identity envelope (track, identify, alias)
95+
internal const string AnonymousId = "anonymousId";
8496
internal const string UserId = "userId";
97+
98+
// Identify envelope
99+
internal const string IdentityType = "identityType";
100+
internal const string Traits = "traits";
101+
102+
// Alias envelope
103+
internal const string FromId = "fromId";
104+
internal const string FromType = "fromType";
105+
internal const string ToId = "toId";
106+
internal const string ToType = "toType";
107+
108+
// Context dictionary keys
109+
internal const string Library = "library";
110+
internal const string LibraryVersion = "libraryVersion";
85111
}
86112

87113
/// <summary>

src/Packages/Audience/Runtime/Events/MessageBuilder.cs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,18 @@ internal static Dictionary<string, object> Track(
1515
Dictionary<string, object>? properties = null)
1616
{
1717
var msg = BuildBase(MessageTypes.Track, packageVersion);
18-
msg["eventName"] = Truncate(eventName, Constants.MaxFieldLength);
18+
msg[MessageFields.EventName] = Truncate(eventName, Constants.MaxFieldLength);
1919

2020
if (!string.IsNullOrEmpty(anonymousId))
21-
msg["anonymousId"] = Truncate(anonymousId, Constants.MaxFieldLength);
21+
msg[MessageFields.AnonymousId] = Truncate(anonymousId, Constants.MaxFieldLength);
2222

2323
if (!string.IsNullOrEmpty(userId))
2424
msg[MessageFields.UserId] = Truncate(userId, Constants.MaxFieldLength);
2525

2626
if (properties != null && properties.Count > 0)
2727
{
2828
TruncateStringValues(properties);
29-
msg["properties"] = properties;
29+
msg[MessageFields.Properties] = properties;
3030
}
3131

3232
return msg;
@@ -42,17 +42,17 @@ internal static Dictionary<string, object> Identify(
4242
var msg = BuildBase(MessageTypes.Identify, packageVersion);
4343

4444
if (!string.IsNullOrEmpty(anonymousId))
45-
msg["anonymousId"] = Truncate(anonymousId, Constants.MaxFieldLength);
45+
msg[MessageFields.AnonymousId] = Truncate(anonymousId, Constants.MaxFieldLength);
4646

4747
if (!string.IsNullOrEmpty(userId))
4848
msg[MessageFields.UserId] = Truncate(userId, Constants.MaxFieldLength);
4949

50-
msg["identityType"] = Truncate(identityType, Constants.MaxFieldLength);
50+
msg[MessageFields.IdentityType] = Truncate(identityType, Constants.MaxFieldLength);
5151

5252
if (traits != null && traits.Count > 0)
5353
{
5454
TruncateStringValues(traits);
55-
msg["traits"] = traits;
55+
msg[MessageFields.Traits] = traits;
5656
}
5757

5858
return msg;
@@ -66,10 +66,10 @@ internal static Dictionary<string, object> Alias(
6666
string packageVersion)
6767
{
6868
var msg = BuildBase(MessageTypes.Alias, packageVersion);
69-
msg["fromId"] = Truncate(fromId, Constants.MaxFieldLength);
70-
msg["fromType"] = Truncate(fromType, Constants.MaxFieldLength);
71-
msg["toId"] = Truncate(toId, Constants.MaxFieldLength);
72-
msg["toType"] = Truncate(toType, Constants.MaxFieldLength);
69+
msg[MessageFields.FromId] = Truncate(fromId, Constants.MaxFieldLength);
70+
msg[MessageFields.FromType] = Truncate(fromType, Constants.MaxFieldLength);
71+
msg[MessageFields.ToId] = Truncate(toId, Constants.MaxFieldLength);
72+
msg[MessageFields.ToType] = Truncate(toType, Constants.MaxFieldLength);
7373
return msg;
7474
}
7575

@@ -78,14 +78,14 @@ private static Dictionary<string, object> BuildBase(string type, string packageV
7878
return new Dictionary<string, object>
7979
{
8080
[MessageFields.Type] = type,
81-
["messageId"] = Guid.NewGuid().ToString(),
82-
["eventTimestamp"] = DateTime.UtcNow.ToString(Constants.IsoTimestampFormat),
83-
["context"] = new Dictionary<string, object>
81+
[MessageFields.MessageId] = Guid.NewGuid().ToString(),
82+
[MessageFields.EventTimestamp] = DateTime.UtcNow.ToString(Constants.IsoTimestampFormat),
83+
[MessageFields.Context] = new Dictionary<string, object>
8484
{
85-
["library"] = Constants.LibraryName,
86-
["libraryVersion"] = Truncate(packageVersion, Constants.MaxFieldLength)
85+
[MessageFields.Library] = Constants.LibraryName,
86+
[MessageFields.LibraryVersion] = Truncate(packageVersion, Constants.MaxFieldLength)
8787
},
88-
["surface"] = Constants.Surface
88+
[MessageFields.Surface] = Constants.Surface
8989
};
9090
}
9191

src/Packages/Audience/Runtime/ImmutableAudience.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -441,15 +441,15 @@ public static Task DeleteData(string? userId = null)
441441
string query;
442442
if (!string.IsNullOrEmpty(userId))
443443
{
444-
query = "userId=" + Uri.EscapeDataString(userId);
444+
query = $"{MessageFields.UserId}=" + Uri.EscapeDataString(userId);
445445
}
446446
else
447447
{
448448
// Get (not GetOrCreate): a fresh install must not register an id just to delete it.
449449
var anonymousId = Identity.Get(config.PersistentDataPath!);
450450
if (string.IsNullOrEmpty(anonymousId))
451451
return Task.CompletedTask;
452-
query = "anonymousId=" + Uri.EscapeDataString(anonymousId);
452+
query = $"{MessageFields.AnonymousId}=" + Uri.EscapeDataString(anonymousId);
453453
}
454454

455455
var url = Constants.DataUrl(config.PublishableKey, config.BaseUrl) + "?" + query;
@@ -626,7 +626,7 @@ private static void SyncConsentToBackend(AudienceConfig config, ConsentLevel lev
626626
[ConsentBodyFields.Status] = level.ToLowercaseString(),
627627
[ConsentBodyFields.Source] = Constants.ConsentSource,
628628
// Explicit null lets the backend distinguish "unknown" from a missing field.
629-
["anonymousId"] = anonymousId!,
629+
[MessageFields.AnonymousId] = anonymousId!,
630630
});
631631

632632
Task.Run(async () =>
@@ -925,10 +925,10 @@ private static void MergeUnityContext(Dictionary<string, object>? msg)
925925
}
926926
if (extra == null) return;
927927

928-
if (!(msg.TryGetValue("context", out var ctxObj) && ctxObj is Dictionary<string, object> ctx))
928+
if (!(msg.TryGetValue(MessageFields.Context, out var ctxObj) && ctxObj is Dictionary<string, object> ctx))
929929
{
930930
ctx = new Dictionary<string, object>();
931-
msg["context"] = ctx;
931+
msg[MessageFields.Context] = ctx;
932932
}
933933

934934
foreach (var kv in extra)

src/Packages/Audience/Tests/Runtime/ConsentSyncTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ public void SetConsent_FiresPut_WithExpectedBodyShape()
4545
Assert.AreEqual(Constants.ConsentUrl("pk_imapik-test-key1"), put.Url);
4646
Assert.AreEqual(ConsentLevel.Full.ToLowercaseString(), body[ConsentBodyFields.Status]);
4747
Assert.AreEqual(Constants.ConsentSource, body[ConsentBodyFields.Source]);
48-
Assert.IsTrue(body.ContainsKey("anonymousId"));
49-
Assert.IsNotNull(body["anonymousId"], "upgrade PUT must carry the current anonymousId");
48+
Assert.IsTrue(body.ContainsKey(MessageFields.AnonymousId));
49+
Assert.IsNotNull(body[MessageFields.AnonymousId], "upgrade PUT must carry the current anonymousId");
5050
}
5151

5252
[Test]
@@ -67,7 +67,7 @@ public void SetConsent_None_PutCarriesOldAnonymousId_AfterReset()
6767
var body = JsonReader.DeserializeObject(put.Body);
6868

6969
Assert.AreEqual(ConsentLevel.None.ToLowercaseString(), body[ConsentBodyFields.Status]);
70-
Assert.AreEqual(seeded, body["anonymousId"],
70+
Assert.AreEqual(seeded, body[MessageFields.AnonymousId],
7171
"revocation PUT must carry the id that was revoked, not null");
7272
Assert.IsFalse(File.Exists(AudiencePaths.IdentityFile(_testDir)),
7373
"precondition: Identity.Reset ran");

src/Packages/Audience/Tests/Runtime/Events/MessageBuilderTests.cs

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ public void Track_RequiredFieldsPresent()
1515
{
1616
var result = MessageBuilder.Track("level_complete", "anon-1", null, PackageVersion);
1717

18-
Assert.AreEqual("track", result["type"]);
19-
Assert.IsTrue(result.ContainsKey("messageId"));
20-
Assert.IsTrue(result.ContainsKey("eventTimestamp"));
21-
Assert.IsTrue(result.ContainsKey("context"));
22-
Assert.IsTrue(result.ContainsKey("surface"));
23-
Assert.AreEqual("level_complete", result["eventName"]);
18+
Assert.AreEqual("track", result[MessageFields.Type]);
19+
Assert.IsTrue(result.ContainsKey(MessageFields.MessageId));
20+
Assert.IsTrue(result.ContainsKey(MessageFields.EventTimestamp));
21+
Assert.IsTrue(result.ContainsKey(MessageFields.Context));
22+
Assert.IsTrue(result.ContainsKey(MessageFields.Surface));
23+
Assert.AreEqual("level_complete", result[MessageFields.EventName]);
2424
}
2525

2626
[Test]
@@ -30,47 +30,47 @@ public void Track_EventNameLongerThan256Chars_TruncatedTo256()
3030

3131
var result = MessageBuilder.Track(longName, null, null, PackageVersion);
3232

33-
Assert.AreEqual(256, ((string)result["eventName"]).Length);
33+
Assert.AreEqual(256, ((string)result[MessageFields.EventName]).Length);
3434
}
3535

3636
[Test]
3737
public void Track_NullUserId_NotPresentInDict()
3838
{
3939
var result = MessageBuilder.Track("evt", "anon-1", null, PackageVersion);
4040

41-
Assert.IsFalse(result.ContainsKey("userId"));
41+
Assert.IsFalse(result.ContainsKey(MessageFields.UserId));
4242
}
4343

4444
[Test]
4545
public void Track_NonNullUserId_PresentInDict()
4646
{
4747
var result = MessageBuilder.Track("evt", "anon-1", "user-99", PackageVersion);
4848

49-
Assert.IsTrue(result.ContainsKey("userId"));
50-
Assert.AreEqual("user-99", result["userId"]);
49+
Assert.IsTrue(result.ContainsKey(MessageFields.UserId));
50+
Assert.AreEqual("user-99", result[MessageFields.UserId]);
5151
}
5252

5353
[Test]
5454
public void Identify_TypeAndIdentityFieldsPresent()
5555
{
5656
var result = MessageBuilder.Identify("anon-42", "user-42", "steam", PackageVersion);
5757

58-
Assert.AreEqual("identify", result["type"]);
59-
Assert.AreEqual("anon-42", result["anonymousId"]);
60-
Assert.AreEqual("user-42", result["userId"]);
61-
Assert.AreEqual("steam", result["identityType"]);
58+
Assert.AreEqual("identify", result[MessageFields.Type]);
59+
Assert.AreEqual("anon-42", result[MessageFields.AnonymousId]);
60+
Assert.AreEqual("user-42", result[MessageFields.UserId]);
61+
Assert.AreEqual("steam", result[MessageFields.IdentityType]);
6262
}
6363

6464
[Test]
6565
public void Alias_AllFourFieldsPresent()
6666
{
6767
var result = MessageBuilder.Alias("from-id", "email", "to-id", "steam", PackageVersion);
6868

69-
Assert.AreEqual("alias", result["type"]);
70-
Assert.AreEqual("from-id", result["fromId"]);
71-
Assert.AreEqual("email", result["fromType"]);
72-
Assert.AreEqual("to-id", result["toId"]);
73-
Assert.AreEqual("steam", result["toType"]);
69+
Assert.AreEqual("alias", result[MessageFields.Type]);
70+
Assert.AreEqual("from-id", result[MessageFields.FromId]);
71+
Assert.AreEqual("email", result[MessageFields.FromType]);
72+
Assert.AreEqual("to-id", result[MessageFields.ToId]);
73+
Assert.AreEqual("steam", result[MessageFields.ToType]);
7474
}
7575

7676
[Test]
@@ -82,9 +82,9 @@ public void AllMessages_ContextContainsLibraryAndLibraryVersion()
8282

8383
foreach (var msg in new[] { track, identify, alias })
8484
{
85-
var ctx = (Dictionary<string, object>)msg["context"];
86-
Assert.AreEqual(Constants.LibraryName, ctx["library"]);
87-
Assert.AreEqual(PackageVersion, ctx["libraryVersion"]);
85+
var ctx = (Dictionary<string, object>)msg[MessageFields.Context];
86+
Assert.AreEqual(Constants.LibraryName, ctx[MessageFields.Library]);
87+
Assert.AreEqual(PackageVersion, ctx[MessageFields.LibraryVersion]);
8888
}
8989
}
9090

@@ -95,17 +95,17 @@ public void AllMessages_SurfaceIsUnity()
9595
var identify = MessageBuilder.Identify(null, "u1", "steam", PackageVersion);
9696
var alias = MessageBuilder.Alias("f", "t1", "t", "t2", PackageVersion);
9797

98-
Assert.AreEqual("unity", track["surface"]);
99-
Assert.AreEqual("unity", identify["surface"]);
100-
Assert.AreEqual("unity", alias["surface"]);
98+
Assert.AreEqual("unity", track[MessageFields.Surface]);
99+
Assert.AreEqual("unity", identify[MessageFields.Surface]);
100+
Assert.AreEqual("unity", alias[MessageFields.Surface]);
101101
}
102102

103103
[Test]
104104
public void AllMessages_MessageId_ParsesAsGuid()
105105
{
106106
foreach (var msg in EveryMessageType())
107107
{
108-
var id = (string)msg["messageId"];
108+
var id = (string)msg[MessageFields.MessageId];
109109
Assert.IsTrue(Guid.TryParse(id, out _),
110110
$"messageId must parse as Guid; got: '{id}'");
111111
}
@@ -117,7 +117,7 @@ public void Track_MessageId_IsUniquePerCall()
117117
// Backend deduplicates on messageId; collisions silently drop events.
118118
var ids = new HashSet<string>();
119119
for (var i = 0; i < 1000; i++)
120-
ids.Add((string)MessageBuilder.Track("evt", null, null, PackageVersion)["messageId"]);
120+
ids.Add((string)MessageBuilder.Track("evt", null, null, PackageVersion)[MessageFields.MessageId]);
121121
Assert.AreEqual(1000, ids.Count);
122122
}
123123

@@ -130,7 +130,7 @@ public void AllMessages_EventTimestamp_IsRoundTripIso8601Utc()
130130
var before = DateTime.UtcNow.AddSeconds(-2);
131131
foreach (var msg in EveryMessageType())
132132
{
133-
var ts = (string)msg["eventTimestamp"];
133+
var ts = (string)msg[MessageFields.EventTimestamp];
134134
Assert.IsTrue(
135135
DateTime.TryParseExact(ts, "o", CultureInfo.InvariantCulture,
136136
DateTimeStyles.RoundtripKind, out var parsed),
@@ -148,9 +148,9 @@ public void AllMessages_Context_LibraryAndLibraryVersionAreNonEmptyStrings()
148148
{
149149
foreach (var msg in EveryMessageType())
150150
{
151-
var ctx = (Dictionary<string, object>)msg["context"];
152-
var library = ctx["library"] as string;
153-
var libraryVersion = ctx["libraryVersion"] as string;
151+
var ctx = (Dictionary<string, object>)msg[MessageFields.Context];
152+
var library = ctx[MessageFields.Library] as string;
153+
var libraryVersion = ctx[MessageFields.LibraryVersion] as string;
154154
Assert.IsFalse(string.IsNullOrEmpty(library), "context.library must be non-empty string");
155155
Assert.IsFalse(string.IsNullOrEmpty(libraryVersion), "context.libraryVersion must be non-empty string");
156156
}

0 commit comments

Comments
 (0)