epoll-j

refactor(auto_track): 更新配置方式并优化请求监听

## 0.0.1
## 0.0.7
* TODO: Describe initial release.
* remove dio dependency
* add http request listener
... ...
... ... @@ -29,9 +29,12 @@ class AutoTrackConfig {
this.enableClick = true, // 监听点击事件
this.enableDrag = false, // 监听拖拽事件
this.enableIgnoreNullKey = false, // 忽略空key事件
this.httpRequestConfig,
}) {
trackId ??= const Uuid().v4().replaceAll('-', '');
signature ??= (t) => sha256.convert(utf8.encode('$appKey$t$appSecret')).toString();
signature ??=
(t) => sha256.convert(utf8.encode('$appKey$t$appSecret')).toString();
httpRequestConfig ??= HttpRequestConfig();
}
String? host;
... ... @@ -77,6 +80,8 @@ class AutoTrackConfig {
bool enableIgnoreNullKey;
HttpRequestConfig? httpRequestConfig;
copyWith({
String? host,
String? appKey,
... ... @@ -98,6 +103,7 @@ class AutoTrackConfig {
bool? enableUpload,
bool? enableDrag,
bool? enableIgnoreNullKey,
HttpRequestConfig? httpRequestConfig
}) {
return AutoTrackConfig(
host: host ?? this.host,
... ... @@ -114,38 +120,14 @@ class AutoTrackConfig {
useCustomRoute: useCustomRoute ?? this.useCustomRoute,
ignoreElementKeys: ignoreElementKeys ?? this.ignoreElementKeys,
ignoreElementStringKeys:
ignoreElementStringKeys ?? this.ignoreElementStringKeys,
ignoreElementStringKeys ?? this.ignoreElementStringKeys,
enablePageView: enablePageView ?? this.enablePageView,
enablePageLeave: enablePageLeave ?? this.enablePageLeave,
enableClick: enableClick ?? this.enableClick,
enableUpload: enableUpload ?? this.enableUpload,
enableDrag: enableDrag ?? this.enableDrag,
enableIgnoreNullKey: enableIgnoreNullKey ?? this.enableIgnoreNullKey,
);
}
merge(AutoTrackConfig config) {
return copyWith(
host: config.host,
appKey: config.appKey,
appSecret: config.appSecret,
trackId: config.trackId,
userId: config.userId,
uniqueId: config.uniqueId,
samplingRate: config.samplingRate,
uploadInterval: config.uploadInterval,
signature: config.signature,
eventHandler: config.eventHandler,
pageConfigs: config.pageConfigs,
useCustomRoute: config.useCustomRoute,
ignoreElementKeys: config.ignoreElementKeys,
ignoreElementStringKeys: config.ignoreElementStringKeys,
enablePageView: config.enablePageView,
enablePageLeave: config.enablePageLeave,
enableClick: config.enableClick,
enableUpload: config.enableUpload,
enableDrag: config.enableDrag,
enableIgnoreNullKey: config.enableIgnoreNullKey,
httpRequestConfig: httpRequestConfig ?? this.httpRequestConfig
);
}
}
... ... @@ -153,13 +135,12 @@ class AutoTrackConfig {
typedef PageWidgetFunc = bool Function(Widget);
class AutoTrackPageConfig<T extends Widget> {
AutoTrackPageConfig({
this.pageID,
this.pagePath,
this.ignore = false,
this.pageTitle,
this.isPageWidget
}) {
AutoTrackPageConfig(
{this.pageID,
this.pagePath,
this.ignore = false,
this.pageTitle,
this.isPageWidget}) {
isPageWidget ??= (pageWidget) => pageWidget is T;
}
... ... @@ -169,3 +150,13 @@ class AutoTrackPageConfig<T extends Widget> {
String? pageTitle;
PageWidgetFunc? isPageWidget;
}
class HttpRequestConfig {
bool ignoreRequestHeader;
bool ignoreResponseHeader;
HttpRequestConfig({
this.ignoreRequestHeader = false,
this.ignoreResponseHeader = false,
});
}
... ...
... ... @@ -8,6 +8,8 @@ import 'package:package_info_plus/package_info_plus.dart';
import 'config.dart';
typedef UpdateConfigFunc = AutoTrackConfig Function(AutoTrackConfig);
class AutoTrackConfigManager {
static final AutoTrackConfigManager instance = AutoTrackConfigManager._();
... ... @@ -37,13 +39,15 @@ class AutoTrackConfigManager {
bool get autoTrackEnable => _autoTrackEnable;
void setConfig(AutoTrackConfig config) {
updateConfig(config);
updateConfig((old) {
return config;
});
_updateDeviceId();
}
void updateConfig(AutoTrackConfig config) {
_config = _config.merge(config);
if (config.enableUpload) {
void updateConfig(UpdateConfigFunc func) {
_config = func(_config);
if (_config.enableUpload) {
AutoTrackQueue.instance.start();
} else {
AutoTrackQueue.instance.stop();
... ...
... ... @@ -8,10 +8,12 @@ import 'package:auto_track/auto_track/utils/track_model.dart';
import '../log/logger.dart';
class AutoTrackQueue {
static final AutoTrackQueue instance = AutoTrackQueue._();
AutoTrackQueue._();
AutoTrackQueue._() {
httpClient.badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
}
Timer? _timer;
final List<TrackModel> _queue = [];
... ... @@ -24,7 +26,10 @@ class AutoTrackQueue {
void start() {
if (_timer != null) return;
_timer = Timer.periodic(Duration(seconds: AutoTrackConfigManager.instance.config.uploadInterval ?? 10), (timer) {
_timer = Timer.periodic(
Duration(
seconds: AutoTrackConfigManager.instance.config.uploadInterval ??
10), (timer) {
flush();
});
}
... ... @@ -48,15 +53,17 @@ class AutoTrackQueue {
}
if (host != null) {
final t = DateTime.now().millisecondsSinceEpoch;
httpClient.postUrl(Uri.parse(host)).then((request) {
request.headers.set(HttpHeaders.contentTypeHeader, 'application/json');
request.headers.contentType = ContentType.json;
request.write(json.encode({
'app_key': config.appKey ?? '',
'signature': config.signature!(t),
't': t,
'user_id': config.userId ?? '',
'track_id': config.trackId ?? '',
'unique_id': config.uniqueId ?? AutoTrackConfigManager.instance.deviceId,
'unique_id':
config.uniqueId ?? AutoTrackConfigManager.instance.deviceId,
'device_id': AutoTrackConfigManager.instance.deviceId,
'data_list': uploadList.map((e) => e.toMap()).toList(),
'app_version': AutoTrackConfigManager.instance.appVersion,
... ... @@ -64,10 +71,11 @@ class AutoTrackQueue {
}));
return request.close();
}).then((response) {
AutoTrackLogger.getInstance().debug('upload status => ${response.statusCode}');
AutoTrackLogger.getInstance()
.debug('upload status => ${response.statusCode}');
}).catchError((error) {
AutoTrackLogger.getInstance().error(error);
});
}
}
}
\ No newline at end of file
}
... ...
... ... @@ -19,11 +19,15 @@ class AutoTrack {
}
void updateUserId(String id) {
AutoTrackConfigManager.instance.updateConfig(AutoTrackConfig(userId: id));
AutoTrackConfigManager.instance.updateConfig((config) {
return config.copyWith(userId: id);
});
}
void updateSampleRate(double rate) {
AutoTrackConfigManager.instance.updateConfig(AutoTrackConfig(samplingRate: rate));
AutoTrackConfigManager.instance.updateConfig((config) {
return config.copyWith(samplingRate: rate);
});
}
AutoTrack config(AutoTrackConfig? config) {
... ... @@ -35,82 +39,112 @@ class AutoTrack {
AutoTrack pageConfigs(List<AutoTrackPageConfig>? pageConfigs) {
if (pageConfigs != null) {
AutoTrackConfigManager.instance.updateConfig(AutoTrackConfig(pageConfigs: pageConfigs));
AutoTrackConfigManager.instance.updateConfig((config) {
return config.copyWith(pageConfigs: pageConfigs);
});
}
return _instance;
}
AutoTrack ignoreElementKeys(List<Key>? ignoreElementKeys) {
if (ignoreElementKeys != null) {
AutoTrackConfigManager.instance.updateConfig(AutoTrackConfig(ignoreElementKeys: ignoreElementKeys));
AutoTrackConfigManager.instance.updateConfig((config) {
return config.copyWith(ignoreElementKeys: ignoreElementKeys);
});
}
return _instance;
}
AutoTrack ignoreElementStringKeys(List<String>? ignoreElementStringKeys) {
if (ignoreElementStringKeys != null) {
AutoTrackConfigManager.instance.updateConfig(AutoTrackConfig(ignoreElementStringKeys: ignoreElementStringKeys));
AutoTrackConfigManager.instance.updateConfig((config) {
return config.copyWith(ignoreElementStringKeys: ignoreElementStringKeys);
});
}
return _instance;
}
AutoTrack enablePageView() {
AutoTrackConfigManager.instance.updateConfig(AutoTrackConfig(enablePageView: true));
AutoTrackConfigManager.instance.updateConfig((config) {
return config.copyWith(enablePageView: true);
});
return _instance;
}
AutoTrack disablePageView() {
AutoTrackConfigManager.instance.updateConfig(AutoTrackConfig(enablePageView: false));
AutoTrackConfigManager.instance.updateConfig((config) {
return config.copyWith(enablePageView: false);
});
return _instance;
}
AutoTrack enablePageLeave() {
AutoTrackConfigManager.instance.updateConfig(AutoTrackConfig(enablePageLeave: true));
AutoTrackConfigManager.instance.updateConfig((config) {
return config.copyWith(enablePageLeave: true);
});
return _instance;
}
AutoTrack disablePageLeave() {
AutoTrackConfigManager.instance.updateConfig(AutoTrackConfig(enablePageLeave: false));
AutoTrackConfigManager.instance.updateConfig((config) {
return config.copyWith(enablePageLeave: false);
});
return _instance;
}
AutoTrack enableIgnoreNullKey() {
AutoTrackConfigManager.instance.updateConfig(AutoTrackConfig(enableIgnoreNullKey: true));
AutoTrackConfigManager.instance.updateConfig((config) {
return config.copyWith(enableIgnoreNullKey: true);
});
return _instance;
}
AutoTrack disableIgnoreNullKey() {
AutoTrackConfigManager.instance.updateConfig(AutoTrackConfig(enableIgnoreNullKey: false));
AutoTrackConfigManager.instance.updateConfig((config) {
return config.copyWith(enableIgnoreNullKey: false);
});
return _instance;
}
AutoTrack enableUpload() {
AutoTrackConfigManager.instance.updateConfig(AutoTrackConfig(enableUpload: true));
AutoTrackConfigManager.instance.updateConfig((config) {
return config.copyWith(enableUpload: true);
});
return _instance;
}
AutoTrack disableUpload() {
AutoTrackConfigManager.instance.updateConfig(AutoTrackConfig(enableUpload: false));
AutoTrackConfigManager.instance.updateConfig((config) {
return config.copyWith(enableUpload: false);
});
return _instance;
}
AutoTrack enableClick() {
AutoTrackConfigManager.instance.updateConfig(AutoTrackConfig(enableClick: true));
AutoTrackConfigManager.instance.updateConfig((config) {
return config.copyWith(enableClick: true);
});
return _instance;
}
AutoTrack disableClick() {
AutoTrackConfigManager.instance.updateConfig(AutoTrackConfig(enableClick: false));
AutoTrackConfigManager.instance.updateConfig((config) {
return config.copyWith(enableClick: false);
});
return _instance;
}
AutoTrack enableDrag() {
AutoTrackConfigManager.instance.updateConfig(AutoTrackConfig(enableDrag: true));
AutoTrackConfigManager.instance.updateConfig((config) {
return config.copyWith(enableDrag: true);
});
return _instance;
}
AutoTrack disableDrag() {
AutoTrackConfigManager.instance.updateConfig(AutoTrackConfig(enableDrag: false));
AutoTrackConfigManager.instance.updateConfig((config) {
return config.copyWith(enableDrag: false);
});
return _instance;
}
... ... @@ -125,6 +159,7 @@ class AutoTrack {
AutoTrackConfigManager.instance.enableAutoTrack(false);
PointerEventListener.instance.stop();
DragPointerEventListener.instance.stop();
disableHttpRequest();
return _instance;
}
... ...
... ... @@ -4,6 +4,7 @@ import 'dart:io';
import 'package:auto_track/auto_track/track/track.dart';
import '../../config/manager.dart';
import '../../utils/request_model.dart';
import '../page_view/page_stack.dart';
... ... @@ -65,7 +66,10 @@ class HttpClientRequestWithChecker implements HttpClientRequest {
uri: _realRequest.uri,
method: method,
pageId: pageInfoData?.pageInfo?.pageKey ?? "",
requestHeaders: _realRequest.headers,
requestHeaders: AutoTrackConfigManager
.instance.config.httpRequestConfig!.ignoreRequestHeader
? null
: _realRequest.headers,
message: message,
status: -1,
spent: _stopwatch.elapsedMilliseconds));
... ... @@ -123,13 +127,13 @@ class HttpClientRequestWithChecker implements HttpClientRequest {
message = '$message: ${response.reasonPhrase}';
_stopwatch.stop();
final config = AutoTrackConfigManager.instance.config.httpRequestConfig!;
Track.instance.reportHttpRequest(RequestModel(
uri: _realRequest.uri,
method: method,
pageId: pageInfoData?.pageInfo?.pageKey ?? "",
requestHeaders: request.headers,
responseHeaders: response.headers,
requestHeaders: config.ignoreRequestHeader ? null : request.headers,
responseHeaders: config.ignoreResponseHeader ? null : response.headers,
message: message,
status: response.statusCode,
spent: _stopwatch.elapsedMilliseconds));
... ... @@ -182,8 +186,8 @@ class HttpClientWithChecker implements HttpClient {
@override
set connectionFactory(
Future<ConnectionTask<Socket>> Function(
Uri url, String? proxyHost, int? proxyPort)?
f) {
Uri url, String? proxyHost, int? proxyPort)?
f) {
// TODO: add impl here
assert(false);
}
... ... @@ -228,30 +232,30 @@ class HttpClientWithChecker implements HttpClient {
@override
void addCredentials(
Uri url, String realm, HttpClientCredentials credentials) =>
Uri url, String realm, HttpClientCredentials credentials) =>
_realClient.addCredentials(url, realm, credentials);
@override
void addProxyCredentials(String host, int port, String realm,
HttpClientCredentials credentials) =>
HttpClientCredentials credentials) =>
_realClient.addProxyCredentials(host, port, realm, credentials);
@override
set authenticate(
Future<bool> Function(Uri url, String scheme, String? realm)? f) =>
Future<bool> Function(Uri url, String scheme, String? realm)? f) =>
_realClient.authenticate = f;
@override
set authenticateProxy(
Future<bool> Function(
String host, int port, String scheme, String? realm)?
f) =>
Future<bool> Function(
String host, int port, String scheme, String? realm)?
f) =>
_realClient.authenticateProxy = f;
@override
set badCertificateCallback(
bool Function(X509Certificate cert, String host, int port)?
callback) =>
bool Function(X509Certificate cert, String host, int port)?
callback) =>
_realClient.badCertificateCallback = callback;
@override
... ... @@ -329,7 +333,7 @@ class HttpClientWithChecker implements HttpClient {
path = path.substring(0, queryStart);
}
final Uri uri =
Uri(scheme: 'http', host: host, port: port, path: path, query: query);
Uri(scheme: 'http', host: host, port: port, path: path, query: query);
return _addCheck(_realClient.open(method, host, port, path), method, uri);
}
... ... @@ -339,11 +343,19 @@ class HttpClientWithChecker implements HttpClient {
Future<HttpClientRequest> _addCheck(
Future<HttpClientRequest> request, String method, Uri url) {
final host = AutoTrackConfigManager.instance.config.host;
if (host != null) {
final uploadUrl = Uri.parse(host);
if (uploadUrl.host == url.host && uploadUrl.path == url.path) {
return request;
}
}
final Stopwatch stopwatch = Stopwatch()..start();
final Page? pageInfoData = PageStack.instance.getCurrentPage();
return request
.then((HttpClientRequest request) =>
HttpClientRequestWithChecker(request, stopwatch, pageInfoData))
HttpClientRequestWithChecker(request, stopwatch, pageInfoData))
.catchError((dynamic error, dynamic stackTrace) {}, test: (error) {
String message = error.toString();
if (error is SocketException) {
... ... @@ -381,4 +393,3 @@ class AutoTrackHttpOverrides extends HttpOverrides {
return _currentOverrides!.findProxyFromEnvironment(url, environment);
}
}
... ...
... ... @@ -3,11 +3,11 @@ import 'package:auto_track/auto_track/utils/error_model.dart';
import 'package:auto_track/auto_track/utils/request_model.dart';
import 'package:auto_track/auto_track/utils/track_model.dart';
import '../listener/click/click_info.dart';
import '../config/manager.dart';
import '../listener/click/click_info.dart';
import '../listener/drag/drag_info.dart';
import '../log/logger.dart';
import '../listener/page_view/page_info.dart';
import '../log/logger.dart';
class Track {
static final Track instance = Track._();
... ... @@ -111,6 +111,7 @@ class Track {
}
void reportHttpRequest(RequestModel requestModel) {
_TrackPlugin.customEvent('http', requestModel.toMap(), key: requestModel.uri.path);
AutoTrackLogger.getInstance().debug('track request => ${requestModel.toMap()}');
}
}
... ... @@ -135,8 +136,8 @@ class _TrackPlugin {
AutoTrackQueue.instance.appendQueue(model);
}
static void customEvent(String type, Map<String, dynamic> params) {
var model = TrackModel(type, DateTime.now().millisecondsSinceEpoch, params, params['key'] ?? type);
static void customEvent(String type, Map<String, dynamic> params, { String? key }) {
var model = TrackModel(type, DateTime.now().millisecondsSinceEpoch, params, params['key'] ?? key ?? type);
AutoTrackConfigManager.instance.config.eventHandler?.call(model);
AutoTrackQueue.instance.appendQueue(model);
}
... ...
... ... @@ -6,7 +6,6 @@ class RequestModel {
required this.status,
required this.spent,
required this.pageId,
this.requestBody,
this.requestHeaders,
this.responseHeaders,
});
... ... @@ -17,21 +16,19 @@ class RequestModel {
String pageId;
int status;
int spent;
dynamic requestBody;
dynamic requestHeaders;
dynamic responseHeaders;
Map<String, dynamic> toMap() {
return {
'uri': uri,
'uri': uri.toString(),
'method': method,
'message': message,
'pageId': pageId,
'status': status,
'spent': spent,
'requestBody': requestBody,
'requestHeaders': requestHeaders,
'responseHeaders': responseHeaders,
'requestHeaders': requestHeaders.toString(),
'responseHeaders': responseHeaders.toString(),
};
}
}
\ No newline at end of file
... ...
name: auto_track
description: "Auto Track Plugin"
version: 0.0.6
description: "Low-intrusion global automatic embedding, automatically recording events such as page entry, exit, clicks, scrolling, and HTTP requests, and supporting custom events."
version: 0.0.7
homepage: https://github.com/epoll-j/auto_track_plugin
environment:
... ...