o
    g                     @   sl  d Z ddlZddlZddlZddlZddlmZmZmZm	Z	m
Z
 ddlmZ ddlZddlZddlZddlmZmZmZ ddlZejejd eeZdZdZed	 ZG d
d deZG dd deZG dd dZG dd dZG dd dZ G dd dZ!G dd dZ"d!dedeee#e#f  fddZ$		d"dedeee#e#f  dee# fddZ%G dd  d Z&dS )#zxFirebase Remote Config Module.
This module has required APIs for the clients to use Firebase Remote Config with python.
    N)DictOptionalLiteralUnionAny)Enum)App_http_client_utils)level_remoteconfig
   )defaultremotestaticc                   @   s    e Zd ZdZdZdZdZdZdS )PercentConditionOperatorzFEnum representing the available operators for percent conditions.
    LESS_OR_EQUALGREATER_THANBETWEENUNKNOWNN)__name__
__module____qualname____doc__r   r   r   r    r   r   V/var/www/html/api-tag/env/lib/python3.10/site-packages/firebase_admin/remote_config.pyr   '   s    r   c                   @   sT   e Zd ZdZdZdZdZdZdZdZ	dZ
d	Zd
ZdZdZdZdZdZdZdZdZdS )CustomSignalOperatorzLEnum representing the available operators for custom signal conditions.
    STRING_CONTAINSSTRING_DOES_NOT_CONTAINSTRING_EXACTLY_MATCHESSTRING_CONTAINS_REGEXNUMERIC_LESS_THANNUMERIC_LESS_EQUALNUMERIC_EQUALNUMERIC_NOT_EQUALNUMERIC_GREATER_THANNUMERIC_GREATER_EQUALSEMANTIC_VERSION_LESS_THANSEMANTIC_VERSION_LESS_EQUALSEMANTIC_VERSION_EQUALSEMANTIC_VERSION_NOT_EQUALSEMANTIC_VERSION_GREATER_THANSEMANTIC_VERSION_GREATER_EQUALr   N)r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   r   r   r   r   r   r   /   s&    r   c                   @   sT   e Zd ZdZdd Zedd Zedd Zedd	 Zed
d Z	edd Z
dS )_ServerTemplateDataz>Parses, validates and encapsulates template data and metadata.c                 C   s   d|v r|d dur|d | _ ntdi | _ d|v r+|d dur'|d | _ntdg | _d| _d|v r:|d | _d| _d|v rMt|d trM|d | _t|| _	dS )	zInitializes a new ServerTemplateData instance.

        Args:
            template_data: The data to be parsed for getting the parameters and conditions.

        Raises:
            ValueError: If the template data is not valid.
        
parametersNz2Remote Config parameters must be a non-null object
conditionsz2Remote Config conditions must be a non-null object versionetag)
_parameters
ValueError_conditions_version_etag
isinstancestrjsondumps_template_data_json)selftemplate_datar   r   r   __init__F   s"   	

z_ServerTemplateData.__init__c                 C      | j S N)r3   r=   r   r   r   r.   i      z_ServerTemplateData.parametersc                 C   r@   rA   )r7   rB   r   r   r   r2   m   rC   z_ServerTemplateData.etagc                 C   r@   rA   )r6   rB   r   r   r   r1   q   rC   z_ServerTemplateData.versionc                 C   r@   rA   )r5   rB   r   r   r   r/   u   rC   z_ServerTemplateData.conditionsc                 C   r@   rA   )r<   rB   r   r   r   template_data_jsony   rC   z&_ServerTemplateData.template_data_jsonN)r   r   r   r   r?   propertyr.   r2   r1   r/   rD   r   r   r   r   r-   D   s    #



r-   c                   @   sv   e Zd ZdZddedeeeef  fddZdd Z	dd	eeee
eef f  d
dfddZdefddZdd ZdS )ServerTemplatezZRepresents a Server Template with implementations for loading and evaluating the template.Nappdefault_configc                 C   sR   t |tt| _d| _i | _t | _	|dur%|D ]}t
|| | j|< qdS dS )a  Initializes a ServerTemplate instance.

        Args:
          app: App instance to be used. This is optional and the default app instance will
                be used if not present.
          default_config: The default config to be used in the evaluated config.
        N)r
   get_app_service_REMOTE_CONFIG_ATTRIBUTE_RemoteConfigService_rc_service_cache_stringified_default_config	threadingRLock_lockr9   )r=   rG   rH   keyr   r   r   r?      s   
zServerTemplate.__init__c                    sD   | j  I dH }| j || _W d   dS 1 sw   Y  dS )z0Fetches the server template and caches the data.N)rL   get_server_templaterQ   rM   )r=   rc_server_templater   r   r   load   s
   "zServerTemplate.loadcontextreturnServerConfigc                 C   s   | j std|p
i }i }| j | j j}| j j}W d   n1 s#w   Y  | jdur>| j D ]\}}td|||< q2t||||| _	t
| j	 dS )a"  Evaluates the cached server template to produce a ServerConfig.

        Args:
          context: A dictionary of values to use for evaluating conditions.

        Returns:
          A ServerConfig object.
        Raises:
            ValueError: If the input arguments are invalid.
        zmNo Remote Config Server template in cache.
                            Call load() before calling evaluate().Nr   )config_values)rM   r4   rQ   r/   r.   rN   items_Value_ConditionEvaluator
_evaluatorrX   evaluate)r=   rV   rY   template_conditionstemplate_parametersrR   valuer   r   r   r^      s    

zServerTemplate.evaluaterD   c                 C   sD   t |}t|}| j || _W d   dS 1 sw   Y  dS )zUpdates the cache to store the given template is of type ServerTemplateData.

        Args:
          template_data_json: A json string representing ServerTemplateData to be cached.
        N)r:   loadsr-   rQ   rM   )r=   rD   template_data_mapr>   r   r   r   set   s
   
"zServerTemplate.setc                 C   sB   | j std| j | j j}W d   |S 1 sw   Y  |S )zRProvides the server template in a JSON format to be used for initialization later.zkNo Remote Config Server template in cache.
                            Call load() before calling toJSON().N)rM   r4   rQ   rD   )r=   template_jsonr   r   r   to_json   s   

zServerTemplate.to_jsonNNrA   )r   r   r   r   r   r   r   r9   r?   rU   r   intr^   rd   rf   r   r   r   r   rF   ~   s     (rF   c                   @   sH   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dS )rX   z.Represents a Remote Config Server Side Config.c                 C   s
   || _ d S rA   )_config_values)r=   rY   r   r   r   r?      s   
zServerConfig.__init__c                 C      |  | S )Returns the value as a boolean.)
_get_value
as_booleanr=   rR   r   r   r   get_boolean      zServerConfig.get_booleanc                 C   rj   )Returns the value as a string.)rl   	as_stringrn   r   r   r   
get_string   rp   zServerConfig.get_stringc                 C   rj   )z Returns the value as an integer.)rl   as_intrn   r   r   r   get_int   rp   zServerConfig.get_intc                 C   rj   )zReturns the value as a float.)rl   as_floatrn   r   r   r   	get_float   rp   zServerConfig.get_floatc                 C   rj   z Returns the source of the value.)rl   
get_sourcern   r   r   r   get_value_source   rp   zServerConfig.get_value_sourcec                 C   s   | j |tdS )Nr   )ri   getr[   rn   r   r   r   rl      s   zServerConfig._get_valueN)r   r   r   r   r?   ro   rs   ru   rw   rz   rl   r   r   r   r   rX      s    rX   c                   @   s:   e Zd ZdZdd Zdd Zdd Zedefd	d
Z	dS )rK   zhInternal class that facilitates sending requests to the Firebase Remote
        Config backend API.
    c                 C   sN   d}|j | _|j }ddtji}|jdt	j
}t	j||||d| _dS )zInitialize a JsonHttpClient with necessary inputs.

        Args:
            app: App instance to be used for fetching app specific details required
                for initializing the http client.
        z+https://firebaseremoteconfig.googleapis.comzX-FIREBASE-CLIENTzfire-admin-python/{0}httpTimeout)
credentialbase_urlheaderstimeoutN)
project_id_project_idr}   get_credentialformatfirebase_admin__version__optionsr{   r	   DEFAULT_TIMEOUT_SECONDSJsonHttpClient_client)r=   rG   remote_config_base_urlapp_credential
rc_headersr   r   r   r   r?      s   
z_RemoteConfigService.__init__c              
      sn   zt  }|d| jjd|  I dH \}}W n tjjy+ } z| 	|d}~ww |
d|d< t|S )zRequests for a server template and converts the response to an instance of
        ServerTemplateData for storing the template parameters and conditions.Nr{   r2   )asyncioget_event_looprun_in_executorr   headers_and_body_get_urlrequests
exceptionsRequestException_handle_remote_config_errorr{   r-   )r=   loopr   r>   errorr   r   r   rS     s   
z(_RemoteConfigService.get_server_templatec                 C   s   d | jS )zJReturns project prefix for url, in the format of /v1/projects/${projectId}z>/v1/projects/{0}/namespaces/firebase-server/serverRemoteConfig)r   r   rB   r   r   r   r     s   z_RemoteConfigService._get_urlr   c                 C   s
   t |S )z5Handles errors received from the Cloud Functions API.)r
   #handle_platform_error_from_requests)clsr   r   r   r   r     s   
z0_RemoteConfigService._handle_remote_config_errorN)
r   r   r   r   r?   rS   r   classmethodr   r   r   r   r   r   rK      s    rK   c                   @   s   e Zd ZdZdd Zdd Zdeeef fddZ			d!d
e
defddZ		d!d
e
defddZ		d!d
e
defddZdefddZdede
fddZdefddZdefddZdefddZdefddZdefddZd S )"r\   z_Internal class that facilitates sending requests to the Firebase Remote
    Config backend API.c                 C   s   || _ || _|| _|| _d S rA   )_contextr5   r3   ri   )r=   r/   r.   rV   rY   r   r   r   r?   !  s   
z_ConditionEvaluator.__init__c           
      C   s   |  | j| j}| jrx| j D ]g\}}|di }|di }d}|r9| D ]\}}||v r8|r8|| } nq(|rG|drGtd| q|rW|d}	td|	| j	|< q|s`t
d| q|drltd| qtd|d| j	|< q| j	S )	z]Internal function that evaluates the cached server template to produce
        a ServerConfigconditionalValuesdefaultValueNuseInAppDefaultz'Using in-app default value for key '%s'ra   r   z#No default value found for key '%s')evaluate_conditionsr5   r   r3   rZ   r{   loggerinfor[   ri   warning)
r=   evaluated_conditionsrR   	parameterconditional_valuesdefault_valueparameter_value_wrappercondition_namecondition_evaluationparameter_valuer   r   r   r^   '  s6   

z_ConditionEvaluator.evaluaterW   c                 C   s.   i }|D ]}|  |d|||d< q|S )a%  Evaluates a list of conditions and returns a dictionary of results.

        Args:
          conditions: A list of NamedCondition objects.
          context: An EvaluationContext object.

        Returns:
          A dictionary that maps condition names to boolean evaluation results.
        	conditionname)evaluate_conditionr{   )r=   r/   rV   r   r   r   r   r   r   M  s   

z'_ConditionEvaluator.evaluate_conditionsr   nesting_levelc                 C   s   |t krtd dS |ddur| |d||d S |ddur1| |d||d S |ddur:dS |d	durCdS |d
durS| |d
|S |ddurc| |d|S td dS )a  Recursively evaluates a condition.

        Args:
          condition: The condition to evaluate.
          context: An EvaluationContext object.
          nesting_level: The current recursion depth.

        Returns:
          The boolean result of the condition evaluation.
        z+Maximum condition recursion depth exceeded.ForConditionN   andConditiontrueTfalsepercentcustomSignalz#Unknown condition type encountered.)MAX_CONDITION_RECURSION_DEPTHr   r   r{   evaluate_or_conditionevaluate_and_conditionevaluate_percent_condition evaluate_custom_signal_condition)r=   r   rV   r   r   r   r   r   ^  s*   

z&_ConditionEvaluator.evaluate_conditionc                 C   s8   | dpg }|D ]}| |||d }|r dS q	dS )a&  Evaluates an OR condition.

        Args:
          or_condition: The OR condition to evaluate.
          context: An EvaluationContext object.
          nesting_level: The current recursion depth.

        Returns:
          True if any of the subconditions are true, False otherwise.
        r/   r   TFr{   r   )r=   or_conditionrV   r   sub_conditionssub_conditionresultr   r   r   r   ~     z)_ConditionEvaluator.evaluate_or_conditionc                 C   s8   | dpg }|D ]}| |||d }|s dS q	dS )a(  Evaluates an AND condition.

        Args:
          and_condition: The AND condition to evaluate.
          context: An EvaluationContext object.
          nesting_level: The current recursion depth.

        Returns:
          True if all of the subconditions are met; False otherwise.
        r/   r   FTr   )r=   and_conditionrV   r   r   r   r   r   r   r   r     r   z*_ConditionEvaluator.evaluate_and_conditionc                 C   s  | dstd dS | d}| d}| d}| d}|s)td dS |r:| d	p1d
}| dp8d
}nd
}d
}|rC|}	nd
}	|rL| dnd}
|
 | d }| |}|d }|tjjkrj||	kS |tjjkrt||	kS |tjjkr||  k o|kS   S td| dS )zEvaluates a percent condition.

        Args:
          percent_condition: The percent condition to evaluate.
          context: An EvaluationContext object.

        Returns:
          True if the condition is met, False otherwise.
        randomization_idzEMissing randomization_id in context for evaluating percent condition.FseedpercentOperatormicroPercentmicroPercentRangez/Missing percent operator for percent condition.microPercentUpperBoundr   microPercentLowerBound.r0   i zUnknown percent operator: %s)	r{   r   r   hash_seeded_randomization_idr   r   ra   r   r   )r=   percent_conditionrV   r   percent_operatormicro_percentmicro_percent_rangenorm_percent_upper_boundnorm_percent_lower_boundnorm_micro_percentseed_prefixstring_to_hashhash64instance_micro_percentiler   r   r   r     s<   







z._ConditionEvaluator.evaluate_percent_conditionseeded_randomization_idc                 C   s.   t  }||d | }tt|dS )zHashes a seeded randomization ID.

        Args:
          seeded_randomization_id: The seeded randomization ID to hash.

        Returns:
          The hashed value.
        zutf-8   )hashlibsha256updateencode	hexdigestabsrh   )r=   r   hash_objectr   r   r   r   r     s   	z0_ConditionEvaluator.hash_seeded_randomization_idc                 C   s  | dpi }| dpi }| dpi }t|||gs#td dS |s'dS | |p-i }|s8td| dS |tjjkrG| ||dd S |tj	jkrW| ||d	d  S |tj
jkrf| ||d
d S |tjjkrt| ||tjS |tjjkr| ||d |dd S |tjjkr| ||d |dd S |tjjkr| ||d |dd S |tjjkr| ||d |dd S |tjjkr| ||d |dd S |tjjkr| ||d |dd S |tjjkr| ||d |dd S |tjjkr| ||d |dd S |tjjkr| ||d |dd S |tjjkr+| ||d |dd S |tjjkr>| ||d |dd S |tjjkrQ| ||d |dd S td| dS )a  Evaluates a custom signal condition.

        Args:
          custom_signal_condition: The custom signal condition to evaluate.
          context: An EvaluationContext object.

        Returns:
          True if the condition is met, False otherwise.
        customSignalOperatorcustomSignalKeytargetCustomSignalValueszDMissing operator, key, or target values for custom signal condition.Fz,Custom signal value not found in context: %sc                 S      | |v S rA   r   targetactualr   r   r   <lambda>       zF_ConditionEvaluator.evaluate_custom_signal_condition.<locals>.<lambda>c                 S   r   rA   r   r   r   r   r   r     r   c                 S   s   |   |  kS rA   )stripr   r   r   r   r     s    r   c                 S      | dk S Nr   r   rr   r   r   r     r   c                 S      | dkS r   r   r   r   r   r   r     r   c                 S      | dkS r   r   r   r   r   r   r     r   c                 S      | dkS r   r   r   r   r   r   r   "  r   c                 S      | dkS r   r   r   r   r   r   r   '  r   c                 S      | dkS r   r   r   r   r   r   r   ,  r   c                 S   r   r   r   r   r   r   r   r   3  r   c                 S   r   r   r   r   r   r   r   r   8  r   c                 S   r   r   r   r   r   r   r   r   =  r   c                 S   r   r   r   r   r   r   r   r   B  r   c                 S   r   r   r   r   r   r   r   r   G  r   c                 S   r   r   r   r   r   r   r   r   L  r   z"Unknown custom signal operator: %s)r{   allr   r   debugr   r   ra   _compare_stringsr   r   r    researchr!   _compare_numbersr"   r#   r$   r%   r&   r'   _compare_semantic_versionsr(   r)   r*   r+   r,   )r=   custom_signal_conditionrV   custom_signal_operatorcustom_signal_keytarget_custom_signal_valuesactual_custom_signal_valuer   r   r   r     s   
z4_ConditionEvaluator.evaluate_custom_signal_conditionc                 C   s"   |D ]}||t |r dS qdS )aj  Compares the actual string value of a signal against a list of target values.

        Args:
            target_values: A list of target string values.
            actual_value: The actual value to compare, which can be a string or number.
            predicate_fn: A function that takes two string arguments (target and actual)
                            and returns a boolean indicating whether
                            the target matches the actual value.

        Returns:
            bool: True if the predicate function returns True for any target value in the list,
                False otherwise.
        TF)r9   )r=   target_valuesactual_valuepredicate_fnr   r   r   r   r   P  s
   z$_ConditionEvaluator._compare_stringsc                 C   sX   zt |}t |}||k rdn||krdnd}||W S  ty+   td| Y dS w )Nr   r   z>Invalid numeric value for comparison for custom signal key %s.F)floatr4   r   r   )r=   r   target_valuer   r  r   r   r   r   r   r   r   d  s   
z$_ConditionEvaluator._compare_numbersc                 C   s   |  |t|t||S )a  Compares the actual semantic version value of a signal against a target value.
        Calls the predicate function with -1, 0, 1 if actual is less than, equal to,
        or greater than target.

        Args:
        custom_signal_key: The custom signal for which the evaluation is being performed.
        target_values: A list of target string values.
        actual_value: The actual value to compare, which can be a string or number.
        predicate_fn: A function that takes an integer (-1, 0, or 1) and returns a boolean.

        Returns:
            bool: True if the predicate function returns True for the result of the comparison,
        False otherwise.
        )_compare_versionsr9   )r=   r   r  r   r  r   r   r   r   o  s   z._ConditionEvaluator._compare_semantic_versionsc           
      C   s   zfdd | dD }dd | dD }tt|t|}|dg|t|   |dg|t|   t||D ]&\}}	t|dk |	dk frKt||	k rV|d  W S ||	kra|d  W S q;|dW S  tyv   td| Y d	S w )
a  Compares two semantic version strings.

        Args:
            custom_signal_key: The custom singal for which the evaluation is being performed.
            sem_version_1: The first semantic version string.
            sem_version_2: The second semantic version string.
            predicate_fn: A function that takes an integer and returns a boolean.

        Returns:
            bool: The result of the predicate function.
        c                 S      g | ]}t |qS r   rh   .0partr   r   r   
<listcomp>      z9_ConditionEvaluator._compare_versions.<locals>.<listcomp>r   c                 S   r  r   r  r  r   r   r   r    r  r   r  r   zHInvalid semantic version format for comparison for custom signal key %s.F)	splitmaxlenextendzipanyr4   r   r   )
r=   r   sem_version_1sem_version_2r  v1_partsv2_parts
max_lengthpart1part2r   r   r   r    s,   
z%_ConditionEvaluator._compare_versionsN)r   )r   r   r   r   r?   r^   r   r9   boolr   rh   r   r   r   r   r   r   r   r   r   r  r   r   r   r   r\     sL    &
"


-
o
r\   rG   rH   c                    s    t | |d}| I dH  |S )a  Initializes a new ServerTemplate instance and fetches the server template.

    Args:
        app: App instance to be used. This is optional and the default app instance will
            be used if not present.
        default_config: The default config to be used in the evaluated config.

    Returns:
        ServerTemplate: An object having the cached server template to be used for evaluation.
    rG   rH   N)init_server_templaterU   )rG   rH   templater   r   r   rS     s   rS   rD   c                 C   s"   t | |d}|dur|| |S )a  Initializes a new ServerTemplate instance.

    Args:
        app: App instance to be used. This is optional and the default app instance will
            be used if not present.
        default_config: The default config to be used in the evaluated config.
        template_data_json: An optional template data JSON to be set on initialization.

    Returns:
        ServerTemplate: A new ServerTemplate instance initialized with an optional
        template and config.
    r  N)rF   rd   )rG   rH   rD   r  r   r   r   r    s   
r  c                   @   s   e Zd ZdZdZdZdZdZg dZefde	de
fd	d
Zde
fddZdefddZdefddZdefddZde	fddZdS )r[   z3Represents a value fetched from Remote Config.
    Fr0   r   g        )1r   tyesyonsourcera   c                 C   s   || _ || _dS )a  Initializes a Value instance.

        Args:
          source: The source of the value (e.g., 'default', 'remote', 'static').
          "static" indicates the value was defined by a static constant.
          "default" indicates the value was defined by default config.
          "remote" indicates the value was defined by config produced by evaluating a template.
          value: The string value.
        N)r#  ra   )r=   r#  ra   r   r   r   r?     s   

z_Value.__init__rW   c                 C   s   | j dkr| jS t| jS )rq   r   )r#  DEFAULT_VALUE_FOR_STRINGr9   ra   rB   r   r   r   rr     s   

z_Value.as_stringc                 C   s$   | j dkr| jS t| j | jv S )rk   r   )r#  DEFAULT_VALUE_FOR_BOOLEANr9   ra   lowerBOOLEAN_TRUTHY_VALUESrB   r   r   r   rm     s   
z_Value.as_booleanc                 C   6   | j dkr| jS zt| jW S  ty   | j Y S w zReturns the value as a number.r   )r#  DEFAULT_VALUE_FOR_INTEGERrh   ra   r4   rB   r   r   r   rt        

z_Value.as_intc                 C   r(  r)  )r#  DEFAULT_VALUE_FOR_FLOAT_NUMBERr  ra   r4   rB   r   r   r   rv     r+  z_Value.as_floatc                 C   r@   rx   )r#  rB   r   r   r   ry     rC   z_Value.get_sourceN)r   r   r   r   r%  r$  r*  r,  r'  ValueSourcer9   r?   rr   r  rm   r  rt   rv   ry   r   r   r   r   r[     s    		r[   rg   )NNN)'r   r   r:   loggingrO   typingr   r   r   r   r   enumr   r   r   r   r   r   r	   r
   basicConfigINFO	getLoggerr   r   rJ   r   r-  r   r   r-   rF   rX   rK   r\   r9   rS   r  r[   r   r   r   r   <module>   sD   
:T/    	
