Skip to main content

Overview

The remote_config module integrates with Firebase Remote Config to dynamically fetch API endpoint URLs. This allows the Cricfy plugin to update API endpoints without requiring plugin updates.
This implementation is based on the Firebase Remote Config REST API and mimics an Android app client to retrieve configuration values.Credits: Adapted from CNCVerse Cloud Stream Extension

Functions

fetch_remote_config()

Fetches Firebase Remote Config and returns the configuration entries.
def fetch_remote_config()
Returns:
entries
Optional[dict]
Dictionary of configuration entries (key-value pairs), or None if fetch failsCommon entries:
  • "cric_api1": Primary API endpoint URL
  • "cric_api2": Secondary API endpoint URL
Request Details: The function makes a POST request to:
https://firebaseremoteconfig.googleapis.com/v1/projects/{PROJECT_NUMBER}/namespaces/firebase:fetch
Request Payload:
{
  "appInstanceId": "<random_hex_uuid>",
  "appInstanceIdToken": "",
  "appId": "<CRICFY_FIREBASE_APP_ID>",
  "countryCode": "US",
  "languageCode": "en-US",
  "platformVersion": "30",
  "timeZone": "UTC",
  "appVersion": "5.0",
  "appBuild": "50",
  "packageName": "<CRICFY_PACKAGE_NAME>",
  "sdkVersion": "22.1.0",
  "analyticsUserProperties": {}
}
Request Headers:
HeaderValue
Content-Typeapplication/json
Acceptapplication/json
X-Android-Package{CRICFY_PACKAGE_NAME}
X-Goog-Api-Key{CRICFY_FIREBASE_API_KEY}
X-Google-GFE-Can-Retryyes
Configuration:
Firebase credentials are loaded from resources/cricfy_properties.json:
  • cricfy_package_name: Android package identifier
  • cricfy_firebase_api_key: Firebase Web API key
  • cricfy_firebase_app_id: Firebase App ID (format: 1:PROJECT_NUMBER:...)
Example:
from lib.remote_config import fetch_remote_config

config = fetch_remote_config()
if config:
    print(f"API 1: {config.get('cric_api1')}")
    print(f"API 2: {config.get('cric_api2')}")
else:
    print("Failed to fetch remote config")
Error Handling:
Returns None if:
  • Firebase credentials are missing or invalid
  • Network request fails
  • Response status is not 200
  • Response parsing fails
All errors are logged using log_error()

get_provider_api_url()

Gets the provider API URL from Firebase Remote Config with retry logic.
def get_provider_api_url()
Returns:
api_url
Optional[str]
Provider API base URL, or None if all retry attempts fail
Behavior:
  • Retries up to 3 times if fetch fails
  • Prioritizes "cric_api2" over "cric_api1"
  • Returns the first available API URL
  • Returns None if no API URLs are available after all retries
Priority Logic:
return entries.get("cric_api2") or entries.get("cric_api1")
This ensures the secondary API is used if available, falling back to the primary API. Example:
from lib.remote_config import get_provider_api_url

api_url = get_provider_api_url()
if api_url:
    providers_url = f"{api_url}/cats.txt"
    print(f"Fetching providers from: {providers_url}")
else:
    print("Could not retrieve API URL")

get_api_urls()

Gets all available API URLs from Firebase Remote Config.
def get_api_urls()
Returns:
api_urls
Optional[tuple]
Tuple containing (api1, api2) where each value is a string URL or NoneReturns None if the remote config fetch fails entirely
Example:
from lib.remote_config import get_api_urls

urls = get_api_urls()
if urls:
    api1, api2 = urls
    print(f"Primary API: {api1}")
    print(f"Secondary API: {api2}")
    
    # Use secondary if available, otherwise primary
    active_api = api2 or api1
    print(f"Using: {active_api}")
else:
    print("Failed to fetch API URLs")
Use Case: This function is useful when you need access to both API endpoints, for example:
  • Load balancing between endpoints
  • Fallback logic if one endpoint fails
  • Health monitoring of multiple endpoints

Internal Functions

_get_random_instance_id()

Generates a random UUID without dashes for use as a fake app instance ID.
def _get_random_instance_id()
Returns:
instance_id
str
32-character hexadecimal string (UUID without hyphens)
Example Output:
a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6

Configuration File

cricfy_properties.json

The module reads Firebase configuration from {ADDON_PATH}/resources/cricfy_properties.json:
{
  "cricfy_package_name": "com.example.cricfy",
  "cricfy_firebase_api_key": "AIzaSyABC123...",
  "cricfy_firebase_app_id": "1:123456789:android:abc123def456"
}
cricfy_package_name
str
required
Android package identifier (reverse domain notation)
cricfy_firebase_api_key
str
required
Firebase Web API Key (starts with AIzaSy)
cricfy_firebase_app_id
str
required
Firebase App ID in format 1:PROJECT_NUMBER:android:APP_ID

Constants

ConstantSourceDescription
CRICFY_PACKAGE_NAMEcricfy_properties.jsonAndroid package name
CRICFY_FIREBASE_API_KEYcricfy_properties.jsonFirebase API key
CRICFY_FIREBASE_APP_IDcricfy_properties.jsonFirebase app identifier
PROJECT_NUMBERExtracted from app IDFirebase project number
Extraction Logic:
PROJECT_NUMBER = CRICFY_FIREBASE_APP_ID.split(":")[1]
From app ID "1:123456789:android:abc123", extracts "123456789"

Response Format

Successful Response

Firebase Remote Config returns JSON in this format:
{
  "entries": {
    "cric_api1": "https://api1.example.com",
    "cric_api2": "https://api2.example.com",
    "other_config_key": "other_value"
  },
  "state": "UPDATE"
}
The module extracts and returns the "entries" dictionary.

Dependencies

  • requests - HTTP client for API requests
  • uuid - Random instance ID generation
  • json - JSON parsing
  • lib.config.ADDON_PATH - Plugin installation path
  • lib.logger - Error logging

Error Scenarios

The module logs errors but returns None in these cases:
  1. Missing Credentials: Firebase API key, App ID, or project number not found
  2. Network Failure: Connection timeout or network error (30-second timeout)
  3. HTTP Error: Response status code != 200
  4. Malformed Response: JSON parsing fails or missing "entries" key
Always check for None return values before using the results.
Example Error Handling:
from lib.remote_config import get_provider_api_url
from lib.logger import log_error

api_url = get_provider_api_url()
if not api_url:
    log_error("main", "Failed to get provider API URL")
    # Use fallback or show error to user
    return

# Continue with valid api_url
providers_endpoint = f"{api_url}/cats.txt"

Build docs developers (and LLMs) love