| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library usage_impl_io; |
| 6 |
| 5 import 'dart:async'; | 7 import 'dart:async'; |
| 6 import 'dart:convert' show JSON, JsonEncoder; | 8 import 'dart:convert' show JSON; |
| 7 import 'dart:io'; | 9 import 'dart:io'; |
| 8 | 10 |
| 9 import 'package:path/path.dart' as path; | 11 import 'package:path/path.dart' as path; |
| 10 | 12 |
| 11 import 'usage_impl.dart'; | 13 import 'usage_impl.dart'; |
| 12 | 14 |
| 13 /// An interface to a Google Analytics session, suitable for use in command-line | 15 String _createUserAgent() { |
| 14 /// applications. | 16 // Mozilla/5.0 (iPhone; U; CPU iPhone OS 5_1_1 like Mac OS X; en) |
| 15 /// | 17 // Dart/1.8.0-edge.41170 (macos; macos; macos; null) |
| 16 /// `trackingId`, `applicationName`, and `applicationVersion` values should be s
upplied. | 18 String os = Platform.operatingSystem; |
| 17 /// `analyticsUrl` is optional, and lets user's substitute their own analytics U
RL for | 19 String locale = Platform.environment['LANG']; |
| 18 /// the default. | 20 return "Dart/${_dartVersion()} (${os}; ${os}; ${os}; ${locale})"; |
| 19 /// | |
| 20 /// `documentDirectory` is where the analytics settings are stored. It | |
| 21 /// defaults to the user home directory. For regular `dart:io` apps this doesn't
need to | |
| 22 /// be supplied. For Flutter applications, you should pass in a value like | |
| 23 /// `PathProvider.getApplicationDocumentsDirectory()`. | |
| 24 class AnalyticsIO extends AnalyticsImpl { | |
| 25 AnalyticsIO( | |
| 26 String trackingId, String applicationName, String applicationVersion, | |
| 27 {String analyticsUrl, Directory documentDirectory}) | |
| 28 : super( | |
| 29 trackingId, | |
| 30 new IOPersistentProperties(applicationName, | |
| 31 documentDirPath: documentDirectory?.path), | |
| 32 new IOPostHandler(), | |
| 33 applicationName: applicationName, | |
| 34 applicationVersion: applicationVersion, | |
| 35 analyticsUrl: analyticsUrl) { | |
| 36 final String locale = getPlatformLocale(); | |
| 37 if (locale != null) { | |
| 38 setSessionValue('ul', locale); | |
| 39 } | |
| 40 } | |
| 41 } | 21 } |
| 42 | 22 |
| 43 String _createUserAgent() { | 23 String _userHomeDir() { |
| 44 final String locale = getPlatformLocale() ?? ''; | |
| 45 | |
| 46 if (Platform.isAndroid) { | |
| 47 return 'Mozilla/5.0 (Android; Mobile; ${locale})'; | |
| 48 } else if (Platform.isIOS) { | |
| 49 return 'Mozilla/5.0 (iPhone; U; CPU iPhone OS like Mac OS X; ${locale})'; | |
| 50 } else if (Platform.isMacOS) { | |
| 51 return 'Mozilla/5.0 (Macintosh; Intel Mac OS X; Macintosh; ${locale})'; | |
| 52 } else if (Platform.isWindows) { | |
| 53 return 'Mozilla/5.0 (Windows; Windows; Windows; ${locale})'; | |
| 54 } else if (Platform.isLinux) { | |
| 55 return 'Mozilla/5.0 (Linux; Linux; Linux; ${locale})'; | |
| 56 } else { | |
| 57 // Dart/1.8.0 (macos; macos; macos; en_US) | |
| 58 String os = Platform.operatingSystem; | |
| 59 return "Dart/${getDartVersion()} (${os}; ${os}; ${os}; ${locale})"; | |
| 60 } | |
| 61 } | |
| 62 | |
| 63 String userHomeDir() { | |
| 64 String envKey = Platform.operatingSystem == 'windows' ? 'APPDATA' : 'HOME'; | 24 String envKey = Platform.operatingSystem == 'windows' ? 'APPDATA' : 'HOME'; |
| 65 String value = Platform.environment[envKey]; | 25 String value = Platform.environment[envKey]; |
| 66 return value == null ? '.' : value; | 26 return value == null ? '.' : value; |
| 67 } | 27 } |
| 68 | 28 |
| 69 String getDartVersion() { | 29 String _dartVersion() { |
| 70 String ver = Platform.version; | 30 String ver = Platform.version; |
| 71 int index = ver.indexOf(' '); | 31 int index = ver.indexOf(' '); |
| 72 if (index != -1) ver = ver.substring(0, index); | 32 if (index != -1) ver = ver.substring(0, index); |
| 73 return ver; | 33 return ver; |
| 74 } | 34 } |
| 75 | 35 |
| 76 class IOPostHandler extends PostHandler { | 36 class IOPostHandler extends PostHandler { |
| 77 final String _userAgent; | 37 final String _userAgent; |
| 78 final HttpClient mockClient; | 38 final HttpClient mockClient; |
| 79 | 39 |
| 80 HttpClient _client; | 40 IOPostHandler({HttpClient this.mockClient}) : _userAgent = _createUserAgent(); |
| 81 | 41 |
| 82 IOPostHandler({this.mockClient}) : _userAgent = _createUserAgent(); | 42 Future sendPost(String url, Map<String, dynamic> parameters) { |
| 43 // Add custom parameters for OS and the Dart version. |
| 44 parameters['cd1'] = Platform.operatingSystem; |
| 45 parameters['cd2'] = 'dart ${_dartVersion()}'; |
| 83 | 46 |
| 84 @override | |
| 85 Future sendPost(String url, Map<String, dynamic> parameters) async { | |
| 86 String data = postEncode(parameters); | 47 String data = postEncode(parameters); |
| 87 | 48 |
| 88 if (_client == null) { | 49 HttpClient client = mockClient != null ? mockClient : new HttpClient(); |
| 89 _client = mockClient != null ? mockClient : new HttpClient(); | 50 client.userAgent = _userAgent; |
| 90 _client.userAgent = _userAgent; | 51 return client.postUrl(Uri.parse(url)).then((HttpClientRequest req) { |
| 91 } | |
| 92 | |
| 93 try { | |
| 94 HttpClientRequest req = await _client.postUrl(Uri.parse(url)); | |
| 95 req.write(data); | 52 req.write(data); |
| 96 HttpClientResponse response = await req.close(); | 53 return req.close(); |
| 54 }).then((HttpClientResponse response) { |
| 97 response.drain(); | 55 response.drain(); |
| 98 } catch (exception) { | 56 }).catchError((e) { |
| 99 // Catch errors that can happen during a request, but that we can't do | 57 // Catch errors that can happen during a request, but that we can't do |
| 100 // anything about, e.g. a missing internet connection. | 58 // anything about, e.g. a missing internet conenction. |
| 101 } | 59 }); |
| 102 } | 60 } |
| 103 | |
| 104 @override | |
| 105 void close() => _client?.close(); | |
| 106 } | 61 } |
| 107 | 62 |
| 108 JsonEncoder _jsonEncoder = new JsonEncoder.withIndent(' '); | |
| 109 | |
| 110 class IOPersistentProperties extends PersistentProperties { | 63 class IOPersistentProperties extends PersistentProperties { |
| 111 File _file; | 64 File _file; |
| 112 Map _map; | 65 Map _map; |
| 113 | 66 |
| 114 IOPersistentProperties(String name, {String documentDirPath}) : super(name) { | 67 IOPersistentProperties(String name) : super(name) { |
| 115 String fileName = '.${name.replaceAll(' ', '_')}'; | 68 String fileName = '.${name.replaceAll(' ', '_')}'; |
| 116 documentDirPath ??= userHomeDir(); | 69 _file = new File(path.join(_userHomeDir(), fileName)); |
| 117 _file = new File(path.join(documentDirPath, fileName)); | 70 _file.createSync(); |
| 118 if (!_file.existsSync()) { | 71 String contents = _file.readAsStringSync(); |
| 119 _file.createSync(); | 72 if (contents.isEmpty) contents = '{}'; |
| 120 } | 73 _map = JSON.decode(contents); |
| 121 syncSettings(); | |
| 122 } | 74 } |
| 123 | 75 |
| 124 IOPersistentProperties.fromFile(File file) : super(path.basename(file.path)) { | 76 dynamic operator[](String key) => _map[key]; |
| 125 _file = file; | |
| 126 if (!_file.existsSync()) { | |
| 127 _file.createSync(); | |
| 128 } | |
| 129 syncSettings(); | |
| 130 } | |
| 131 | 77 |
| 132 @override | 78 void operator[]=(String key, dynamic value) { |
| 133 dynamic operator [](String key) => _map[key]; | |
| 134 | |
| 135 @override | |
| 136 void operator []=(String key, dynamic value) { | |
| 137 if (value == null && !_map.containsKey(key)) return; | |
| 138 if (_map[key] == value) return; | |
| 139 | |
| 140 if (value == null) { | 79 if (value == null) { |
| 141 _map.remove(key); | 80 _map.remove(key); |
| 142 } else { | 81 } else { |
| 143 _map[key] = value; | 82 _map[key] = value; |
| 144 } | 83 } |
| 145 | 84 |
| 146 try { | 85 _file.writeAsStringSync(JSON.encode(_map) + '\n'); |
| 147 _file.writeAsStringSync(_jsonEncoder.convert(_map) + '\n'); | |
| 148 } catch (_) {} | |
| 149 } | |
| 150 | |
| 151 @override | |
| 152 void syncSettings() { | |
| 153 try { | |
| 154 String contents = _file.readAsStringSync(); | |
| 155 if (contents.isEmpty) contents = '{}'; | |
| 156 _map = JSON.decode(contents); | |
| 157 } catch (_) { | |
| 158 _map = {}; | |
| 159 } | |
| 160 } | 86 } |
| 161 } | 87 } |
| 162 | |
| 163 /// Return the string for the platform's locale; return's `null` if the locale | |
| 164 /// can't be determined. | |
| 165 String getPlatformLocale() { | |
| 166 String locale = Platform.localeName; | |
| 167 if (locale == null) return null; | |
| 168 | |
| 169 if (locale != null) { | |
| 170 // Convert `en_US.UTF-8` to `en_US`. | |
| 171 int index = locale.indexOf('.'); | |
| 172 if (index != -1) locale = locale.substring(0, index); | |
| 173 | |
| 174 // Convert `en_US` to `en-us`. | |
| 175 locale = locale.replaceAll('_', '-').toLowerCase(); | |
| 176 } | |
| 177 | |
| 178 return locale; | |
| 179 } | |
| OLD | NEW |