<s> import atexit <EOL> import platform <EOL> import Queue <EOL> import sys <EOL> import threading <EOL> import uuid <EOL> from collections import deque <EOL> from os import getenv <EOL> from time import sleep , time <EOL> from traceback import format_exc <EOL> import click <EOL> import requests <EOL> from platformio import __version__ , app , exception , util <EOL> from platformio . ide . projectgenerator import ProjectGenerator <EOL> class TelemetryBase ( object ) : <EOL> MACHINE_ID = str ( uuid . uuid5 ( uuid . NAMESPACE_OID , str ( uuid . getnode ( ) ) ) ) <EOL> def __init__ ( self ) : <EOL> self . _params = { } <EOL> def __getitem__ ( self , name ) : <EOL> return self . _params . get ( name , None ) <EOL> def __setitem__ ( self , name , value ) : <EOL> self . _params [ name ] = value <EOL> def __delitem__ ( self , name ) : <EOL> if name in self . _params : <EOL> del self . _params [ name ] <EOL> def get_cid ( self ) : <EOL> cid = app . get_state_item ( "<STR_LIT>" ) <EOL> if not cid : <EOL> cid = self . MACHINE_ID <EOL> app . set_state_item ( "<STR_LIT>" , cid ) <EOL> return cid <EOL> def send ( self , hittype ) : <EOL> raise NotImplementedError ( ) <EOL> class MeasurementProtocol ( TelemetryBase ) : <EOL> TRACKING_ID = "<STR_LIT>" <EOL> PARAMS_MAP = { <EOL> "<STR_LIT>" : "<STR_LIT>" , <EOL> "<STR_LIT>" : "<STR_LIT>" , <EOL> "<STR_LIT>" : "<STR_LIT>" , <EOL> "<STR_LIT>" : "<STR_LIT>" , <EOL> "<STR_LIT>" : "<STR_LIT>" <EOL> } <EOL> def __init__ ( self ) : <EOL> TelemetryBase . __init__ ( self ) <EOL> self [ '<STR_LIT:v>' ] = <NUM_LIT:1> <EOL> self [ '<STR_LIT>' ] = self . TRACKING_ID <EOL> self [ '<STR_LIT>' ] = self . get_cid ( ) <EOL> self [ '<STR_LIT>' ] = "<STR_LIT>" % click . get_terminal_size ( ) <EOL> self . _prefill_screen_name ( ) <EOL> self . _prefill_appinfo ( ) <EOL> self . _prefill_custom_data ( ) <EOL> def __getitem__ ( self , name ) : <EOL> if name in self . PARAMS_MAP : <EOL> name = self . PARAMS_MAP [ name ] <EOL> return TelemetryBase . __getitem__ ( self , name ) <EOL> def __setitem__ ( self , name , value ) : <EOL> if name in self . PARAMS_MAP : <EOL> name = self . PARAMS_MAP [ name ] <EOL> TelemetryBase . __setitem__ ( self , name , value ) <EOL> def _prefill_appinfo ( self ) : <EOL> self [ '<STR_LIT>' ] = __version__ <EOL> dpdata = [ ] <EOL> dpdata . append ( "<STR_LIT>" % __version__ ) <EOL> if app . get_session_var ( "<STR_LIT>" ) : <EOL> dpdata . append ( "<STR_LIT>" % app . get_session_var ( "<STR_LIT>" ) ) <EOL> if getenv ( "<STR_LIT>" ) : <EOL> dpdata . append ( "<STR_LIT>" % getenv ( "<STR_LIT>" ) ) <EOL> self [ '<STR_LIT>' ] = "<STR_LIT:U+0020>" . join ( dpdata ) <EOL> def _prefill_custom_data ( self ) : <EOL> self [ '<STR_LIT>' ] = util . get_systype ( ) <EOL> self [ '<STR_LIT>' ] = "<STR_LIT>" % ( platform . python_version ( ) , <EOL> platform . platform ( ) ) <EOL> self [ '<STR_LIT>' ] = ( <NUM_LIT:1> if app . get_setting ( "<STR_LIT>" ) or <EOL> app . get_session_var ( "<STR_LIT>" ) else <NUM_LIT:0> ) <EOL> def _prefill_screen_name ( self ) : <EOL> self [ '<STR_LIT>' ] = "<STR_LIT:U+0020>" . join ( [ str ( s ) . lower ( ) for s in sys . argv [ <NUM_LIT:1> : ] ] ) <EOL> if not app . get_session_var ( "<STR_LIT>" ) : <EOL> return <EOL> ctx_args = app . get_session_var ( "<STR_LIT>" ) . args <EOL> args = [ str ( s ) . lower ( ) for s in ctx_args if not str ( s ) . startswith ( "<STR_LIT:->" ) ] <EOL> if not args : <EOL> return <EOL> if args [ <NUM_LIT:0> ] in ( "<STR_LIT>" , "<STR_LIT>" , "<STR_LIT>" , "<STR_LIT>" ) : <EOL> cmd_path = args [ : <NUM_LIT:2> ] <EOL> else : <EOL> cmd_path = args [ : <NUM_LIT:1> ] <EOL> self [ '<STR_LIT>' ] = "<STR_LIT:U+0020>" . join ( [ p . title ( ) for p in cmd_path ] ) <EOL> def send ( self , hittype ) : <EOL> if not app . get_setting ( "<STR_LIT>" ) : <EOL> return <EOL> self [ '<STR_LIT:t>' ] = hittype <EOL> if "<STR_LIT>" in self . _params and isinstance ( self [ '<STR_LIT>' ] , float ) : <EOL> self [ '<STR_LIT>' ] = int ( ( time ( ) - self [ '<STR_LIT>' ] ) * <NUM_LIT:1000> ) <EOL> MPDataPusher ( ) . push ( self . _params ) <EOL> @ util . singleton <EOL> class MPDataPusher ( object ) : <EOL> MAX_WORKERS = <NUM_LIT:5> <EOL> def __init__ ( self ) : <EOL> self . _queue = Queue . LifoQueue ( ) <EOL> self . _failedque = deque ( ) <EOL> self . _http_session = requests . Session ( ) <EOL> self . _http_offline = False <EOL> self . _workers = [ ] <EOL> def push ( self , item ) : <EOL> if self . _http_offline : <EOL> if "<STR_LIT>" not in item : <EOL> item [ '<STR_LIT>' ] = time ( ) <EOL> self . _failedque . append ( item ) <EOL> return <EOL> self . _queue . put ( item ) <EOL> self . _tune_workers ( ) <EOL> def in_wait ( self ) : <EOL> return self . _queue . unfinished_tasks <EOL> def get_items ( self ) : <EOL> items = list ( self . _failedque ) <EOL> try : <EOL> while True : <EOL> items . append ( self . _queue . get_nowait ( ) ) <EOL> except Queue . Empty : <EOL> pass <EOL> return items <EOL> def _tune_workers ( self ) : <EOL> for i , w in enumerate ( self . _workers ) : <EOL> if not w . is_alive ( ) : <EOL> del self . _workers [ i ] <EOL> need_nums = min ( self . _queue . qsize ( ) , self . MAX_WORKERS ) <EOL> active_nums = len ( self . _workers ) <EOL> if need_nums <= active_nums : <EOL> return <EOL> for i in range ( need_nums - active_nums ) : <EOL> t = threading . Thread ( target = self . _worker ) <EOL> t . daemon = True <EOL> t . start ( ) <EOL> self . _workers . append ( t ) <EOL> def _worker ( self ) : <EOL> while True : <EOL> try : <EOL> item = self . _queue . get ( ) <EOL> _item = item . copy ( ) <EOL> if "<STR_LIT>" not in _item : <EOL> _item [ '<STR_LIT>' ] = time ( ) <EOL> self . _failedque . append ( _item ) <EOL> if self . _send_data ( item ) : <EOL> self . _failedque . remove ( _item ) <EOL> self . _queue . task_done ( ) <EOL> except : <EOL> pass <EOL> def _send_data ( self , data ) : <EOL> if self . _http_offline : <EOL> return False <EOL> try : <EOL> r = self . _http_session . post ( <EOL> "<STR_LIT>" , <EOL> data = data , <EOL> headers = util . get_request_defheaders ( ) , <EOL> timeout = <NUM_LIT:1> <EOL> ) <EOL> r . raise_for_status ( ) <EOL> return True <EOL> except : <EOL> self . _http_offline = True <EOL> return False <EOL> def on_command ( ) : <EOL> resend_backuped_reports ( ) <EOL> mp = MeasurementProtocol ( ) <EOL> mp . send ( "<STR_LIT>" ) <EOL> if util . is_ci ( ) : <EOL> measure_ci ( ) <EOL> if app . get_session_var ( "<STR_LIT>" ) : <EOL> measure_caller ( app . get_session_var ( "<STR_LIT>" ) ) <EOL> def measure_ci ( ) : <EOL> event = { <EOL> "<STR_LIT>" : "<STR_LIT>" , <EOL> "<STR_LIT:action>" : "<STR_LIT>" , <EOL> "<STR_LIT:label>" : None <EOL> } <EOL> envmap = { <EOL> "<STR_LIT>" : { "<STR_LIT:label>" : getenv ( "<STR_LIT>" ) } , <EOL> "<STR_LIT>" : { "<STR_LIT:label>" : "<STR_LIT>" % ( getenv ( "<STR_LIT>" ) , <EOL> getenv ( "<STR_LIT>" ) ) } , <EOL> "<STR_LIT>" : { "<STR_LIT:label>" : getenv ( "<STR_LIT>" ) } , <EOL> "<STR_LIT>" : { "<STR_LIT:label>" : getenv ( "<STR_LIT>" ) } , <EOL> "<STR_LIT>" : { "<STR_LIT:label>" : getenv ( "<STR_LIT>" ) } <EOL> } <EOL> for key , value in envmap . iteritems ( ) : <EOL> if getenv ( key , "<STR_LIT>" ) . lower ( ) != "<STR_LIT:true>" : <EOL> continue <EOL> event . update ( { "<STR_LIT:action>" : key , "<STR_LIT:label>" : value [ '<STR_LIT:label>' ] } ) <EOL> on_event ( ** event ) <EOL> def measure_caller ( calller_id ) : <EOL> calller_id = str ( calller_id ) [ : <NUM_LIT:20> ] . lower ( ) <EOL> event = { <EOL> "<STR_LIT>" : "<STR_LIT>" , <EOL> "<STR_LIT:action>" : "<STR_LIT>" , <EOL> "<STR_LIT:label>" : calller_id <EOL> } <EOL> if calller_id in ( [ "<STR_LIT>" , "<STR_LIT>" ] + ProjectGenerator . get_supported_ides ( ) ) : <EOL> event [ '<STR_LIT:action>' ] = "<STR_LIT>" <EOL> on_event ( ** event ) <EOL> def on_run_environment ( options , targets ) : <EOL> opts = [ "<STR_LIT>" % ( opt , value ) for opt , value in sorted ( options . items ( ) ) ] <EOL> targets = [ t . title ( ) for t in targets or [ "<STR_LIT>" ] ] <EOL> on_event ( "<STR_LIT>" , "<STR_LIT:U+0020>" . join ( targets ) , "<STR_LIT:&>" . join ( opts ) ) <EOL> def on_event ( category , action , label = None , value = None , screen_name = None ) : <EOL> mp = MeasurementProtocol ( ) <EOL> mp [ '<STR_LIT>' ] = category [ : <NUM_LIT> ] <EOL> mp [ '<STR_LIT>' ] = action [ : <NUM_LIT> ] <EOL> if label : <EOL> mp [ '<STR_LIT>' ] = label [ : <NUM_LIT> ] <EOL> if value : <EOL> mp [ '<STR_LIT>' ] = int ( value ) <EOL> if screen_name : <EOL> mp [ '<STR_LIT>' ] = screen_name [ : <NUM_LIT> ] <EOL> mp . send ( "<STR_LIT>" ) <EOL> def on_exception ( e ) : <EOL> if isinstance ( e , exception . AbortedByUser ) : <EOL> return <EOL> is_crash = any ( [ <EOL> not isinstance ( e , exception . PlatformioException ) , <EOL> "<STR_LIT>" in e . __class__ . __name__ <EOL> ] ) <EOL> mp = MeasurementProtocol ( ) <EOL> mp [ '<STR_LIT>' ] = "<STR_LIT>" % ( type ( e ) . __name__ , format_exc ( ) if is_crash else e ) <EOL> mp [ '<STR_LIT>' ] = <NUM_LIT:1> if is_crash else <NUM_LIT:0> <EOL> mp . send ( "<STR_LIT>" ) <EOL> @ atexit . register <EOL> def _finalize ( ) : <EOL> timeout = <NUM_LIT:1000> <EOL> elapsed = <NUM_LIT:0> <EOL> try : <EOL> while elapsed < timeout : <EOL> if not MPDataPusher ( ) . in_wait ( ) : <EOL> break <EOL> sleep ( <NUM_LIT> ) <EOL> elapsed += <NUM_LIT:200> <EOL> backup_reports ( MPDataPusher ( ) . get_items ( ) ) <EOL> except KeyboardInterrupt : <EOL> pass <EOL> def backup_reports ( items ) : <EOL> if not items : <EOL> return <EOL> KEEP_MAX_REPORTS = <NUM_LIT:100> <EOL> tm = app . get_state_item ( "<STR_LIT>" , { } ) <EOL> if "<STR_LIT>" not in tm : <EOL> tm [ '<STR_LIT>' ] = [ ] <EOL> for params in items : <EOL> for key in params . keys ( ) : <EOL> if key in ( "<STR_LIT:v>" , "<STR_LIT>" , "<STR_LIT>" , "<STR_LIT>" , "<STR_LIT>" , "<STR_LIT>" , "<STR_LIT>" ) : <EOL> del params [ key ] <EOL> if "<STR_LIT>" not in params : <EOL> params [ '<STR_LIT>' ] = time ( ) <EOL> elif not isinstance ( params [ '<STR_LIT>' ] , float ) : <EOL> params [ '<STR_LIT>' ] = time ( ) - ( params [ '<STR_LIT>' ] / <NUM_LIT:1000> ) <EOL> tm [ '<STR_LIT>' ] . append ( params ) <EOL> tm [ '<STR_LIT>' ] = tm [ '<STR_LIT>' ] [ KEEP_MAX_REPORTS * - <NUM_LIT:1> : ] <EOL> app . set_state_item ( "<STR_LIT>" , tm ) <EOL> def resend_backuped_reports ( ) : <EOL> tm = app . get_state_item ( "<STR_LIT>" , { } ) <EOL> if "<STR_LIT>" not in tm or not tm [ '<STR_LIT>' ] : <EOL> return False <EOL> for report in tm [ '<STR_LIT>' ] : <EOL> mp = MeasurementProtocol ( ) <EOL> for key , value in report . items ( ) : <EOL> mp [ key ] = value <EOL> mp . send ( report [ '<STR_LIT:t>' ] ) <EOL> tm [ '<STR_LIT>' ] = [ ] <EOL> app . set_state_item ( "<STR_LIT>" , tm ) </s>
