/
k-freq-measurement-worklet.js
92 lines (81 loc) · 3.53 KB
/
k-freq-measurement-worklet.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/**
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* The scale factor is multiplied by the aggregatable value to maximize
* the signal-to-noise ratio. See “Noise and scaling” section in the
* Aggregation Fundamentals document to learn more:
* - https://developer.chrome.com/en/docs/privacy-sandbox/aggregation-fundamentals
*
* The scale factor used here has been intentionally reduced to an arbitrary number.
* The maximum aggregatable value used in this demo is 1. The scale factor
* of 65536 would have maximized the signal-to-noise ratio. However, that also
* uses the entire contribution budget for the rolling 24-hour period.
*
* Therefore, the scale factor has been significantly reduced to allow the demo
* to be used repeatedly for testing throughout without hitting the contribution
* budget limit.
*/
const SCALE_FACTOR = 128;
/**
* The bucket key must be a number, and in this case, it is simply the content
* ID itself. For more complex buckey key construction, see other use cases in
* this demo.
*/
function convertContentIdToBucket(contentId) {
return BigInt(contentId);
}
class KFreqMeasurementOperation {
async run(data) {
try {
const { kFreq, contentId, debugKey } = data;
// Read from Shared Storage
const hasReportedContentKey = 'has-reported-content';
const impressionCountKey = 'impression-count';
const hasReportedContent = (await sharedStorage.get(hasReportedContentKey)) === 'true';
const impressionCount = parseInt((await sharedStorage.get(impressionCountKey)) || 0);
// Do not report if a report has been sent already
if (hasReportedContent) {
console.log(
`[PAA] K-frequency report has been submitted already for Content ID ${contentId}. Reset the demo to start over.`
);
return;
}
// Check ipmression count against frequency limit
if (impressionCount < kFreq) {
console.log(
`[PAA] Current impression count is ${impressionCount} and has not met the K threashold of ${kFreq}`
);
await sharedStorage.set(impressionCountKey, impressionCount + 1);
return;
}
// Generate the aggregation key and the aggregatable value
const bucket = convertContentIdToBucket(contentId);
const value = 1 * SCALE_FACTOR;
// Send an aggregatable report via the Private Aggregation API
privateAggregation.enableDebugMode({ debugKey });
privateAggregation.contributeToHistogram({ bucket, value });
// Set the report submission status flag
await sharedStorage.set(hasReportedContentKey, 'true');
console.log(`[PAA] Current impression count is ${impressionCount} which meets the K threashold of ${kFreq}`);
console.log('[PAA] K-frequency measurement report will be submitted');
console.log(`[PAA] The aggregation key is ${bucket} and the aggregatable value is ${value}`);
} catch (e) {
console.log(e);
}
}
}
// Register the operation
register('k-freq-measurement', KFreqMeasurementOperation);