Committed by
GitHub
Merge pull request #2 from epoll-j/feat/request-listener
Feat/request listener
Showing
22 changed files
with
658 additions
and
137 deletions
@@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
2 | 2 | ||
3 | > Flutter全埋点插件,支持 Android 和 iOS | 3 | > Flutter全埋点插件,支持 Android 和 iOS |
4 | 4 | ||
5 | -低侵入全局自动埋点,自动记录页面进入、退出,点击、滑动等事件,并支持自定义事件。 | 5 | +低侵入全局自动埋点,自动记录页面进入、退出,点击、滑动、http请求等事件,并支持自定义事件。 |
6 | 6 | ||
7 | 7 | ||
8 | ## Getting Started 使用指南 | 8 | ## Getting Started 使用指南 |
@@ -69,6 +69,7 @@ class _MyAppState extends State<MyApp> { | @@ -69,6 +69,7 @@ class _MyAppState extends State<MyApp> { | ||
69 | .enableClick() // 启用点击统计 | 69 | .enableClick() // 启用点击统计 |
70 | .enableDrag() // 启用滑动统计 | 70 | .enableDrag() // 启用滑动统计 |
71 | .enableIgnoreNullKey() // 忽略空的key,如果不忽略,没有配置key的页面或事件会基于一定的规则生成一个随机的key进行上报统计 | 71 | .enableIgnoreNullKey() // 忽略空的key,如果不忽略,没有配置key的页面或事件会基于一定的规则生成一个随机的key进行上报统计 |
72 | + .enableHttpRequest() // 启用http请求监听 | ||
72 | .enableLog(); // 启用日志,建议在debug模式下开启,会打印一些埋点相关的日志 | 73 | .enableLog(); // 启用日志,建议在debug模式下开启,会打印一些埋点相关的日志 |
73 | 74 | ||
74 | super.initState(); | 75 | super.initState(); |
@@ -2,7 +2,7 @@ library autotrack; | @@ -2,7 +2,7 @@ library autotrack; | ||
2 | 2 | ||
3 | export './auto_track/index.dart'; | 3 | export './auto_track/index.dart'; |
4 | export './auto_track/config/config.dart'; | 4 | export './auto_track/config/config.dart'; |
5 | -export './auto_track/page_view/navigation_observer.dart'; | ||
6 | -export './auto_track/click/navigator_key.dart'; | ||
7 | -export './auto_track/click/element_key.dart'; | 5 | +export './auto_track/listener/page_view/navigation_observer.dart'; |
6 | +export './auto_track/listener/click/navigator_key.dart'; | ||
7 | +export './auto_track/listener/click/element_key.dart'; | ||
8 | export './auto_track/log/logger.dart'; | 8 | export './auto_track/log/logger.dart'; |
@@ -29,9 +29,12 @@ class AutoTrackConfig { | @@ -29,9 +29,12 @@ class AutoTrackConfig { | ||
29 | this.enableClick = true, // 监听点击事件 | 29 | this.enableClick = true, // 监听点击事件 |
30 | this.enableDrag = false, // 监听拖拽事件 | 30 | this.enableDrag = false, // 监听拖拽事件 |
31 | this.enableIgnoreNullKey = false, // 忽略空key事件 | 31 | this.enableIgnoreNullKey = false, // 忽略空key事件 |
32 | + this.httpRequestConfig, | ||
32 | }) { | 33 | }) { |
33 | trackId ??= const Uuid().v4().replaceAll('-', ''); | 34 | trackId ??= const Uuid().v4().replaceAll('-', ''); |
34 | - signature ??= (t) => sha256.convert(utf8.encode('$appKey$t$appSecret')).toString(); | 35 | + signature ??= |
36 | + (t) => sha256.convert(utf8.encode('$appKey$t$appSecret')).toString(); | ||
37 | + httpRequestConfig ??= HttpRequestConfig(); | ||
35 | } | 38 | } |
36 | 39 | ||
37 | String? host; | 40 | String? host; |
@@ -76,18 +79,68 @@ class AutoTrackConfig { | @@ -76,18 +79,68 @@ class AutoTrackConfig { | ||
76 | bool enableDrag; | 79 | bool enableDrag; |
77 | 80 | ||
78 | bool enableIgnoreNullKey; | 81 | bool enableIgnoreNullKey; |
82 | + | ||
83 | + HttpRequestConfig? httpRequestConfig; | ||
84 | + | ||
85 | + copyWith({ | ||
86 | + String? host, | ||
87 | + String? appKey, | ||
88 | + String? appSecret, | ||
89 | + String? trackId, | ||
90 | + String? userId, | ||
91 | + String? uniqueId, | ||
92 | + double? samplingRate, | ||
93 | + int? uploadInterval, | ||
94 | + Function? signature, | ||
95 | + EventHandlerFunc? eventHandler, | ||
96 | + List<AutoTrackPageConfig>? pageConfigs, | ||
97 | + bool? useCustomRoute, | ||
98 | + List<Key>? ignoreElementKeys, | ||
99 | + List<String>? ignoreElementStringKeys, | ||
100 | + bool? enablePageView, | ||
101 | + bool? enablePageLeave, | ||
102 | + bool? enableClick, | ||
103 | + bool? enableUpload, | ||
104 | + bool? enableDrag, | ||
105 | + bool? enableIgnoreNullKey, | ||
106 | + HttpRequestConfig? httpRequestConfig | ||
107 | + }) { | ||
108 | + return AutoTrackConfig( | ||
109 | + host: host ?? this.host, | ||
110 | + appKey: appKey ?? this.appKey, | ||
111 | + appSecret: appSecret ?? this.appSecret, | ||
112 | + trackId: trackId ?? this.trackId, | ||
113 | + userId: userId ?? this.userId, | ||
114 | + uniqueId: uniqueId ?? this.uniqueId, | ||
115 | + samplingRate: samplingRate ?? this.samplingRate, | ||
116 | + uploadInterval: uploadInterval ?? this.uploadInterval, | ||
117 | + signature: signature ?? this.signature, | ||
118 | + eventHandler: eventHandler ?? this.eventHandler, | ||
119 | + pageConfigs: pageConfigs ?? this.pageConfigs, | ||
120 | + useCustomRoute: useCustomRoute ?? this.useCustomRoute, | ||
121 | + ignoreElementKeys: ignoreElementKeys ?? this.ignoreElementKeys, | ||
122 | + ignoreElementStringKeys: | ||
123 | + ignoreElementStringKeys ?? this.ignoreElementStringKeys, | ||
124 | + enablePageView: enablePageView ?? this.enablePageView, | ||
125 | + enablePageLeave: enablePageLeave ?? this.enablePageLeave, | ||
126 | + enableClick: enableClick ?? this.enableClick, | ||
127 | + enableUpload: enableUpload ?? this.enableUpload, | ||
128 | + enableDrag: enableDrag ?? this.enableDrag, | ||
129 | + enableIgnoreNullKey: enableIgnoreNullKey ?? this.enableIgnoreNullKey, | ||
130 | + httpRequestConfig: httpRequestConfig ?? this.httpRequestConfig | ||
131 | + ); | ||
132 | + } | ||
79 | } | 133 | } |
80 | 134 | ||
81 | typedef PageWidgetFunc = bool Function(Widget); | 135 | typedef PageWidgetFunc = bool Function(Widget); |
82 | 136 | ||
83 | class AutoTrackPageConfig<T extends Widget> { | 137 | class AutoTrackPageConfig<T extends Widget> { |
84 | - AutoTrackPageConfig({ | ||
85 | - this.pageID, | ||
86 | - this.pagePath, | ||
87 | - this.ignore = false, | ||
88 | - this.pageTitle, | ||
89 | - this.isPageWidget | ||
90 | - }) { | 138 | + AutoTrackPageConfig( |
139 | + {this.pageID, | ||
140 | + this.pagePath, | ||
141 | + this.ignore = false, | ||
142 | + this.pageTitle, | ||
143 | + this.isPageWidget}) { | ||
91 | isPageWidget ??= (pageWidget) => pageWidget is T; | 144 | isPageWidget ??= (pageWidget) => pageWidget is T; |
92 | } | 145 | } |
93 | 146 | ||
@@ -97,3 +150,13 @@ class AutoTrackPageConfig<T extends Widget> { | @@ -97,3 +150,13 @@ class AutoTrackPageConfig<T extends Widget> { | ||
97 | String? pageTitle; | 150 | String? pageTitle; |
98 | PageWidgetFunc? isPageWidget; | 151 | PageWidgetFunc? isPageWidget; |
99 | } | 152 | } |
153 | + | ||
154 | +class HttpRequestConfig { | ||
155 | + bool ignoreRequestHeader; | ||
156 | + bool ignoreResponseHeader; | ||
157 | + | ||
158 | + HttpRequestConfig({ | ||
159 | + this.ignoreRequestHeader = false, | ||
160 | + this.ignoreResponseHeader = false, | ||
161 | + }); | ||
162 | +} |
@@ -8,6 +8,8 @@ import 'package:package_info_plus/package_info_plus.dart'; | @@ -8,6 +8,8 @@ import 'package:package_info_plus/package_info_plus.dart'; | ||
8 | 8 | ||
9 | import 'config.dart'; | 9 | import 'config.dart'; |
10 | 10 | ||
11 | +typedef UpdateConfigFunc = AutoTrackConfig Function(AutoTrackConfig); | ||
12 | + | ||
11 | class AutoTrackConfigManager { | 13 | class AutoTrackConfigManager { |
12 | static final AutoTrackConfigManager instance = AutoTrackConfigManager._(); | 14 | static final AutoTrackConfigManager instance = AutoTrackConfigManager._(); |
13 | 15 | ||
@@ -36,10 +38,16 @@ class AutoTrackConfigManager { | @@ -36,10 +38,16 @@ class AutoTrackConfigManager { | ||
36 | bool _autoTrackEnable = false; | 38 | bool _autoTrackEnable = false; |
37 | bool get autoTrackEnable => _autoTrackEnable; | 39 | bool get autoTrackEnable => _autoTrackEnable; |
38 | 40 | ||
39 | - void updateConfig(AutoTrackConfig config) { | ||
40 | - _config = config; | 41 | + void setConfig(AutoTrackConfig config) { |
42 | + updateConfig((old) { | ||
43 | + return config; | ||
44 | + }); | ||
41 | _updateDeviceId(); | 45 | _updateDeviceId(); |
42 | - if (config.enableUpload) { | 46 | + } |
47 | + | ||
48 | + void updateConfig(UpdateConfigFunc func) { | ||
49 | + _config = func(_config); | ||
50 | + if (_config.enableUpload) { | ||
43 | AutoTrackQueue.instance.start(); | 51 | AutoTrackQueue.instance.start(); |
44 | } else { | 52 | } else { |
45 | AutoTrackQueue.instance.stop(); | 53 | AutoTrackQueue.instance.stop(); |
@@ -58,59 +66,10 @@ class AutoTrackConfigManager { | @@ -58,59 +66,10 @@ class AutoTrackConfigManager { | ||
58 | } | 66 | } |
59 | } | 67 | } |
60 | 68 | ||
61 | - void updateUserId(String userId) { | ||
62 | - _config.userId = userId; | ||
63 | - } | ||
64 | - | ||
65 | - void updateSampleRate(double rate) { | ||
66 | - _config.samplingRate = rate; | ||
67 | - } | ||
68 | - | ||
69 | - void updatePageConfigs(List<AutoTrackPageConfig> pageConfigs) { | ||
70 | - _config.pageConfigs = pageConfigs; | ||
71 | - } | ||
72 | - | ||
73 | - void updateIgnoreElementKeys(List<Key> ignoreElementKeys) { | ||
74 | - _config.ignoreElementKeys = ignoreElementKeys; | ||
75 | - } | ||
76 | - | ||
77 | - void updateIgnoreElementStringKeys(List<String> ignoreElementStringKeys) { | ||
78 | - _config.ignoreElementStringKeys = ignoreElementStringKeys; | ||
79 | - } | ||
80 | - | ||
81 | - void enablePageView(bool enable) { | ||
82 | - _config.enablePageView = enable; | ||
83 | - } | ||
84 | - | ||
85 | - void enablePageLeave(bool enable) { | ||
86 | - _config.enablePageLeave = enable; | ||
87 | - } | ||
88 | - | ||
89 | - void enableClick(bool enable) { | ||
90 | - _config.enableClick = enable; | ||
91 | - } | ||
92 | - | ||
93 | - void enableDrag(bool enable) { | ||
94 | - _config.enableDrag = enable; | ||
95 | - } | ||
96 | - | ||
97 | void enableAutoTrack(bool enable) { | 69 | void enableAutoTrack(bool enable) { |
98 | _autoTrackEnable = enable; | 70 | _autoTrackEnable = enable; |
99 | } | 71 | } |
100 | 72 | ||
101 | - void enableUpload(bool enable) { | ||
102 | - _config.enableUpload = enable; | ||
103 | - if (enable) { | ||
104 | - AutoTrackQueue.instance.start(); | ||
105 | - } else { | ||
106 | - AutoTrackQueue.instance.stop(); | ||
107 | - } | ||
108 | - } | ||
109 | - | ||
110 | - void enableIgnoreNullKey(bool enable) { | ||
111 | - _config.enableIgnoreNullKey = enable; | ||
112 | - } | ||
113 | - | ||
114 | List<AutoTrackPageConfig> get pageConfigs => _config.pageConfigs; | 73 | List<AutoTrackPageConfig> get pageConfigs => _config.pageConfigs; |
115 | 74 | ||
116 | bool get useCustomRoute => _config.useCustomRoute; | 75 | bool get useCustomRoute => _config.useCustomRoute; |
1 | import 'dart:async'; | 1 | import 'dart:async'; |
2 | +import 'dart:convert'; | ||
3 | +import 'dart:io'; | ||
2 | import 'dart:math'; | 4 | import 'dart:math'; |
3 | 5 | ||
4 | import 'package:auto_track/auto_track/config/manager.dart'; | 6 | import 'package:auto_track/auto_track/config/manager.dart'; |
5 | import 'package:auto_track/auto_track/utils/track_model.dart'; | 7 | import 'package:auto_track/auto_track/utils/track_model.dart'; |
6 | -import 'package:dio/dio.dart'; | ||
7 | 8 | ||
8 | import '../log/logger.dart'; | 9 | import '../log/logger.dart'; |
9 | 10 | ||
10 | - | ||
11 | - | ||
12 | class AutoTrackQueue { | 11 | class AutoTrackQueue { |
13 | static final AutoTrackQueue instance = AutoTrackQueue._(); | 12 | static final AutoTrackQueue instance = AutoTrackQueue._(); |
14 | - AutoTrackQueue._(); | 13 | + AutoTrackQueue._() { |
14 | + httpClient.badCertificateCallback = | ||
15 | + (X509Certificate cert, String host, int port) => true; | ||
16 | + } | ||
15 | 17 | ||
16 | Timer? _timer; | 18 | Timer? _timer; |
17 | final List<TrackModel> _queue = []; | 19 | final List<TrackModel> _queue = []; |
18 | - final dio = Dio(); | 20 | + final httpClient = HttpClient(); |
19 | 21 | ||
20 | void appendQueue(TrackModel model) { | 22 | void appendQueue(TrackModel model) { |
21 | if (_timer == null) return; | 23 | if (_timer == null) return; |
@@ -24,7 +26,10 @@ class AutoTrackQueue { | @@ -24,7 +26,10 @@ class AutoTrackQueue { | ||
24 | 26 | ||
25 | void start() { | 27 | void start() { |
26 | if (_timer != null) return; | 28 | if (_timer != null) return; |
27 | - _timer = Timer.periodic(Duration(seconds: AutoTrackConfigManager.instance.config.uploadInterval ?? 10), (timer) { | 29 | + _timer = Timer.periodic( |
30 | + Duration( | ||
31 | + seconds: AutoTrackConfigManager.instance.config.uploadInterval ?? | ||
32 | + 10), (timer) { | ||
28 | flush(); | 33 | flush(); |
29 | }); | 34 | }); |
30 | } | 35 | } |
@@ -48,21 +53,29 @@ class AutoTrackQueue { | @@ -48,21 +53,29 @@ class AutoTrackQueue { | ||
48 | } | 53 | } |
49 | if (host != null) { | 54 | if (host != null) { |
50 | final t = DateTime.now().millisecondsSinceEpoch; | 55 | final t = DateTime.now().millisecondsSinceEpoch; |
51 | - dio.post(host, data: { | ||
52 | - 'app_key': config.appKey ?? '', | ||
53 | - 'signature': config.signature!(t), | ||
54 | - 't': t, | ||
55 | - 'user_id': config.userId ?? '', | ||
56 | - 'track_id': config.trackId ?? '', | ||
57 | - 'unique_id': config.uniqueId ?? AutoTrackConfigManager.instance.deviceId, | ||
58 | - 'device_id': AutoTrackConfigManager.instance.deviceId, | ||
59 | - 'data_list': uploadList.map((e) => e.toMap()).toList(), | ||
60 | - 'app_version': AutoTrackConfigManager.instance.appVersion, | ||
61 | - 'device_info': AutoTrackConfigManager.instance.deviceInfo | ||
62 | - }).onError((error, stackTrace) { | ||
63 | - AutoTrackLogger.getInstance().error(error!); | ||
64 | - return Future.value(Response(statusCode: 500, requestOptions: RequestOptions(path: host))); | 56 | + |
57 | + httpClient.postUrl(Uri.parse(host)).then((request) { | ||
58 | + request.headers.contentType = ContentType.json; | ||
59 | + request.write(json.encode({ | ||
60 | + 'app_key': config.appKey ?? '', | ||
61 | + 'signature': config.signature!(t), | ||
62 | + 't': t, | ||
63 | + 'user_id': config.userId ?? '', | ||
64 | + 'track_id': config.trackId ?? '', | ||
65 | + 'unique_id': | ||
66 | + config.uniqueId ?? AutoTrackConfigManager.instance.deviceId, | ||
67 | + 'device_id': AutoTrackConfigManager.instance.deviceId, | ||
68 | + 'data_list': uploadList.map((e) => e.toMap()).toList(), | ||
69 | + 'app_version': AutoTrackConfigManager.instance.appVersion, | ||
70 | + 'device_info': AutoTrackConfigManager.instance.deviceInfo | ||
71 | + })); | ||
72 | + return request.close(); | ||
73 | + }).then((response) { | ||
74 | + AutoTrackLogger.getInstance() | ||
75 | + .debug('upload status => ${response.statusCode}'); | ||
76 | + }).catchError((error) { | ||
77 | + AutoTrackLogger.getInstance().error(error); | ||
65 | }); | 78 | }); |
66 | } | 79 | } |
67 | } | 80 | } |
68 | -} | ||
81 | +} |
1 | -import 'package:auto_track/auto_track/drag/drag_pointer_event_listener.dart'; | 1 | +import 'dart:io'; |
2 | + | ||
2 | import 'package:flutter/foundation.dart'; | 3 | import 'package:flutter/foundation.dart'; |
3 | 4 | ||
4 | -import 'click/pointer_event_listener.dart'; | ||
5 | import 'config/config.dart'; | 5 | import 'config/config.dart'; |
6 | import 'config/manager.dart'; | 6 | import 'config/manager.dart'; |
7 | +import 'listener/click/pointer_event_listener.dart'; | ||
8 | +import 'listener/drag/drag_pointer_event_listener.dart'; | ||
9 | +import 'listener/request/request_listener.dart'; | ||
7 | import 'log/logger.dart'; | 10 | import 'log/logger.dart'; |
8 | 11 | ||
9 | class AutoTrack { | 12 | class AutoTrack { |
@@ -16,98 +19,132 @@ class AutoTrack { | @@ -16,98 +19,132 @@ class AutoTrack { | ||
16 | } | 19 | } |
17 | 20 | ||
18 | void updateUserId(String id) { | 21 | void updateUserId(String id) { |
19 | - AutoTrackConfigManager.instance.updateUserId(id); | 22 | + AutoTrackConfigManager.instance.updateConfig((config) { |
23 | + return config.copyWith(userId: id); | ||
24 | + }); | ||
20 | } | 25 | } |
21 | 26 | ||
22 | void updateSampleRate(double rate) { | 27 | void updateSampleRate(double rate) { |
23 | - AutoTrackConfigManager.instance.updateSampleRate(rate); | 28 | + AutoTrackConfigManager.instance.updateConfig((config) { |
29 | + return config.copyWith(samplingRate: rate); | ||
30 | + }); | ||
24 | } | 31 | } |
25 | 32 | ||
26 | AutoTrack config(AutoTrackConfig? config) { | 33 | AutoTrack config(AutoTrackConfig? config) { |
27 | if (config != null) { | 34 | if (config != null) { |
28 | - AutoTrackConfigManager.instance.updateConfig(config); | 35 | + AutoTrackConfigManager.instance.setConfig(config); |
29 | } | 36 | } |
30 | return _instance; | 37 | return _instance; |
31 | } | 38 | } |
32 | 39 | ||
33 | AutoTrack pageConfigs(List<AutoTrackPageConfig>? pageConfigs) { | 40 | AutoTrack pageConfigs(List<AutoTrackPageConfig>? pageConfigs) { |
34 | if (pageConfigs != null) { | 41 | if (pageConfigs != null) { |
35 | - AutoTrackConfigManager.instance.updatePageConfigs(pageConfigs); | 42 | + AutoTrackConfigManager.instance.updateConfig((config) { |
43 | + return config.copyWith(pageConfigs: pageConfigs); | ||
44 | + }); | ||
36 | } | 45 | } |
37 | return _instance; | 46 | return _instance; |
38 | } | 47 | } |
39 | 48 | ||
40 | AutoTrack ignoreElementKeys(List<Key>? ignoreElementKeys) { | 49 | AutoTrack ignoreElementKeys(List<Key>? ignoreElementKeys) { |
41 | if (ignoreElementKeys != null) { | 50 | if (ignoreElementKeys != null) { |
42 | - AutoTrackConfigManager.instance.updateIgnoreElementKeys(ignoreElementKeys); | 51 | + AutoTrackConfigManager.instance.updateConfig((config) { |
52 | + return config.copyWith(ignoreElementKeys: ignoreElementKeys); | ||
53 | + }); | ||
43 | } | 54 | } |
44 | return _instance; | 55 | return _instance; |
45 | } | 56 | } |
46 | 57 | ||
47 | AutoTrack ignoreElementStringKeys(List<String>? ignoreElementStringKeys) { | 58 | AutoTrack ignoreElementStringKeys(List<String>? ignoreElementStringKeys) { |
48 | if (ignoreElementStringKeys != null) { | 59 | if (ignoreElementStringKeys != null) { |
49 | - AutoTrackConfigManager.instance.updateIgnoreElementStringKeys(ignoreElementStringKeys); | 60 | + AutoTrackConfigManager.instance.updateConfig((config) { |
61 | + return config.copyWith(ignoreElementStringKeys: ignoreElementStringKeys); | ||
62 | + }); | ||
50 | } | 63 | } |
51 | return _instance; | 64 | return _instance; |
52 | } | 65 | } |
53 | 66 | ||
54 | AutoTrack enablePageView() { | 67 | AutoTrack enablePageView() { |
55 | - AutoTrackConfigManager.instance.enablePageView(true); | 68 | + AutoTrackConfigManager.instance.updateConfig((config) { |
69 | + return config.copyWith(enablePageView: true); | ||
70 | + }); | ||
56 | return _instance; | 71 | return _instance; |
57 | } | 72 | } |
58 | 73 | ||
59 | AutoTrack disablePageView() { | 74 | AutoTrack disablePageView() { |
60 | - AutoTrackConfigManager.instance.enablePageView(false); | 75 | + AutoTrackConfigManager.instance.updateConfig((config) { |
76 | + return config.copyWith(enablePageView: false); | ||
77 | + }); | ||
61 | return _instance; | 78 | return _instance; |
62 | } | 79 | } |
63 | 80 | ||
64 | AutoTrack enablePageLeave() { | 81 | AutoTrack enablePageLeave() { |
65 | - AutoTrackConfigManager.instance.enablePageLeave(true); | 82 | + AutoTrackConfigManager.instance.updateConfig((config) { |
83 | + return config.copyWith(enablePageLeave: true); | ||
84 | + }); | ||
66 | return _instance; | 85 | return _instance; |
67 | } | 86 | } |
68 | 87 | ||
69 | AutoTrack disablePageLeave() { | 88 | AutoTrack disablePageLeave() { |
70 | - AutoTrackConfigManager.instance.enablePageLeave(false); | 89 | + AutoTrackConfigManager.instance.updateConfig((config) { |
90 | + return config.copyWith(enablePageLeave: false); | ||
91 | + }); | ||
71 | return _instance; | 92 | return _instance; |
72 | } | 93 | } |
73 | 94 | ||
74 | AutoTrack enableIgnoreNullKey() { | 95 | AutoTrack enableIgnoreNullKey() { |
75 | - AutoTrackConfigManager.instance.enableIgnoreNullKey(true); | 96 | + AutoTrackConfigManager.instance.updateConfig((config) { |
97 | + return config.copyWith(enableIgnoreNullKey: true); | ||
98 | + }); | ||
76 | return _instance; | 99 | return _instance; |
77 | } | 100 | } |
78 | 101 | ||
79 | AutoTrack disableIgnoreNullKey() { | 102 | AutoTrack disableIgnoreNullKey() { |
80 | - AutoTrackConfigManager.instance.enableIgnoreNullKey(false); | 103 | + AutoTrackConfigManager.instance.updateConfig((config) { |
104 | + return config.copyWith(enableIgnoreNullKey: false); | ||
105 | + }); | ||
81 | return _instance; | 106 | return _instance; |
82 | } | 107 | } |
83 | 108 | ||
84 | AutoTrack enableUpload() { | 109 | AutoTrack enableUpload() { |
85 | - AutoTrackConfigManager.instance.enableUpload(true); | 110 | + AutoTrackConfigManager.instance.updateConfig((config) { |
111 | + return config.copyWith(enableUpload: true); | ||
112 | + }); | ||
86 | return _instance; | 113 | return _instance; |
87 | } | 114 | } |
88 | 115 | ||
89 | AutoTrack disableUpload() { | 116 | AutoTrack disableUpload() { |
90 | - AutoTrackConfigManager.instance.enableUpload(false); | 117 | + AutoTrackConfigManager.instance.updateConfig((config) { |
118 | + return config.copyWith(enableUpload: false); | ||
119 | + }); | ||
91 | return _instance; | 120 | return _instance; |
92 | } | 121 | } |
93 | 122 | ||
94 | AutoTrack enableClick() { | 123 | AutoTrack enableClick() { |
95 | - AutoTrackConfigManager.instance.enableClick(true); | 124 | + AutoTrackConfigManager.instance.updateConfig((config) { |
125 | + return config.copyWith(enableClick: true); | ||
126 | + }); | ||
96 | return _instance; | 127 | return _instance; |
97 | } | 128 | } |
98 | 129 | ||
99 | - AutoTrack enableDrag() { | ||
100 | - AutoTrackConfigManager.instance.enableDrag(true); | 130 | + AutoTrack disableClick() { |
131 | + AutoTrackConfigManager.instance.updateConfig((config) { | ||
132 | + return config.copyWith(enableClick: false); | ||
133 | + }); | ||
101 | return _instance; | 134 | return _instance; |
102 | } | 135 | } |
103 | 136 | ||
104 | - AutoTrack disableDrag() { | ||
105 | - AutoTrackConfigManager.instance.enableDrag(true); | 137 | + AutoTrack enableDrag() { |
138 | + AutoTrackConfigManager.instance.updateConfig((config) { | ||
139 | + return config.copyWith(enableDrag: true); | ||
140 | + }); | ||
106 | return _instance; | 141 | return _instance; |
107 | } | 142 | } |
108 | 143 | ||
109 | - AutoTrack disableClick() { | ||
110 | - AutoTrackConfigManager.instance.enableClick(false); | 144 | + AutoTrack disableDrag() { |
145 | + AutoTrackConfigManager.instance.updateConfig((config) { | ||
146 | + return config.copyWith(enableDrag: false); | ||
147 | + }); | ||
111 | return _instance; | 148 | return _instance; |
112 | } | 149 | } |
113 | 150 | ||
@@ -122,6 +159,7 @@ class AutoTrack { | @@ -122,6 +159,7 @@ class AutoTrack { | ||
122 | AutoTrackConfigManager.instance.enableAutoTrack(false); | 159 | AutoTrackConfigManager.instance.enableAutoTrack(false); |
123 | PointerEventListener.instance.stop(); | 160 | PointerEventListener.instance.stop(); |
124 | DragPointerEventListener.instance.stop(); | 161 | DragPointerEventListener.instance.stop(); |
162 | + disableHttpRequest(); | ||
125 | return _instance; | 163 | return _instance; |
126 | } | 164 | } |
127 | 165 | ||
@@ -136,4 +174,14 @@ class AutoTrack { | @@ -136,4 +174,14 @@ class AutoTrack { | ||
136 | } | 174 | } |
137 | return _instance; | 175 | return _instance; |
138 | } | 176 | } |
177 | + | ||
178 | + AutoTrack enableHttpRequest() { | ||
179 | + HttpOverrides.global = AutoTrackHttpOverrides(HttpOverrides.current); | ||
180 | + return _instance; | ||
181 | + } | ||
182 | + | ||
183 | + AutoTrack disableHttpRequest() { | ||
184 | + HttpOverrides.global = null; | ||
185 | + return _instance; | ||
186 | + } | ||
139 | } | 187 | } |
@@ -3,9 +3,9 @@ import 'dart:convert'; | @@ -3,9 +3,9 @@ import 'dart:convert'; | ||
3 | import 'package:crypto/crypto.dart'; | 3 | import 'package:crypto/crypto.dart'; |
4 | import 'package:flutter/widgets.dart'; | 4 | import 'package:flutter/widgets.dart'; |
5 | 5 | ||
6 | -import '../config/manager.dart'; | 6 | +import '../../config/manager.dart'; |
7 | import '../page_view/page_info.dart'; | 7 | import '../page_view/page_info.dart'; |
8 | -import '../utils/element_util.dart'; | 8 | +import '../../utils/element_util.dart'; |
9 | import 'element_key.dart'; | 9 | import 'element_key.dart'; |
10 | import 'xpath.dart'; | 10 | import 'xpath.dart'; |
11 | 11 |
@@ -5,11 +5,11 @@ import 'package:flutter/rendering.dart'; | @@ -5,11 +5,11 @@ import 'package:flutter/rendering.dart'; | ||
5 | import 'package:flutter/widgets.dart'; | 5 | import 'package:flutter/widgets.dart'; |
6 | 6 | ||
7 | 7 | ||
8 | -import '../log/logger.dart'; | 8 | +import '../../log/logger.dart'; |
9 | import '../page_view/page_info.dart'; | 9 | import '../page_view/page_info.dart'; |
10 | import '../page_view/page_stack.dart'; | 10 | import '../page_view/page_stack.dart'; |
11 | -import '../track/track.dart'; | ||
12 | -import '../utils/element_util.dart'; | 11 | +import '../../track/track.dart'; |
12 | +import '../../utils/element_util.dart'; | ||
13 | import 'click_info.dart'; | 13 | import 'click_info.dart'; |
14 | 14 | ||
15 | class PointerEventListener { | 15 | class PointerEventListener { |
1 | -import 'package:auto_track/auto_track/drag/drag_info.dart'; | ||
2 | import 'package:auto_track/auto_track/track/track.dart'; | 1 | import 'package:auto_track/auto_track/track/track.dart'; |
3 | import 'package:flutter/gestures.dart'; | 2 | import 'package:flutter/gestures.dart'; |
4 | 3 | ||
5 | import '../page_view/page_stack.dart'; | 4 | import '../page_view/page_stack.dart'; |
5 | +import 'drag_info.dart'; | ||
6 | 6 | ||
7 | class DragPointerEventListener { | 7 | class DragPointerEventListener { |
8 | static final DragPointerEventListener instance = DragPointerEventListener._(); | 8 | static final DragPointerEventListener instance = DragPointerEventListener._(); |
1 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
2 | import 'package:flutter/scheduler.dart'; | 2 | import 'package:flutter/scheduler.dart'; |
3 | 3 | ||
4 | -import '../config/config.dart'; | ||
5 | -import '../config/manager.dart'; | ||
6 | -import '../log/logger.dart'; | ||
7 | -import '../utils/element_util.dart'; | 4 | +import '../../config/config.dart'; |
5 | +import '../../config/manager.dart'; | ||
6 | +import '../../log/logger.dart'; | ||
7 | +import '../../utils/element_util.dart'; | ||
8 | import 'page_stack.dart'; | 8 | import 'page_stack.dart'; |
9 | 9 | ||
10 | class AutoTrackNavigationObserver extends NavigatorObserver { | 10 | class AutoTrackNavigationObserver extends NavigatorObserver { |
@@ -3,9 +3,9 @@ import 'dart:convert'; | @@ -3,9 +3,9 @@ import 'dart:convert'; | ||
3 | import 'package:crypto/crypto.dart'; | 3 | import 'package:crypto/crypto.dart'; |
4 | import 'package:flutter/material.dart'; | 4 | import 'package:flutter/material.dart'; |
5 | 5 | ||
6 | -import '../config/config.dart'; | ||
7 | -import '../config/manager.dart'; | ||
8 | -import '../utils/element_util.dart'; | 6 | +import '../../config/config.dart'; |
7 | +import '../../config/manager.dart'; | ||
8 | +import '../../utils/element_util.dart'; | ||
9 | 9 | ||
10 | class PageInfo { | 10 | class PageInfo { |
11 | PageInfo._(this.timer); | 11 | PageInfo._(this.timer); |
@@ -3,7 +3,7 @@ import 'dart:core'; | @@ -3,7 +3,7 @@ import 'dart:core'; | ||
3 | 3 | ||
4 | import 'package:flutter/widgets.dart'; | 4 | import 'package:flutter/widgets.dart'; |
5 | 5 | ||
6 | -import '../track/track.dart'; | 6 | +import '../../track/track.dart'; |
7 | import 'page_info.dart'; | 7 | import 'page_info.dart'; |
8 | 8 | ||
9 | class PageStack with WidgetsBindingObserver { | 9 | class PageStack with WidgetsBindingObserver { |
1 | +import 'dart:async'; | ||
2 | +import 'dart:convert'; | ||
3 | +import 'dart:io'; | ||
4 | + | ||
5 | +import 'package:auto_track/auto_track/track/track.dart'; | ||
6 | + | ||
7 | +import '../../config/manager.dart'; | ||
8 | +import '../../utils/request_model.dart'; | ||
9 | +import '../page_view/page_stack.dart'; | ||
10 | + | ||
11 | +class HttpClientRequestWithChecker implements HttpClientRequest { | ||
12 | + final HttpClientRequest _realRequest; | ||
13 | + final Stopwatch _stopwatch; | ||
14 | + final Page? pageInfoData; | ||
15 | + | ||
16 | + HttpClientRequestWithChecker( | ||
17 | + this._realRequest, this._stopwatch, this.pageInfoData); | ||
18 | + | ||
19 | + @override | ||
20 | + bool get bufferOutput => _realRequest.bufferOutput; | ||
21 | + | ||
22 | + @override | ||
23 | + int get contentLength => _realRequest.contentLength; | ||
24 | + | ||
25 | + @override | ||
26 | + Encoding get encoding => _realRequest.encoding; | ||
27 | + | ||
28 | + @override | ||
29 | + bool get followRedirects => _realRequest.followRedirects; | ||
30 | + | ||
31 | + @override | ||
32 | + int get maxRedirects => _realRequest.maxRedirects; | ||
33 | + | ||
34 | + @override | ||
35 | + bool get persistentConnection => _realRequest.persistentConnection; | ||
36 | + | ||
37 | + @override | ||
38 | + void add(List<int> data) { | ||
39 | + _realRequest.add(data); | ||
40 | + } | ||
41 | + | ||
42 | + @override | ||
43 | + void addError(Object error, [StackTrace? stackTrace]) { | ||
44 | + _realRequest.addError(error, stackTrace); | ||
45 | + } | ||
46 | + | ||
47 | + @override | ||
48 | + Future addStream(Stream<List<int>> stream) { | ||
49 | + return _realRequest.addStream(stream); | ||
50 | + } | ||
51 | + | ||
52 | + @override | ||
53 | + Future<HttpClientResponse> close() async { | ||
54 | + return _realRequest.close().then((HttpClientResponse response) { | ||
55 | + _checkResponse(_realRequest, response); | ||
56 | + return response; | ||
57 | + }).catchError((dynamic error, dynamic stackTrace) {}, test: (error) { | ||
58 | + _stopwatch.stop(); | ||
59 | + String message; | ||
60 | + if (error is HttpException) { | ||
61 | + message = error.message; | ||
62 | + } else { | ||
63 | + message = error.toString(); | ||
64 | + } | ||
65 | + Track.instance.reportHttpRequest(RequestModel( | ||
66 | + uri: _realRequest.uri, | ||
67 | + method: method, | ||
68 | + pageId: pageInfoData?.pageInfo?.pageKey ?? "", | ||
69 | + requestHeaders: AutoTrackConfigManager | ||
70 | + .instance.config.httpRequestConfig!.ignoreRequestHeader | ||
71 | + ? null | ||
72 | + : _realRequest.headers, | ||
73 | + message: message, | ||
74 | + status: -1, | ||
75 | + spent: _stopwatch.elapsedMilliseconds)); | ||
76 | + return false; | ||
77 | + }); | ||
78 | + } | ||
79 | + | ||
80 | + @override | ||
81 | + HttpConnectionInfo? get connectionInfo => _realRequest.connectionInfo; | ||
82 | + | ||
83 | + @override | ||
84 | + List<Cookie> get cookies => _realRequest.cookies; | ||
85 | + | ||
86 | + @override | ||
87 | + Future<HttpClientResponse> get done async { | ||
88 | + return close(); | ||
89 | + } | ||
90 | + | ||
91 | + @override | ||
92 | + Future flush() { | ||
93 | + return _realRequest.flush(); | ||
94 | + } | ||
95 | + | ||
96 | + @override | ||
97 | + HttpHeaders get headers => _realRequest.headers; | ||
98 | + | ||
99 | + @override | ||
100 | + String get method => _realRequest.method; | ||
101 | + | ||
102 | + @override | ||
103 | + Uri get uri => _realRequest.uri; | ||
104 | + | ||
105 | + @override | ||
106 | + void write(Object? obj) { | ||
107 | + _realRequest.write(obj); | ||
108 | + } | ||
109 | + | ||
110 | + @override | ||
111 | + void writeAll(Iterable objects, [String separator = '']) { | ||
112 | + _realRequest.writeAll(objects, separator); | ||
113 | + } | ||
114 | + | ||
115 | + @override | ||
116 | + void writeCharCode(int charCode) { | ||
117 | + _realRequest.writeCharCode(charCode); | ||
118 | + } | ||
119 | + | ||
120 | + @override | ||
121 | + void writeln([Object? obj = '']) { | ||
122 | + _realRequest.writeln(obj); | ||
123 | + } | ||
124 | + | ||
125 | + void _checkResponse(HttpClientRequest request, HttpClientResponse response) { | ||
126 | + String message = 'status ${response.statusCode}'; | ||
127 | + message = '$message: ${response.reasonPhrase}'; | ||
128 | + | ||
129 | + _stopwatch.stop(); | ||
130 | + final config = AutoTrackConfigManager.instance.config.httpRequestConfig!; | ||
131 | + Track.instance.reportHttpRequest(RequestModel( | ||
132 | + uri: _realRequest.uri, | ||
133 | + method: method, | ||
134 | + pageId: pageInfoData?.pageInfo?.pageKey ?? "", | ||
135 | + requestHeaders: config.ignoreRequestHeader ? null : request.headers, | ||
136 | + responseHeaders: config.ignoreResponseHeader ? null : response.headers, | ||
137 | + message: message, | ||
138 | + status: response.statusCode, | ||
139 | + spent: _stopwatch.elapsedMilliseconds)); | ||
140 | + } | ||
141 | + | ||
142 | + @override | ||
143 | + set bufferOutput(bool bufferOutput) { | ||
144 | + _realRequest.bufferOutput = bufferOutput; | ||
145 | + } | ||
146 | + | ||
147 | + @override | ||
148 | + set contentLength(int contentLength) { | ||
149 | + _realRequest.contentLength = contentLength; | ||
150 | + } | ||
151 | + | ||
152 | + @override | ||
153 | + set encoding(Encoding encoding) { | ||
154 | + _realRequest.encoding = encoding; | ||
155 | + } | ||
156 | + | ||
157 | + @override | ||
158 | + set followRedirects(bool followRedirects) { | ||
159 | + _realRequest.followRedirects = followRedirects; | ||
160 | + } | ||
161 | + | ||
162 | + @override | ||
163 | + set maxRedirects(int maxRedirects) { | ||
164 | + _realRequest.maxRedirects = maxRedirects; | ||
165 | + } | ||
166 | + | ||
167 | + @override | ||
168 | + set persistentConnection(bool persistentConnection) { | ||
169 | + _realRequest.persistentConnection = persistentConnection; | ||
170 | + } | ||
171 | + | ||
172 | + @override | ||
173 | + void abort([Object? exception, StackTrace? stackTrace]) { | ||
174 | + _realRequest.abort(exception, stackTrace); | ||
175 | + } | ||
176 | +} | ||
177 | + | ||
178 | +class HttpClientWithChecker implements HttpClient { | ||
179 | + final HttpClient _realClient; | ||
180 | + | ||
181 | + Uri? url; | ||
182 | + String? method; | ||
183 | + | ||
184 | + HttpClientWithChecker(this._realClient); | ||
185 | + | ||
186 | + @override | ||
187 | + set connectionFactory( | ||
188 | + Future<ConnectionTask<Socket>> Function( | ||
189 | + Uri url, String? proxyHost, int? proxyPort)? | ||
190 | + f) { | ||
191 | + // TODO: add impl here | ||
192 | + assert(false); | ||
193 | + } | ||
194 | + | ||
195 | + @override | ||
196 | + set keyLog(Function(String line)? callback) { | ||
197 | + // TODO: add impl here | ||
198 | + assert(false); | ||
199 | + } | ||
200 | + | ||
201 | + @override | ||
202 | + bool get autoUncompress => _realClient.autoUncompress; | ||
203 | + | ||
204 | + @override | ||
205 | + set autoUncompress(bool value) => _realClient.autoUncompress = value; | ||
206 | + | ||
207 | + @override | ||
208 | + Duration? get connectionTimeout => _realClient.connectionTimeout; | ||
209 | + | ||
210 | + @override | ||
211 | + set connectionTimeout(Duration? value) => | ||
212 | + _realClient.connectionTimeout = value; | ||
213 | + | ||
214 | + @override | ||
215 | + Duration get idleTimeout => _realClient.idleTimeout; | ||
216 | + | ||
217 | + @override | ||
218 | + set idleTimeout(Duration value) => _realClient.idleTimeout = value; | ||
219 | + | ||
220 | + @override | ||
221 | + int? get maxConnectionsPerHost => _realClient.maxConnectionsPerHost; | ||
222 | + | ||
223 | + @override | ||
224 | + set maxConnectionsPerHost(int? value) => | ||
225 | + _realClient.maxConnectionsPerHost = value; | ||
226 | + | ||
227 | + @override | ||
228 | + String? get userAgent => _realClient.userAgent; | ||
229 | + | ||
230 | + @override | ||
231 | + set userAgent(String? value) => _realClient.userAgent = value; | ||
232 | + | ||
233 | + @override | ||
234 | + void addCredentials( | ||
235 | + Uri url, String realm, HttpClientCredentials credentials) => | ||
236 | + _realClient.addCredentials(url, realm, credentials); | ||
237 | + | ||
238 | + @override | ||
239 | + void addProxyCredentials(String host, int port, String realm, | ||
240 | + HttpClientCredentials credentials) => | ||
241 | + _realClient.addProxyCredentials(host, port, realm, credentials); | ||
242 | + | ||
243 | + @override | ||
244 | + set authenticate( | ||
245 | + Future<bool> Function(Uri url, String scheme, String? realm)? f) => | ||
246 | + _realClient.authenticate = f; | ||
247 | + | ||
248 | + @override | ||
249 | + set authenticateProxy( | ||
250 | + Future<bool> Function( | ||
251 | + String host, int port, String scheme, String? realm)? | ||
252 | + f) => | ||
253 | + _realClient.authenticateProxy = f; | ||
254 | + | ||
255 | + @override | ||
256 | + set badCertificateCallback( | ||
257 | + bool Function(X509Certificate cert, String host, int port)? | ||
258 | + callback) => | ||
259 | + _realClient.badCertificateCallback = callback; | ||
260 | + | ||
261 | + @override | ||
262 | + void close({bool force = false}) => _realClient.close(force: force); | ||
263 | + | ||
264 | + @override | ||
265 | + Future<HttpClientRequest> delete(String host, int port, String path) => | ||
266 | + _realClient.delete(host, port, path); | ||
267 | + | ||
268 | + @override | ||
269 | + Future<HttpClientRequest> deleteUrl(Uri url) => _realClient.deleteUrl(url); | ||
270 | + | ||
271 | + @override | ||
272 | + set findProxy(String Function(Uri url)? f) => _realClient.findProxy = f; | ||
273 | + | ||
274 | + @override | ||
275 | + Future<HttpClientRequest> get(String host, int port, String path) => | ||
276 | + _realClient.get(host, port, path); | ||
277 | + | ||
278 | + @override | ||
279 | + Future<HttpClientRequest> getUrl(Uri url) => | ||
280 | + _addCheck(_realClient.getUrl(url), 'get', url); | ||
281 | + | ||
282 | + @override | ||
283 | + Future<HttpClientRequest> head(String host, int port, String path) => | ||
284 | + _realClient.head(host, port, path); | ||
285 | + | ||
286 | + @override | ||
287 | + Future<HttpClientRequest> headUrl(Uri url) => | ||
288 | + _addCheck(_realClient.headUrl(url), 'head', url); | ||
289 | + | ||
290 | + @override | ||
291 | + Future<HttpClientRequest> patch(String host, int port, String path) => | ||
292 | + _realClient.patch(host, port, path); | ||
293 | + | ||
294 | + @override | ||
295 | + Future<HttpClientRequest> patchUrl(Uri url) => | ||
296 | + _addCheck(_realClient.patchUrl(url), 'patch', url); | ||
297 | + | ||
298 | + @override | ||
299 | + Future<HttpClientRequest> post(String host, int port, String path) => | ||
300 | + _realClient.post(host, port, path); | ||
301 | + | ||
302 | + @override | ||
303 | + Future<HttpClientRequest> postUrl(Uri url) => | ||
304 | + _addCheck(_realClient.postUrl(url), 'post', url); | ||
305 | + | ||
306 | + @override | ||
307 | + Future<HttpClientRequest> put(String host, int port, String path) => | ||
308 | + _realClient.put(host, port, path); | ||
309 | + | ||
310 | + @override | ||
311 | + Future<HttpClientRequest> putUrl(Uri url) => | ||
312 | + _addCheck(_realClient.putUrl(url), 'put', url); | ||
313 | + | ||
314 | + @override | ||
315 | + Future<HttpClientRequest> open( | ||
316 | + String method, String host, int port, String path) { | ||
317 | + const int hashMark = 0x23; | ||
318 | + const int questionMark = 0x3f; | ||
319 | + int fragmentStart = path.length; | ||
320 | + int queryStart = path.length; | ||
321 | + for (int i = path.length - 1; i >= 0; i--) { | ||
322 | + final char = path.codeUnitAt(i); | ||
323 | + if (char == hashMark) { | ||
324 | + fragmentStart = i; | ||
325 | + queryStart = i; | ||
326 | + } else if (char == questionMark) { | ||
327 | + queryStart = i; | ||
328 | + } | ||
329 | + } | ||
330 | + String? query; | ||
331 | + if (queryStart < fragmentStart) { | ||
332 | + query = path.substring(queryStart + 1, fragmentStart); | ||
333 | + path = path.substring(0, queryStart); | ||
334 | + } | ||
335 | + final Uri uri = | ||
336 | + Uri(scheme: 'http', host: host, port: port, path: path, query: query); | ||
337 | + return _addCheck(_realClient.open(method, host, port, path), method, uri); | ||
338 | + } | ||
339 | + | ||
340 | + @override | ||
341 | + Future<HttpClientRequest> openUrl(String method, Uri url) => | ||
342 | + _addCheck(_realClient.openUrl(method, url), method, url); | ||
343 | + | ||
344 | + Future<HttpClientRequest> _addCheck( | ||
345 | + Future<HttpClientRequest> request, String method, Uri url) { | ||
346 | + final host = AutoTrackConfigManager.instance.config.host; | ||
347 | + if (host != null) { | ||
348 | + final uploadUrl = Uri.parse(host); | ||
349 | + if (uploadUrl.host == url.host && uploadUrl.path == url.path) { | ||
350 | + return request; | ||
351 | + } | ||
352 | + } | ||
353 | + | ||
354 | + final Stopwatch stopwatch = Stopwatch()..start(); | ||
355 | + final Page? pageInfoData = PageStack.instance.getCurrentPage(); | ||
356 | + return request | ||
357 | + .then((HttpClientRequest request) => | ||
358 | + HttpClientRequestWithChecker(request, stopwatch, pageInfoData)) | ||
359 | + .catchError((dynamic error, dynamic stackTrace) {}, test: (error) { | ||
360 | + String message = error.toString(); | ||
361 | + if (error is SocketException) { | ||
362 | + message = error.message; | ||
363 | + } | ||
364 | + Track.instance.reportHttpRequest(RequestModel( | ||
365 | + uri: url, | ||
366 | + method: method, | ||
367 | + pageId: pageInfoData?.pageInfo?.pageKey ?? "", | ||
368 | + requestHeaders: null, | ||
369 | + message: message, | ||
370 | + status: -1, | ||
371 | + spent: stopwatch.elapsedMilliseconds)); | ||
372 | + return false; | ||
373 | + }); | ||
374 | + } | ||
375 | +} | ||
376 | + | ||
377 | +class _DefaultHttpOverrides extends HttpOverrides {} | ||
378 | + | ||
379 | +class AutoTrackHttpOverrides extends HttpOverrides { | ||
380 | + HttpOverrides? _currentOverrides; | ||
381 | + | ||
382 | + AutoTrackHttpOverrides(this._currentOverrides) : super() { | ||
383 | + _currentOverrides ??= _DefaultHttpOverrides(); | ||
384 | + } | ||
385 | + | ||
386 | + @override | ||
387 | + HttpClient createHttpClient(SecurityContext? context) { | ||
388 | + return HttpClientWithChecker(_currentOverrides!.createHttpClient(context)); | ||
389 | + } | ||
390 | + | ||
391 | + @override | ||
392 | + String findProxyFromEnvironment(Uri url, Map<String, String>? environment) { | ||
393 | + return _currentOverrides!.findProxyFromEnvironment(url, environment); | ||
394 | + } | ||
395 | +} |
1 | -import 'package:dio/dio.dart'; | 1 | +import 'dart:io'; |
2 | + | ||
2 | import 'package:flutter/widgets.dart'; | 3 | import 'package:flutter/widgets.dart'; |
3 | 4 | ||
4 | typedef AutoTrackLoggerHandler = void Function(AutoTrackLoggerLevel level, String message); | 5 | typedef AutoTrackLoggerHandler = void Function(AutoTrackLoggerLevel level, String message); |
@@ -26,8 +27,8 @@ class AutoTrackLogger { | @@ -26,8 +27,8 @@ class AutoTrackLogger { | ||
26 | message = e.message; | 27 | message = e.message; |
27 | } else if (e is Error) { | 28 | } else if (e is Error) { |
28 | message = e.stackTrace.toString(); | 29 | message = e.stackTrace.toString(); |
29 | - } else if (e is DioException) { | ||
30 | - message = (e).message ?? 'dio exception with unknown message'; | 30 | + } else if (e is HttpException) { |
31 | + message = e.message; | ||
31 | } | 32 | } |
32 | _print(AutoTrackLoggerLevel.error, message); | 33 | _print(AutoTrackLoggerLevel.error, message); |
33 | } | 34 | } |
1 | import 'package:auto_track/auto_track/config/queue.dart'; | 1 | import 'package:auto_track/auto_track/config/queue.dart'; |
2 | -import 'package:auto_track/auto_track/drag/drag_info.dart'; | ||
3 | import 'package:auto_track/auto_track/utils/error_model.dart'; | 2 | import 'package:auto_track/auto_track/utils/error_model.dart'; |
3 | +import 'package:auto_track/auto_track/utils/request_model.dart'; | ||
4 | import 'package:auto_track/auto_track/utils/track_model.dart'; | 4 | import 'package:auto_track/auto_track/utils/track_model.dart'; |
5 | 5 | ||
6 | -import '../click/click_info.dart'; | ||
7 | import '../config/manager.dart'; | 6 | import '../config/manager.dart'; |
7 | +import '../listener/click/click_info.dart'; | ||
8 | +import '../listener/drag/drag_info.dart'; | ||
9 | +import '../listener/page_view/page_info.dart'; | ||
8 | import '../log/logger.dart'; | 10 | import '../log/logger.dart'; |
9 | -import '../page_view/page_info.dart'; | ||
10 | 11 | ||
11 | class Track { | 12 | class Track { |
12 | static final Track instance = Track._(); | 13 | static final Track instance = Track._(); |
@@ -104,7 +105,14 @@ class Track { | @@ -104,7 +105,14 @@ class Track { | ||
104 | } | 105 | } |
105 | 106 | ||
106 | void reportError(Object error, StackTrace stack) { | 107 | void reportError(Object error, StackTrace stack) { |
107 | - _TrackPlugin.customEvent('error', ErrorModel(error: error, stack: stack).toMap()); | 108 | + final model = ErrorModel(error: error, stack: stack); |
109 | + _TrackPlugin.customEvent('error', model.toMap()); | ||
110 | + AutoTrackLogger.getInstance().debug('track error => ${model.toMap()}'); | ||
111 | + } | ||
112 | + | ||
113 | + void reportHttpRequest(RequestModel requestModel) { | ||
114 | + _TrackPlugin.customEvent('http', requestModel.toMap(), key: requestModel.uri.path); | ||
115 | + AutoTrackLogger.getInstance().debug('track request => ${requestModel.toMap()}'); | ||
108 | } | 116 | } |
109 | } | 117 | } |
110 | 118 | ||
@@ -128,8 +136,8 @@ class _TrackPlugin { | @@ -128,8 +136,8 @@ class _TrackPlugin { | ||
128 | AutoTrackQueue.instance.appendQueue(model); | 136 | AutoTrackQueue.instance.appendQueue(model); |
129 | } | 137 | } |
130 | 138 | ||
131 | - static void customEvent(String type, Map<String, dynamic> params) { | ||
132 | - var model = TrackModel(type, DateTime.now().millisecondsSinceEpoch, params, params['key'] ?? type); | 139 | + static void customEvent(String type, Map<String, dynamic> params, { String? key }) { |
140 | + var model = TrackModel(type, DateTime.now().millisecondsSinceEpoch, params, params['key'] ?? key ?? type); | ||
133 | AutoTrackConfigManager.instance.config.eventHandler?.call(model); | 141 | AutoTrackConfigManager.instance.config.eventHandler?.call(model); |
134 | AutoTrackQueue.instance.appendQueue(model); | 142 | AutoTrackQueue.instance.appendQueue(model); |
135 | } | 143 | } |
lib/auto_track/utils/request_model.dart
0 → 100644
1 | +class RequestModel { | ||
2 | + RequestModel({ | ||
3 | + required this.uri, | ||
4 | + required this.method, | ||
5 | + required this.message, | ||
6 | + required this.status, | ||
7 | + required this.spent, | ||
8 | + required this.pageId, | ||
9 | + this.requestHeaders, | ||
10 | + this.responseHeaders, | ||
11 | + }); | ||
12 | + | ||
13 | + Uri uri; | ||
14 | + String method; | ||
15 | + String message; | ||
16 | + String pageId; | ||
17 | + int status; | ||
18 | + int spent; | ||
19 | + dynamic requestHeaders; | ||
20 | + dynamic responseHeaders; | ||
21 | + | ||
22 | + Map<String, dynamic> toMap() { | ||
23 | + return { | ||
24 | + 'uri': uri.toString(), | ||
25 | + 'method': method, | ||
26 | + 'message': message, | ||
27 | + 'pageId': pageId, | ||
28 | + 'status': status, | ||
29 | + 'spent': spent, | ||
30 | + 'requestHeaders': requestHeaders.toString(), | ||
31 | + 'responseHeaders': responseHeaders.toString(), | ||
32 | + }; | ||
33 | + } | ||
34 | +} |
1 | name: auto_track | 1 | name: auto_track |
2 | -description: "Auto Track Plugin" | ||
3 | -version: 0.0.6 | 2 | +description: "Low-intrusion global automatic embedding, automatically recording events such as page entry, exit, clicks, scrolling, and HTTP requests, and supporting custom events." |
3 | +version: 0.0.7 | ||
4 | homepage: https://github.com/epoll-j/auto_track_plugin | 4 | homepage: https://github.com/epoll-j/auto_track_plugin |
5 | 5 | ||
6 | environment: | 6 | environment: |
@@ -10,7 +10,6 @@ environment: | @@ -10,7 +10,6 @@ environment: | ||
10 | dependencies: | 10 | dependencies: |
11 | crypto: ^3.0.3 | 11 | crypto: ^3.0.3 |
12 | device_info_plus: ^9.1.2 | 12 | device_info_plus: ^9.1.2 |
13 | - dio: ^5.4.1 | ||
14 | flutter: | 13 | flutter: |
15 | sdk: flutter | 14 | sdk: flutter |
16 | package_info_plus: ^8.0.1 | 15 | package_info_plus: ^8.0.1 |
-
Please register or login to post a comment