
    `gj                        d Z ddlmZ ddlZddlmZmZmZmZ  ej                  d      Z
dZdZdZ G d	 d
e      Z G d d      Zy)u)  Thin HTTP client for the agent → NAS ``agent-cron`` endpoints (Chronos).

The Chronos provider speaks ONLY to NAS — it names no scheduler vendor and
holds no scheduler credentials. NAS owns the external scheduler (an internal
implementation detail) and that scheduler's account; the agent just asks NAS to
"arm a one-shot at time T" / "cancel" / "list", authenticated with the agent's
existing Nous Portal access token (the same token it already uses to call the
portal — no new secret).

Wire contract: ``docs/chronos-managed-cron-contract.md``.
    )annotationsN)AnyDictListOptionalzcron.chronosz/api/agent-cron/provisionz/api/agent-cron/cancelz/api/agent-cron/listc                      e Zd ZdZy)NasCronClientErrorzERaised when a NAS agent-cron call fails (non-2xx or transport error).N)__name__
__module____qualname____doc__     ]/root/.hermes/venv/lib/python3.12/site-packages/plugins/cron_providers/chronos/_nas_client.pyr	   r	      s    Or   r	   c                  ^    e Zd ZdZddddZddZddZddZddZ	 	 	 	 dd	Z	dd
Z
ddZy)NasCronClientu   Minimal client for the agent→NAS provision/cancel/list endpoints.

    Uses the agent's refresh-aware Nous access token for auth. No scheduler
    vendor, no scheduler creds — NAS hides all of that behind these three calls.
    g      .@)timeout_secondsc               >    |j                  d      | _        || _        y )N/)rstrip
portal_urlr   )selfr   r   s      r   __init__zNasCronClient.__init__%   s    $++C0.r   c                    ddl m}  |       S )z>The agent's existing Nous Portal access token (refresh-aware).r   )resolve_nous_access_token)hermes_cli.authr   )r   r   s     r   _access_tokenzNasCronClient._access_token+   s    =(**r   c                .    d| j                          ddS )NzBearer zapplication/json)AuthorizationzContent-Type)r   )r   s    r   _headerszNasCronClient._headers0   s#    &t'9'9';&<=.
 	
r   c           
        dd l }| j                   | }	 |j                  ||| j                         | j                        }|j                  dz  dk7  r+t        d| d|j                   d|j                  d d	        	 |j                  r|j                         S i S # t
        $ r}t        d| d|       |d }~ww xY w# t
        $ r i cY S w xY w)
Nr   )jsonheaderstimeoutzPOST 	 failed: d      
 returned :    )requestsr   postr    r   	Exceptionr	   status_codetextcontentr"   )r   pathbodyr+   urlrespes          r   _postzNasCronClient._post8   s    !$(	H==$AUAU ! D
 s"a'$vZ(8(8'9DIIdsO;LM 	"&,,499;6B6  	H$uTF)A3%?@aG	H  	I	/   -B C C 	B?(B::B?CCc           
        dd l }| j                   | }	 |j                  ||| j                         | j                        }|j                  dz  dk7  r+t        d| d|j                   d|j                  d d	        	 |j                  r|j                         S i S # t
        $ r}t        d| d|       |d }~ww xY w# t
        $ r i cY S w xY w)
Nr   )paramsr#   r$   zGET r%   r&   r'   r(   r)   r*   )r+   r   getr    r   r-   r	   r.   r/   r0   r"   )r   r1   r9   r+   r3   r4   r5   s          r   _getzNasCronClient._getK   s    !$(	G<<FDMMOTEYEY   D
 s"a'$tfJt'7'7&8499Tc?:KL 	"&,,499;6B6  	G$tD61#%>?QF	G  	I	r7   c               8    | j                  t        ||||d      S )zAsk NAS to arm a one-shot for ``job_id`` at ``fire_at`` (ISO 8601).

        ``dedup_key`` (``{job_id}:{fire_at}``) makes re-arming the same fire
        idempotent NAS-side. Returns the NAS response (e.g. ``{schedule_id}``).
        )job_idfire_atagent_callback_url	dedup_key)r6   _PROVISION_PATH)r   r=   r>   r?   r@   s        r   	provisionzNasCronClient.provision`   s(     zz/"4"	,
  	r   c               2    | j                  t        d|i      S )z4Ask NAS to cancel any armed one-shot for ``job_id``.r=   )r6   _CANCEL_PATH)r   r=   s     r   cancelzNasCronClient.canceln   s    zz,6(:;;r   c                    | j                  t        i       }t        |t              r|j	                  d      nd}t        |t
              r|S g S )a#  List the one-shots NAS currently has armed for this agent.

        Returns a list of ``{job_id, fire_at, schedule_id}``. Best-effort: used
        by reconcile to find orphaned arms on a cold process; on error the
        caller falls back to idempotent re-arm of all desired jobs.
        armedN)r;   
_LIST_PATH
isinstancedictr:   list)r   dataitemss      r   
list_armedzNasCronClient.list_armedr   sA     yyR(%/d%;!"5$/u7R7r   N)r   strr   floatreturnNone)rQ   rO   )rQ   zDict[str, str])r1   rO   r2   Dict[str, Any]rQ   rS   )r1   rO   r9   rS   rQ   rS   )
r=   rO   r>   rO   r?   rO   r@   rO   rQ   rS   )r=   rO   rQ   rS   )rQ   zList[Dict[str, Any]])r
   r   r   r   r   r   r    r6   r;   rB   rE   rN   r   r   r   r   r      sF     EI /+

&* %3<	8r   r   )r   
__future__r   loggingtypingr   r   r   r   	getLoggerloggerrA   rD   rH   RuntimeErrorr	   r   r   r   r   <module>rZ      sU   
 #  , ,			>	* .'#
P P]8 ]8r   