From 80c9eb34e4c1fb88081238040d3dc39135ae2aec Mon Sep 17 00:00:00 2001 From: jackie-pc Date: Wed, 31 Jan 2024 11:39:48 -0800 Subject: [PATCH] Rework telemetry to support installation_id (#2480) --- reflex/reflex.py | 4 ++++ reflex/utils/prerequisites.py | 44 ++++++++++++++++++++++++++++++++--- reflex/utils/telemetry.py | 10 ++++++-- tests/utils/test_utils.py | 2 +- 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/reflex/reflex.py b/reflex/reflex.py index 4ea16466c..2ba0cc5a8 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -80,6 +80,10 @@ def _init( prerequisites.check_latest_package_version(constants.Reflex.MODULE_NAME) + prerequisites.initialize_reflex_user_directory() + + prerequisites.ensure_reflex_installation_id() + # Set up the app directory, only if the config doesn't exist. if not os.path.exists(constants.Config.FILE): if template is None: diff --git a/reflex/utils/prerequisites.py b/reflex/utils/prerequisites.py index 249b739cf..2b2109c22 100644 --- a/reflex/utils/prerequisites.py +++ b/reflex/utils/prerequisites.py @@ -16,7 +16,7 @@ import zipfile from fileinput import FileInput from pathlib import Path from types import ModuleType -from typing import Callable +from typing import Callable, Optional import httpx import pkg_resources @@ -824,10 +824,48 @@ def validate_frontend_dependencies(init=True): validate_bun() -def initialize_frontend_dependencies(): - """Initialize all the frontend dependencies.""" +def ensure_reflex_installation_id() -> Optional[int]: + """Ensures that a reflex distinct id has been generated and stored in the reflex directory. + + Returns: + Distinct id. + """ + try: + initialize_reflex_user_directory() + installation_id_file = os.path.join(constants.Reflex.DIR, "installation_id") + + installation_id = None + if os.path.exists(installation_id_file): + try: + with open(installation_id_file, "r") as f: + installation_id = int(f.read()) + except Exception: + # If anything goes wrong at all... just regenerate. + # Like what? Examples: + # - file not exists + # - file not readable + # - content not parseable as an int + pass + + if installation_id is None: + installation_id = random.getrandbits(128) + with open(installation_id_file, "w") as f: + f.write(str(installation_id)) + # If we get here, installation_id is definitely set + return installation_id + except Exception as e: + console.debug(f"Failed to ensure reflex installation id: {e}") + return None + + +def initialize_reflex_user_directory(): + """Initialize the reflex user directory.""" # Create the reflex directory. path_ops.mkdir(constants.Reflex.DIR) + + +def initialize_frontend_dependencies(): + """Initialize all the frontend dependencies.""" # validate dependencies before install validate_frontend_dependencies() # Install the frontend dependencies. diff --git a/reflex/utils/telemetry.py b/reflex/utils/telemetry.py index d6dd61d54..2b565f680 100644 --- a/reflex/utils/telemetry.py +++ b/reflex/utils/telemetry.py @@ -10,6 +10,7 @@ from datetime import datetime import psutil from reflex import constants +from reflex.utils.prerequisites import ensure_reflex_installation_id def get_os() -> str: @@ -79,15 +80,20 @@ def send(event: str, telemetry_enabled: bool | None = None) -> bool: if not telemetry_enabled: return False + installation_id = ensure_reflex_installation_id() + if installation_id is None: + return False + try: with open(constants.Dirs.REFLEX_JSON) as f: reflex_json = json.load(f) - distinct_id = reflex_json["project_hash"] + project_hash = reflex_json["project_hash"] post_hog = { "api_key": "phc_JoMo0fOyi0GQAooY3UyO9k0hebGkMyFJrrCw1Gt5SGb", "event": event, "properties": { - "distinct_id": distinct_id, + "distinct_id": installation_id, + "distinct_app_id": project_hash, "user_os": get_os(), "reflex_version": get_reflex_version(), "python_version": get_python_version(), diff --git a/tests/utils/test_utils.py b/tests/utils/test_utils.py index fac3fc3b7..0e2c48e50 100644 --- a/tests/utils/test_utils.py +++ b/tests/utils/test_utils.py @@ -485,7 +485,7 @@ def test_create_reflex_dir(mocker, is_windows): "reflex.utils.prerequisites.path_ops.mkdir", mocker.Mock() ) - prerequisites.initialize_frontend_dependencies() + prerequisites.initialize_reflex_user_directory() assert create_cmd.called