Skip to content

Commit 16dc196

Browse files
committed
Change to a different stat tracking paradigm.
1 parent 8518894 commit 16dc196

File tree

7 files changed

+84
-48
lines changed

7 files changed

+84
-48
lines changed

lib/src/auth/codelessly_auth_manager.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ class CodelesslyAuthManager extends AuthManager {
371371
);
372372

373373
try {
374+
// TODO(Saad): Use an HTTP client.
374375
// Make a POST request to the server to verify the token.
375376
final Response result = await post(
376377
Uri.parse(

lib/src/codelessly.dart

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import 'package:flutter/widgets.dart';
1010
import '../codelessly_sdk.dart';
1111
import 'logging/reporter.dart';
1212

13-
const String clientType = String.fromEnvironment('client_type');
14-
1513
typedef NavigationListener = void Function(BuildContext context);
1614
typedef BreakpointsListener = void Function(
1715
BuildContext context, Breakpoint breakpoint);
@@ -128,7 +126,7 @@ class Codelessly {
128126
final StreamController<CStatus> _statusStreamController =
129127
StreamController.broadcast()..add(CStatus.empty());
130128

131-
final StatTracker _tracker = FirestoreStatTracker();
129+
final StatTracker _tracker = CodelesslyStatTracker();
132130

133131
/// Tracks statistics of various operations in the SDK.
134132
StatTracker get tracker => _tracker;
@@ -641,7 +639,10 @@ class Codelessly {
641639
_config!.publishSource = _authManager!.getBestPublishSource(_config!);
642640

643641
if (_authManager?.authData?.projectId case String projectId) {
644-
tracker.init(projectId);
642+
tracker.init(
643+
projectId: projectId,
644+
serverUrl: Uri.parse(_config!.firebaseCloudFunctionsBaseURL),
645+
);
645646
}
646647

647648
_updateStatus(CStatus.loading(CLoadingState.initializedAuth));
@@ -692,7 +693,10 @@ class Codelessly {
692693
if (_authManager!.authData == null) return;
693694

694695
if (_authManager?.authData?.projectId case String projectId) {
695-
tracker.init(projectId);
696+
tracker.init(
697+
projectId: projectId,
698+
serverUrl: Uri.parse(_config!.firebaseCloudFunctionsBaseURL),
699+
);
696700
}
697701

698702
log('[POST-INIT] Background authentication succeeded. Initializing layout storage.');

lib/src/constants.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const String clientType = String.fromEnvironment('client_type');
2+
13
const String kCodelesslyFirebaseApp = 'codelessly';
24

35
const String defaultFirebaseProjectId = String.fromEnvironment(

lib/src/data/network_data_repository.dart

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ abstract class NetworkDataRepository {
1515
/// The [CodelesslyConfig] instance that is used to configure the SDK.
1616
final CodelesslyConfig config;
1717

18-
/// The [FirestoreStatTracker] instance to track the statistics of the data repository.
18+
/// The [StatTracker] instance to track the statistics of the data repository.
1919
final StatTracker tracker;
2020

2121
/// Creates a new instance of [NetworkDataRepository].
@@ -69,40 +69,6 @@ abstract class NetworkDataRepository {
6969
}
7070
}
7171

72-
/// Calls a cloud function that searches for the project associated with the
73-
/// given unique slug and returns a completely populated [SDKPublishModel]
74-
/// instance.
75-
// Future<SDKPublishModel?> downloadCompletePublishBundle({
76-
// required String slug,
77-
// required PublishSource source,
78-
// }) async {
79-
// logger.log(_label, 'Downloading publish bundle with slug: $slug and source: $source');
80-
// final http.Response result = await http.post(
81-
// Uri.parse(
82-
// '${config.firebaseCloudFunctionsBaseURL}/getPublishBundleBySlugRequest'),
83-
// headers: <String, String>{'Content-Type': 'application/json'},
84-
// body: jsonEncode({'slug': slug, 'source': source.serverPath}),
85-
// encoding: utf8,
86-
// );
87-
//
88-
// if (result.statusCode != 200) {
89-
// logger.log(_label, 'Error downloading publish bundle.');
90-
// logger.log(_label, 'Status code: ${result.statusCode}');
91-
// logger.log(_label, 'Message: ${result.body}');
92-
// CodelesslyErrorHandler.instance.captureException(CodelesslyException(
93-
// 'Error downloading publish bundle from slug [$slug]',
94-
// stacktrace: StackTrace.current,
95-
// ));
96-
// return null;
97-
// }
98-
//
99-
// final Map<String, dynamic> modelDoc = jsonDecode(result.body);
100-
// final SDKPublishModel model = SDKPublishModel.fromJson(modelDoc);
101-
//
102-
// logger.log(_label, 'Finished downloading publish bundle with slug: $slug and source: $source.');
103-
// return model;
104-
// }
105-
10672
/// Streams a given [projectID]'s associated [SDKPublishModel] from the
10773
/// network with preferably live updates.
10874
Stream<SDKPublishModel?> streamPublishModel({

lib/src/data/web_data_repository.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class WebDataRepository extends NetworkDataRepository {
2424
required String projectID,
2525
required PublishSource source,
2626
}) async* {
27+
// TODO(Saad): Use an HTTP client.
2728
final Response result = await post(
2829
Uri.parse(
2930
'${config.firebaseCloudFunctionsBaseURL}/api/getPublishModelRequest'),
@@ -56,6 +57,7 @@ class WebDataRepository extends NetworkDataRepository {
5657
required String layoutID,
5758
required PublishSource source,
5859
}) async {
60+
// TODO(Saad): Use an HTTP client.
5961
final Response result = await post(
6062
Uri.parse(
6163
'${config.firebaseCloudFunctionsBaseURL}/api/getLayoutModelRequest'),
@@ -92,6 +94,7 @@ class WebDataRepository extends NetworkDataRepository {
9294
required PublishSource source,
9395
}) async {
9496
try {
97+
// TODO(Saad): Use an HTTP client.
9598
final Response result = await post(
9699
Uri.parse(
97100
'${config.firebaseCloudFunctionsBaseURL}/api/getFontModelRequest'),
@@ -129,6 +132,7 @@ class WebDataRepository extends NetworkDataRepository {
129132
required PublishSource source,
130133
}) async {
131134
try {
135+
// TODO(Saad): Use an HTTP client.
132136
final Response result = await post(
133137
Uri.parse(
134138
'${config.firebaseCloudFunctionsBaseURL}/api/getPublishedApiRequest'),
@@ -168,6 +172,7 @@ class WebDataRepository extends NetworkDataRepository {
168172
required PublishSource source,
169173
}) async {
170174
try {
175+
// TODO(Saad): Use an HTTP client.
171176
final Response result = await post(
172177
Uri.parse(
173178
'${config.firebaseCloudFunctionsBaseURL}/api/getPublishedLayoutVariablesRequest'),
@@ -209,6 +214,7 @@ class WebDataRepository extends NetworkDataRepository {
209214
}) async {
210215
log('[WebDataRepo] Downloading conditions for $layoutID');
211216
try {
217+
// TODO(Saad): Use an HTTP client.
212218
final Response result = await post(
213219
Uri.parse(
214220
'${config.firebaseCloudFunctionsBaseURL}/api/getPublishedLayoutConditionsRequest'),

lib/src/functions/functions_repository.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ class FunctionsRepository {
422422
reasonPhrase: actualResponse['reasonPhrase']?.toString(),
423423
);
424424
} else {
425+
// TODO(Saad): Use an HTTP client.
425426
final Uri uri = Uri.parse(url);
426427
response = switch (method) {
427428
HttpMethod.get => await http.get(uri, headers: headers),
@@ -522,6 +523,7 @@ ${response.body.contains('{') ? const JsonEncoder.withIndent(' ').convert(json.
522523
required Object? body,
523524
required String cloudFunctionsURL,
524525
}) async {
526+
// TODO(Saad): Use an HTTP client.
525527
return http.post(
526528
Uri.parse('$cloudFunctionsURL/makeApiRequest'),
527529
headers: {'content-type': 'application/json'},

lib/src/logging/stat_tracker.dart

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,30 @@
1+
import 'dart:convert';
2+
13
import 'package:codelessly_api/codelessly_api.dart';
4+
import 'package:collection/collection.dart';
5+
import 'package:http/http.dart';
6+
import 'package:meta/meta.dart';
27

3-
import '../constants.dart';
8+
import '../../codelessly_sdk.dart';
49
import '../utils/debouncer.dart';
510

611
/// A class that tracks statistics of various operations in the SDK.
712
abstract class StatTracker {
13+
Uri? serverUrl;
14+
815
/// The project ID to track the statistics for.
916
String? projectId;
1017

1118
bool get didInitialize => projectId != null;
1219

13-
void init(String projectId) => this.projectId = projectId;
20+
@mustCallSuper
21+
void init({
22+
required String projectId,
23+
required Uri serverUrl,
24+
}) {
25+
this.projectId = projectId;
26+
this.serverUrl = serverUrl;
27+
}
1428

1529
/// Tracks one document read operation.
1630
Future<void> trackRead(String label);
@@ -31,21 +45,50 @@ abstract class StatTracker {
3145
Future<void> trackCloudAction(ActionModel action);
3246
}
3347

34-
/// A [StatTracker] implementation that utilizes Firestore to track the
35-
/// statistics.
36-
final class FirestoreStatTracker extends StatTracker {
48+
/// A [StatTracker] implementation that sends the stats to Codelessly's server.
49+
final class CodelesslyStatTracker extends StatTracker {
50+
@override
51+
void init({
52+
required String projectId,
53+
required Uri serverUrl,
54+
}) {
55+
super.init(projectId: projectId, serverUrl: serverUrl);
56+
57+
// Send a batch if stats were tracked while this wasn't initialized yet.
58+
if (statBatch.isNotEmpty && !disabled) {
59+
sendBatch();
60+
}
61+
}
3762

3863
/// The field name to track the number of each operation.
3964
final Map<String, int> statBatch = {};
4065

41-
/// Debounces the batch sending of the stats to prevent spamming the Firestore
66+
/// Debounces the batch sending of the stats to prevent spamming the server
4267
/// with too many writes.
4368
final DeBouncer debouncer = DeBouncer(const Duration(seconds: 1));
4469

45-
/// Sends the batch of stats to the Firestore.
70+
bool get disabled =>
71+
clientType == kCodelesslyEditor || projectId == null || serverUrl == null;
72+
73+
/// Sends the batch of stats to the server.
4674
Future<void> sendBatch() => debouncer.run(
4775
() async {
48-
// TODO: call api endpoint.
76+
// TODO(Saad): Use an HTTP client.
77+
post(
78+
serverUrl!,
79+
body: jsonEncode({
80+
'projectId': projectId,
81+
'stats': {
82+
for (final entry in statBatch.entries
83+
.whereNot((entry) => entry.key == writesField))
84+
entry.key: entry.value,
85+
86+
// Account for this stat tracking operation as an additional write
87+
// operation.
88+
writesField: (statBatch[writesField] ?? 0) + 1,
89+
},
90+
}),
91+
);
4992
statBatch.clear();
5093
},
5194
forceRunAfter: 20,
@@ -57,36 +100,48 @@ final class FirestoreStatTracker extends StatTracker {
57100

58101
@override
59102
Future<void> trackRead(String label) {
103+
if (disabled) return Future.value();
104+
60105
incrementField('$readsField/$label');
61106
return sendBatch();
62107
}
63108

64109
@override
65110
Future<void> trackWrite(String label) {
111+
if (disabled) return Future.value();
112+
66113
incrementField('$writesField/$label');
67114
return sendBatch();
68115
}
69116

70117
@override
71118
Future<void> trackBundleDownload() {
119+
if (disabled) return Future.value();
120+
72121
incrementField(bundleDownloadsField);
73122
return sendBatch();
74123
}
75124

76125
@override
77126
Future<void> trackFontDownload() {
127+
if (disabled) return Future.value();
128+
78129
incrementField(fontDownloadsField);
79130
return sendBatch();
80131
}
81132

82133
@override
83134
Future<void> trackAction(ActionModel action) {
135+
if (disabled) return Future.value();
136+
84137
incrementField('$actionsField/${action.type.name}');
85138
return sendBatch();
86139
}
87140

88141
@override
89142
Future<void> trackCloudAction(ActionModel action) {
143+
if (disabled) return Future.value();
144+
90145
incrementField('$cloudActionsField/${action.type.name}');
91146
return sendBatch();
92147
}

0 commit comments

Comments
 (0)