| 
									
										
										
										
											2017-06-05 16:02:39 +03:00
										 |  |  | # Copyright (c) 2014-present PlatformIO <contact@platformio.org> | 
					
						
							| 
									
										
										
										
											2015-11-18 17:16:17 +02:00
										 |  |  | # | 
					
						
							|  |  |  | # Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  | # you may not use this file except in compliance with the License. | 
					
						
							|  |  |  | # You may obtain a copy of the License at | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #    http://www.apache.org/licenses/LICENSE-2.0 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  | # distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  | # See the License for the specific language governing permissions and | 
					
						
							|  |  |  | # limitations under the License. | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-14 00:39:33 +02:00
										 |  |  | import atexit | 
					
						
							| 
									
										
										
										
											2020-04-10 17:59:58 +03:00
										 |  |  | import hashlib | 
					
						
							| 
									
										
										
										
											2020-04-25 13:14:54 +03:00
										 |  |  | import json | 
					
						
							| 
									
										
										
										
											2019-11-28 16:15:54 +02:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2017-12-15 01:39:10 +02:00
										 |  |  | import re | 
					
						
							| 
									
										
										
										
											2018-04-27 01:41:28 +03:00
										 |  |  | import sys | 
					
						
							| 
									
										
										
										
											2014-12-14 00:39:33 +02:00
										 |  |  | import threading | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  | from collections import deque | 
					
						
							|  |  |  | from time import sleep, time | 
					
						
							| 
									
										
										
										
											2015-12-18 19:58:09 +02:00
										 |  |  | from traceback import format_exc | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | import click | 
					
						
							|  |  |  | import requests | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-06 15:02:12 +03:00
										 |  |  | from platformio import __version__, app, exception, util | 
					
						
							| 
									
										
										
										
											2019-05-09 00:51:28 +03:00
										 |  |  | from platformio.commands import PlatformioCLI | 
					
						
							| 
									
										
										
										
											2020-04-10 17:59:58 +03:00
										 |  |  | from platformio.compat import hashlib_encode_data, string_types | 
					
						
							| 
									
										
										
										
											2019-05-16 21:03:15 +03:00
										 |  |  | from platformio.proc import is_ci, is_container | 
					
						
							| 
									
										
										
										
											2020-04-10 17:59:58 +03:00
										 |  |  | from platformio.project.helpers import is_platformio_project | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-26 20:54:29 +02:00
										 |  |  | try: | 
					
						
							|  |  |  |     import queue | 
					
						
							|  |  |  | except ImportError: | 
					
						
							|  |  |  |     import Queue as queue | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | class TelemetryBase(object): | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							|  |  |  |         self._params = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __getitem__(self, name): | 
					
						
							|  |  |  |         return self._params.get(name, None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __setitem__(self, name, value): | 
					
						
							|  |  |  |         self._params[name] = value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __delitem__(self, name): | 
					
						
							|  |  |  |         if name in self._params: | 
					
						
							|  |  |  |             del self._params[name] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def send(self, hittype): | 
					
						
							|  |  |  |         raise NotImplementedError() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MeasurementProtocol(TelemetryBase): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-26 11:46:59 +03:00
										 |  |  |     TID = "UA-1768265-9" | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  |     PARAMS_MAP = { | 
					
						
							|  |  |  |         "screen_name": "cd", | 
					
						
							|  |  |  |         "event_category": "ec", | 
					
						
							|  |  |  |         "event_action": "ea", | 
					
						
							|  |  |  |         "event_label": "el", | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |         "event_value": "ev", | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							| 
									
										
										
										
											2018-10-27 15:24:10 +03:00
										 |  |  |         super(MeasurementProtocol, self).__init__() | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |         self["v"] = 1 | 
					
						
							|  |  |  |         self["tid"] = self.TID | 
					
						
							|  |  |  |         self["cid"] = app.get_cid() | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-05 19:48:04 +03:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |             self["sr"] = "%dx%d" % click.get_terminal_size() | 
					
						
							| 
									
										
										
										
											2019-04-05 19:48:04 +03:00
										 |  |  |         except ValueError: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  |         self._prefill_screen_name() | 
					
						
							|  |  |  |         self._prefill_appinfo() | 
					
						
							| 
									
										
										
										
											2020-02-12 15:14:58 +02:00
										 |  |  |         self._prefill_sysargs() | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  |         self._prefill_custom_data() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __getitem__(self, name): | 
					
						
							|  |  |  |         if name in self.PARAMS_MAP: | 
					
						
							|  |  |  |             name = self.PARAMS_MAP[name] | 
					
						
							| 
									
										
										
										
											2018-12-26 20:54:29 +02:00
										 |  |  |         return super(MeasurementProtocol, self).__getitem__(name) | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __setitem__(self, name, value): | 
					
						
							|  |  |  |         if name in self.PARAMS_MAP: | 
					
						
							|  |  |  |             name = self.PARAMS_MAP[name] | 
					
						
							| 
									
										
										
										
											2018-12-26 20:54:29 +02:00
										 |  |  |         super(MeasurementProtocol, self).__setitem__(name, value) | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _prefill_appinfo(self): | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |         self["av"] = __version__ | 
					
						
							| 
									
										
										
										
											2020-04-10 17:59:58 +03:00
										 |  |  |         self["an"] = app.get_user_agent() | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-12 15:14:58 +02:00
										 |  |  |     def _prefill_sysargs(self): | 
					
						
							|  |  |  |         args = [] | 
					
						
							|  |  |  |         for arg in sys.argv[1:]: | 
					
						
							| 
									
										
										
										
											2020-04-25 13:14:54 +03:00
										 |  |  |             arg = str(arg) | 
					
						
							|  |  |  |             if arg == "account":  # ignore account cmd which can contain username | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |             if any(("@" in arg, "/" in arg, "\\" in arg)): | 
					
						
							| 
									
										
										
										
											2020-02-12 15:14:58 +02:00
										 |  |  |                 arg = "***" | 
					
						
							| 
									
										
										
										
											2020-04-25 13:14:54 +03:00
										 |  |  |             args.append(arg.lower()) | 
					
						
							| 
									
										
										
										
											2020-02-12 15:14:58 +02:00
										 |  |  |         self["cd3"] = " ".join(args) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  |     def _prefill_custom_data(self): | 
					
						
							| 
									
										
										
										
											2017-07-03 13:35:39 +03:00
										 |  |  |         def _filter_args(items): | 
					
						
							|  |  |  |             result = [] | 
					
						
							|  |  |  |             stop = False | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 item = str(item).lower() | 
					
						
							|  |  |  |                 result.append(item) | 
					
						
							|  |  |  |                 if stop: | 
					
						
							|  |  |  |                     break | 
					
						
							|  |  |  |                 if item == "account": | 
					
						
							|  |  |  |                     stop = True | 
					
						
							|  |  |  |             return result | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 23:53:19 +03:00
										 |  |  |         caller_id = str(app.get_session_var("caller_id")) | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |         self["cd1"] = util.get_systype() | 
					
						
							|  |  |  |         self["cd4"] = ( | 
					
						
							|  |  |  |             1 if (not util.is_ci() and (caller_id or not is_container())) else 0 | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2016-09-29 23:53:19 +03:00
										 |  |  |         if caller_id: | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |             self["cd5"] = caller_id.lower() | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _prefill_screen_name(self): | 
					
						
							| 
									
										
										
										
											2016-11-03 14:03:26 +02:00
										 |  |  |         def _first_arg_from_list(args_, list_): | 
					
						
							|  |  |  |             for _arg in args_: | 
					
						
							|  |  |  |                 if _arg in list_: | 
					
						
							|  |  |  |                     return _arg | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-03 13:30:35 +03:00
										 |  |  |         args = [] | 
					
						
							|  |  |  |         for arg in PlatformioCLI.leftover_args: | 
					
						
							|  |  |  |             if not isinstance(arg, string_types): | 
					
						
							|  |  |  |                 arg = str(arg) | 
					
						
							|  |  |  |             if not arg.startswith("-"): | 
					
						
							|  |  |  |                 args.append(arg.lower()) | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  |         if not args: | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2019-06-03 13:30:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-03 17:26:24 +03:00
										 |  |  |         cmd_path = args[:1] | 
					
						
							| 
									
										
										
										
											2020-05-27 16:20:02 +03:00
										 |  |  |         if args[0] in ( | 
					
						
							|  |  |  |             "account", | 
					
						
							|  |  |  |             "device", | 
					
						
							|  |  |  |             "platform", | 
					
						
							|  |  |  |             "package", | 
					
						
							|  |  |  |             "project", | 
					
						
							|  |  |  |             "settings", | 
					
						
							|  |  |  |             "system", | 
					
						
							|  |  |  |         ): | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  |             cmd_path = args[:2] | 
					
						
							| 
									
										
										
										
											2016-11-03 14:03:26 +02:00
										 |  |  |         if args[0] == "lib" and len(args) > 1: | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |             lib_subcmds = ( | 
					
						
							|  |  |  |                 "builtin", | 
					
						
							|  |  |  |                 "install", | 
					
						
							|  |  |  |                 "list", | 
					
						
							|  |  |  |                 "register", | 
					
						
							|  |  |  |                 "search", | 
					
						
							|  |  |  |                 "show", | 
					
						
							|  |  |  |                 "stats", | 
					
						
							|  |  |  |                 "uninstall", | 
					
						
							|  |  |  |                 "update", | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2016-11-03 14:03:26 +02:00
										 |  |  |             sub_cmd = _first_arg_from_list(args[1:], lib_subcmds) | 
					
						
							|  |  |  |             if sub_cmd: | 
					
						
							|  |  |  |                 cmd_path.append(sub_cmd) | 
					
						
							|  |  |  |         elif args[0] == "remote" and len(args) > 1: | 
					
						
							|  |  |  |             remote_subcmds = ("agent", "device", "run", "test") | 
					
						
							|  |  |  |             sub_cmd = _first_arg_from_list(args[1:], remote_subcmds) | 
					
						
							|  |  |  |             if sub_cmd: | 
					
						
							|  |  |  |                 cmd_path.append(sub_cmd) | 
					
						
							|  |  |  |                 if len(args) > 2 and sub_cmd in ("agent", "device"): | 
					
						
							|  |  |  |                     remote2_subcmds = ("list", "start", "monitor") | 
					
						
							|  |  |  |                     sub_cmd = _first_arg_from_list(args[2:], remote2_subcmds) | 
					
						
							|  |  |  |                     if sub_cmd: | 
					
						
							|  |  |  |                         cmd_path.append(sub_cmd) | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |         self["screen_name"] = " ".join([p.title() for p in cmd_path]) | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-28 16:15:54 +02:00
										 |  |  |     def _ignore_hit(self): | 
					
						
							| 
									
										
										
										
											2014-12-06 19:00:36 +02:00
										 |  |  |         if not app.get_setting("enable_telemetry"): | 
					
						
							| 
									
										
										
										
											2018-04-27 01:41:28 +03:00
										 |  |  |             return True | 
					
						
							| 
									
										
										
										
											2019-11-28 16:15:54 +02:00
										 |  |  |         if all(c in sys.argv for c in ("run", "idedata")) or self["ea"] == "Idedata": | 
					
						
							| 
									
										
										
										
											2018-04-27 01:41:28 +03:00
										 |  |  |             return True | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2014-12-06 19:00:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-27 01:41:28 +03:00
										 |  |  |     def send(self, hittype): | 
					
						
							|  |  |  |         if self._ignore_hit(): | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |         self["t"] = hittype | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  |         # correct queue time | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |         if "qt" in self._params and isinstance(self["qt"], float): | 
					
						
							|  |  |  |             self["qt"] = int((time() - self["qt"]) * 1000) | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  |         MPDataPusher().push(self._params) | 
					
						
							| 
									
										
										
										
											2014-12-14 00:39:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  | @util.singleton | 
					
						
							|  |  |  | class MPDataPusher(object): | 
					
						
							| 
									
										
										
										
											2014-12-14 00:39:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  |     MAX_WORKERS = 5 | 
					
						
							| 
									
										
										
										
											2014-12-14 00:39:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							| 
									
										
										
										
											2018-12-26 20:54:29 +02:00
										 |  |  |         self._queue = queue.LifoQueue() | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  |         self._failedque = deque() | 
					
						
							|  |  |  |         self._http_session = requests.Session() | 
					
						
							|  |  |  |         self._http_offline = False | 
					
						
							|  |  |  |         self._workers = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def push(self, item): | 
					
						
							|  |  |  |         # if network is off-line | 
					
						
							|  |  |  |         if self._http_offline: | 
					
						
							|  |  |  |             if "qt" not in item: | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |                 item["qt"] = time() | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  |             self._failedque.append(item) | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2014-12-14 00:39:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  |         self._queue.put(item) | 
					
						
							|  |  |  |         self._tune_workers() | 
					
						
							| 
									
										
										
										
											2014-12-14 00:39:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  |     def in_wait(self): | 
					
						
							|  |  |  |         return self._queue.unfinished_tasks | 
					
						
							| 
									
										
										
										
											2014-12-14 00:39:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  |     def get_items(self): | 
					
						
							|  |  |  |         items = list(self._failedque) | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             while True: | 
					
						
							|  |  |  |                 items.append(self._queue.get_nowait()) | 
					
						
							| 
									
										
										
										
											2018-12-26 20:54:29 +02:00
										 |  |  |         except queue.Empty: | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  |             pass | 
					
						
							|  |  |  |         return items | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  |     def _tune_workers(self): | 
					
						
							|  |  |  |         for i, w in enumerate(self._workers): | 
					
						
							|  |  |  |             if not w.is_alive(): | 
					
						
							|  |  |  |                 del self._workers[i] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         need_nums = min(self._queue.qsize(), self.MAX_WORKERS) | 
					
						
							|  |  |  |         active_nums = len(self._workers) | 
					
						
							|  |  |  |         if need_nums <= active_nums: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for i in range(need_nums - active_nums): | 
					
						
							|  |  |  |             t = threading.Thread(target=self._worker) | 
					
						
							|  |  |  |             t.daemon = True | 
					
						
							|  |  |  |             t.start() | 
					
						
							|  |  |  |             self._workers.append(t) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _worker(self): | 
					
						
							|  |  |  |         while True: | 
					
						
							| 
									
										
										
										
											2015-11-17 23:04:49 +02:00
										 |  |  |             try: | 
					
						
							|  |  |  |                 item = self._queue.get() | 
					
						
							|  |  |  |                 _item = item.copy() | 
					
						
							|  |  |  |                 if "qt" not in _item: | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |                     _item["qt"] = time() | 
					
						
							| 
									
										
										
										
											2015-11-17 23:04:49 +02:00
										 |  |  |                 self._failedque.append(_item) | 
					
						
							|  |  |  |                 if self._send_data(item): | 
					
						
							|  |  |  |                     self._failedque.remove(_item) | 
					
						
							|  |  |  |                 self._queue.task_done() | 
					
						
							|  |  |  |             except:  # pylint: disable=W0702 | 
					
						
							|  |  |  |                 pass | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _send_data(self, data): | 
					
						
							| 
									
										
										
										
											2015-12-29 21:03:51 +02:00
										 |  |  |         if self._http_offline: | 
					
						
							|  |  |  |             return False | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  |         try: | 
					
						
							|  |  |  |             r = self._http_session.post( | 
					
						
							|  |  |  |                 "https://ssl.google-analytics.com/collect", | 
					
						
							|  |  |  |                 data=data, | 
					
						
							| 
									
										
										
										
											2020-04-10 17:59:58 +03:00
										 |  |  |                 headers={"User-Agent": app.get_user_agent()}, | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |                 timeout=1, | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  |             r.raise_for_status() | 
					
						
							| 
									
										
										
										
											2015-12-29 21:03:51 +02:00
										 |  |  |             return True | 
					
						
							| 
									
										
										
										
											2017-02-01 00:58:12 +02:00
										 |  |  |         except requests.exceptions.HTTPError as e: | 
					
						
							|  |  |  |             # skip Bad Request | 
					
						
							|  |  |  |             if 400 >= e.response.status_code < 500: | 
					
						
							|  |  |  |                 return True | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  |         except:  # pylint: disable=W0702 | 
					
						
							| 
									
										
										
										
											2017-02-01 00:58:12 +02:00
										 |  |  |             pass | 
					
						
							|  |  |  |         self._http_offline = True | 
					
						
							| 
									
										
										
										
											2015-12-29 21:03:51 +02:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def on_command(): | 
					
						
							|  |  |  |     resend_backuped_reports() | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     mp = MeasurementProtocol() | 
					
						
							| 
									
										
										
										
											2014-12-14 00:39:33 +02:00
										 |  |  |     mp.send("screenview") | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-16 21:03:15 +03:00
										 |  |  |     if is_ci(): | 
					
						
							| 
									
										
										
										
											2015-07-30 17:33:45 +03:00
										 |  |  |         measure_ci() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-28 16:15:54 +02:00
										 |  |  | def on_exception(e): | 
					
						
							|  |  |  |     skip_conditions = [ | 
					
						
							|  |  |  |         isinstance(e, cls) | 
					
						
							|  |  |  |         for cls in (IOError, exception.ReturnErrorCode, exception.UserSideException,) | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  |     if any(skip_conditions): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     is_fatal = any( | 
					
						
							|  |  |  |         [ | 
					
						
							|  |  |  |             not isinstance(e, exception.PlatformioException), | 
					
						
							|  |  |  |             "Error" in e.__class__.__name__, | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     description = "%s: %s" % ( | 
					
						
							|  |  |  |         type(e).__name__, | 
					
						
							|  |  |  |         " ".join(reversed(format_exc().split("\n"))) if is_fatal else str(e), | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     send_exception(description, is_fatal) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-30 17:33:45 +03:00
										 |  |  | def measure_ci(): | 
					
						
							| 
									
										
										
										
											2016-08-03 23:38:20 +03:00
										 |  |  |     event = {"category": "CI", "action": "NoName", "label": None} | 
					
						
							| 
									
										
										
										
											2020-04-26 12:58:32 +03:00
										 |  |  |     known_cis = ( | 
					
						
							|  |  |  |         "GITHUB_ACTIONS", | 
					
						
							|  |  |  |         "TRAVIS", | 
					
						
							|  |  |  |         "APPVEYOR", | 
					
						
							|  |  |  |         "GITLAB_CI", | 
					
						
							|  |  |  |         "CIRCLECI", | 
					
						
							|  |  |  |         "SHIPPABLE", | 
					
						
							|  |  |  |         "DRONE", | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2019-07-17 14:03:48 +03:00
										 |  |  |     for name in known_cis: | 
					
						
							| 
									
										
										
										
											2019-11-28 16:15:54 +02:00
										 |  |  |         if os.getenv(name, "false").lower() == "true": | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |             event["action"] = name | 
					
						
							| 
									
										
										
										
											2019-07-17 14:03:48 +03:00
										 |  |  |             break | 
					
						
							| 
									
										
										
										
											2019-11-28 16:15:54 +02:00
										 |  |  |     send_event(**event) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-25 13:14:54 +03:00
										 |  |  | def dump_run_environment(options): | 
					
						
							|  |  |  |     non_sensitive_data = [ | 
					
						
							| 
									
										
										
										
											2019-11-28 16:15:54 +02:00
										 |  |  |         "platform", | 
					
						
							| 
									
										
										
										
											2020-04-10 17:59:58 +03:00
										 |  |  |         "platform_packages", | 
					
						
							| 
									
										
										
										
											2019-11-28 16:15:54 +02:00
										 |  |  |         "framework", | 
					
						
							|  |  |  |         "board", | 
					
						
							|  |  |  |         "upload_protocol", | 
					
						
							|  |  |  |         "check_tool", | 
					
						
							|  |  |  |         "debug_tool", | 
					
						
							| 
									
										
										
										
											2020-04-10 17:59:58 +03:00
										 |  |  |         "monitor_filters", | 
					
						
							| 
									
										
										
										
											2019-11-28 16:15:54 +02:00
										 |  |  |     ] | 
					
						
							| 
									
										
										
										
											2020-04-25 13:14:54 +03:00
										 |  |  |     safe_options = {k: v for k, v in options.items() if k in non_sensitive_data} | 
					
						
							| 
									
										
										
										
											2020-04-10 17:59:58 +03:00
										 |  |  |     if is_platformio_project(os.getcwd()): | 
					
						
							|  |  |  |         phash = hashlib.sha1(hashlib_encode_data(app.get_cid())) | 
					
						
							| 
									
										
										
										
											2020-04-25 13:14:54 +03:00
										 |  |  |         safe_options["pid"] = phash.hexdigest() | 
					
						
							|  |  |  |     return json.dumps(safe_options, sort_keys=True, ensure_ascii=False) | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-28 16:15:54 +02:00
										 |  |  | def send_run_environment(options, targets): | 
					
						
							|  |  |  |     send_event( | 
					
						
							|  |  |  |         "Env", | 
					
						
							|  |  |  |         " ".join([t.title() for t in targets or ["run"]]), | 
					
						
							| 
									
										
										
										
											2020-04-25 13:14:54 +03:00
										 |  |  |         dump_run_environment(options), | 
					
						
							| 
									
										
										
										
											2019-11-28 16:15:54 +02:00
										 |  |  |     ) | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-28 16:15:54 +02:00
										 |  |  | def send_event(category, action, label=None, value=None, screen_name=None): | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  |     mp = MeasurementProtocol() | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |     mp["event_category"] = category[:150] | 
					
						
							|  |  |  |     mp["event_action"] = action[:500] | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  |     if label: | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |         mp["event_label"] = label[:500] | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  |     if value: | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |         mp["event_value"] = int(value) | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  |     if screen_name: | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |         mp["screen_name"] = screen_name[:2048] | 
					
						
							| 
									
										
										
										
											2014-12-14 00:39:33 +02:00
										 |  |  |     mp.send("event") | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-28 16:15:54 +02:00
										 |  |  | def send_exception(description, is_fatal=False): | 
					
						
							|  |  |  |     # cleanup sensitive information, such as paths | 
					
						
							|  |  |  |     description = description.replace("Traceback (most recent call last):", "") | 
					
						
							|  |  |  |     description = description.replace("\\", "/") | 
					
						
							|  |  |  |     description = re.sub( | 
					
						
							|  |  |  |         r'(^|\s+|")(?:[a-z]\:)?((/[^"/]+)+)(\s+|"|$)', | 
					
						
							|  |  |  |         lambda m: " %s " % os.path.join(*m.group(2).split("/")[-2:]), | 
					
						
							|  |  |  |         description, | 
					
						
							|  |  |  |         re.I | re.M, | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |     ) | 
					
						
							| 
									
										
										
										
											2019-11-28 16:15:54 +02:00
										 |  |  |     description = re.sub(r"\s+", " ", description, flags=re.M) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-18 19:58:09 +02:00
										 |  |  |     mp = MeasurementProtocol() | 
					
						
							| 
									
										
										
										
											2019-11-28 16:15:54 +02:00
										 |  |  |     mp["exd"] = description[:8192].strip() | 
					
						
							|  |  |  |     mp["exf"] = 1 if is_fatal else 0 | 
					
						
							| 
									
										
										
										
											2014-12-14 00:39:33 +02:00
										 |  |  |     mp.send("exception") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  | @atexit.register | 
					
						
							|  |  |  | def _finalize(): | 
					
						
							|  |  |  |     timeout = 1000  # msec | 
					
						
							|  |  |  |     elapsed = 0 | 
					
						
							| 
									
										
										
										
											2016-01-14 01:07:57 +02:00
										 |  |  |     try: | 
					
						
							|  |  |  |         while elapsed < timeout: | 
					
						
							|  |  |  |             if not MPDataPusher().in_wait(): | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |             sleep(0.2) | 
					
						
							|  |  |  |             elapsed += 200 | 
					
						
							|  |  |  |         backup_reports(MPDataPusher().get_items()) | 
					
						
							|  |  |  |     except KeyboardInterrupt: | 
					
						
							|  |  |  |         pass | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def backup_reports(items): | 
					
						
							|  |  |  |     if not items: | 
					
						
							| 
									
										
										
										
											2014-12-14 00:39:33 +02:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  |     KEEP_MAX_REPORTS = 100 | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  |     tm = app.get_state_item("telemetry", {}) | 
					
						
							|  |  |  |     if "backup" not in tm: | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |         tm["backup"] = [] | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  |     for params in items: | 
					
						
							| 
									
										
										
										
											2014-12-14 00:39:33 +02:00
										 |  |  |         # skip static options | 
					
						
							| 
									
										
										
										
											2019-05-23 19:39:04 +03:00
										 |  |  |         for key in list(params.keys()): | 
					
						
							| 
									
										
										
										
											2014-12-14 00:39:33 +02:00
										 |  |  |             if key in ("v", "tid", "cid", "cd1", "cd2", "sr", "an"): | 
					
						
							|  |  |  |                 del params[key] | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-14 00:39:33 +02:00
										 |  |  |         # store time in UNIX format | 
					
						
							|  |  |  |         if "qt" not in params: | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |             params["qt"] = time() | 
					
						
							|  |  |  |         elif not isinstance(params["qt"], float): | 
					
						
							|  |  |  |             params["qt"] = time() - (params["qt"] / 1000) | 
					
						
							| 
									
										
										
										
											2014-12-14 00:39:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |         tm["backup"].append(params) | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |     tm["backup"] = tm["backup"][KEEP_MAX_REPORTS * -1 :] | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  |     app.set_state_item("telemetry", tm) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  | def resend_backuped_reports(): | 
					
						
							| 
									
										
										
										
											2014-12-14 00:39:33 +02:00
										 |  |  |     tm = app.get_state_item("telemetry", {}) | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |     if "backup" not in tm or not tm["backup"]: | 
					
						
							| 
									
										
										
										
											2014-12-14 00:39:33 +02:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |     for report in tm["backup"]: | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  |         mp = MeasurementProtocol() | 
					
						
							|  |  |  |         for key, value in report.items(): | 
					
						
							|  |  |  |             mp[key] = value | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |         mp.send(report["t"]) | 
					
						
							| 
									
										
										
										
											2014-11-29 22:48:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  |     # clean | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |     tm["backup"] = [] | 
					
						
							| 
									
										
										
										
											2015-09-03 19:04:09 +03:00
										 |  |  |     app.set_state_item("telemetry", tm) | 
					
						
							| 
									
										
										
										
											2017-12-15 22:16:37 +02:00
										 |  |  |     return True |