mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-08-06 15:21:21 +08:00
Analytics: Send to backend when possible
This commit is contained in:
@ -6,7 +6,10 @@ import 'package:uuid/uuid.dart';
|
||||
|
||||
import 'package:gitjournal/features.dart';
|
||||
import 'package:gitjournal/logger/logger.dart';
|
||||
import 'device_info.dart';
|
||||
import 'generated/analytics.pb.dart' as pb;
|
||||
import 'network.dart';
|
||||
import 'package_info.dart';
|
||||
import 'storage.dart';
|
||||
|
||||
enum Event {
|
||||
@ -114,6 +117,8 @@ class Analytics {
|
||||
|
||||
await storage.logEvent(_buildEvent(name, parameters));
|
||||
analyticsCallback(name, parameters);
|
||||
|
||||
await _sendAnalytics();
|
||||
}
|
||||
|
||||
Future<void> setCurrentScreen({required String screenName}) async {
|
||||
@ -138,6 +143,39 @@ class Analytics {
|
||||
userFirstTouchTimestamp: null,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _sendAnalytics() async {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
var oldestEvent = await storage.oldestEvent();
|
||||
if (DateTime.now().difference(oldestEvent) < const Duration(hours: 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
await storage.fetchAll((events) async {
|
||||
var msg = pb.AnalyticsMessage(
|
||||
appId: 'io.gitjournal',
|
||||
deviceInfo: await buildDeviceInfo(),
|
||||
packageInfo: await buildPackageInfo(),
|
||||
events: events,
|
||||
);
|
||||
Log.i("Sending ${events.length} events");
|
||||
var result = await sendAnalytics(msg);
|
||||
if (result.isFailure) {
|
||||
Log.e(
|
||||
"Failed to send Analytics",
|
||||
ex: result.error,
|
||||
stacktrace: result.stackTrace,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
Log.i("Sent ${events.length} Analytics Events");
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void logEvent(Event event, {Map<String, String> parameters = const {}}) {
|
||||
@ -149,3 +187,7 @@ String _eventToString(Event e) {
|
||||
var str = e.toString().substring('Event.'.length);
|
||||
return ReCase(str).snakeCase;
|
||||
}
|
||||
|
||||
// FIXME: Discard the old analytics, if there are way too many!
|
||||
// TODO: Take network connectivity into account
|
||||
// TODO: Take connection type (wifi vs mobile) into account
|
||||
|
@ -1,13 +1,17 @@
|
||||
import 'package:fixnum/fixnum.dart';
|
||||
import 'package:dart_git/utils/result.dart';
|
||||
import 'package:grpc/grpc.dart';
|
||||
|
||||
import 'package:gitjournal/analytics/generated/analytics.pbgrpc.dart';
|
||||
import 'generated/analytics.pb.dart' as pb;
|
||||
|
||||
Future<void> main(List<String> args) async {
|
||||
const _url = 'analyticsbackend-wetu2tkdpq-ew.a.run.app';
|
||||
const _port = 444;
|
||||
const _timeout = Duration(seconds: 30);
|
||||
|
||||
Future<Result<void>> sendAnalytics(pb.AnalyticsMessage msg) async {
|
||||
final channel = ClientChannel(
|
||||
'analyticsbackend-wetu2tkdpq-ew.a.run.app',
|
||||
port: 443,
|
||||
_url,
|
||||
port: _port,
|
||||
options: ChannelOptions(
|
||||
// credentials: const ChannelCredentials.insecure(),
|
||||
credentials: const ChannelCredentials.secure(),
|
||||
@ -18,38 +22,21 @@ Future<void> main(List<String> args) async {
|
||||
),
|
||||
);
|
||||
|
||||
final stub = AnalyticsServiceClient(channel);
|
||||
final client = AnalyticsServiceClient(channel);
|
||||
try {
|
||||
var dt = DateTime.now().add(const Duration(days: -1));
|
||||
var ev = pb.Event(
|
||||
name: 'test',
|
||||
date: Int64(dt.millisecondsSinceEpoch ~/ 1000),
|
||||
params: {'a': 'hello'},
|
||||
pseudoId: 'id',
|
||||
userProperties: {'b': 'c'},
|
||||
sessionID: 'session',
|
||||
var call = client.sendData(
|
||||
msg,
|
||||
options: CallOptions(
|
||||
timeout: _timeout,
|
||||
compression: const GzipCodec(),
|
||||
),
|
||||
);
|
||||
|
||||
var request = AnalyticsMessage(
|
||||
appId: 'io.gitjournal',
|
||||
events: [ev],
|
||||
);
|
||||
print("Sending ${request.toDebugString()}");
|
||||
var call = stub.sendData(
|
||||
request,
|
||||
options: CallOptions(timeout: const Duration(seconds: 10)),
|
||||
);
|
||||
call.headers.then((headers) {
|
||||
print('Received header metadata: $headers');
|
||||
});
|
||||
call.trailers.then((trailers) {
|
||||
print('Received trailer metadata: $trailers');
|
||||
});
|
||||
var response = await call;
|
||||
print('Greeter client received: $response');
|
||||
} catch (e) {
|
||||
print('Caught error: $e');
|
||||
return;
|
||||
await call;
|
||||
} on Exception catch (e, st) {
|
||||
await channel.shutdown();
|
||||
return Result.fail(e, st);
|
||||
}
|
||||
|
||||
await channel.shutdown();
|
||||
return Result(null);
|
||||
}
|
||||
|
14
lib/analytics/package_info.dart
Normal file
14
lib/analytics/package_info.dart
Normal file
@ -0,0 +1,14 @@
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
import 'generated/analytics.pb.dart' as pb;
|
||||
|
||||
Future<pb.PackageInfo> buildPackageInfo() async {
|
||||
var info = await PackageInfo.fromPlatform();
|
||||
return pb.PackageInfo(
|
||||
appName: info.appName,
|
||||
packageName: info.packageName,
|
||||
version: info.version,
|
||||
buildNumber: info.buildNumber,
|
||||
buildSignature: info.buildSignature,
|
||||
);
|
||||
}
|
@ -15,7 +15,7 @@ import 'package:quick_actions/quick_actions.dart';
|
||||
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:universal_io/io.dart' show Platform;
|
||||
import 'package:universal_io/io.dart' show Directory, Platform;
|
||||
|
||||
import 'package:gitjournal/analytics/analytics.dart';
|
||||
import 'package:gitjournal/analytics/route_observer.dart';
|
||||
@ -131,8 +131,10 @@ class JournalApp extends StatefulWidget {
|
||||
|
||||
var supportDir = await getApplicationSupportDirectory();
|
||||
var analyticsStorage = p.join(supportDir.path, 'analytics');
|
||||
await Directory(analyticsStorage).create(recursive: true);
|
||||
|
||||
Log.d("Analytics Collection: $enabled");
|
||||
Log.d("Analytics Storage: $analyticsStorage");
|
||||
var analytics = Analytics.init(
|
||||
enable: enabled,
|
||||
pref: pref,
|
||||
|
Reference in New Issue
Block a user