o
    [h\.                     @   s  d dl Z d dlZd dlZd dlZd dlZd dlmZ d dlmZm	Z	 d dl
mZ d dlmZ d dlmZ d dlm  mZ d dlmZ d dlmZ d	Zed
Ze eZzd dlmZ  d dl!m"Z" W n e#yq   e$d Y nw G dd deZ%e%j&dddeddd gie%j'ddgie%j(ddgiiZ)de%fddZ*G dd dZ+dZ,dZ-G dd  d e"Z.de/fd!d"Z0G d#d$ d$Z1dS )%    N)Enum)check_outputPopen)urljoin)settings)reverse)SESSION_CONFIGS_DICT)get_admin_secret_codez
Could not login to the server using your ADMIN_USERNAME
and ADMIN_PASSWORD from settings.py. If you are testing
browser bots on a remote server, make sure the username
and password on your local oTree installation match that
on the server.
ZOTREE_REST_KEY)session)WebSocketClientzZTo use command-line browser bots, you need to pip install "requests" and "ws4py" locally. c                   @   s   e Zd ZdZdZdZdS )OSEnumwindowsmaclinuxN)__name__
__module____qualname__r   r   r    r   r   /home/ubuntu/experiments/live_experiments/Pythonexperiments/Otree/venv/lib/python3.10/site-packages/otree/bots/browser_launcher.pyr   '   s    r   chromez;C:/Program Files (x86)/Google/Chrome/Application/chrome.exez5C:/Program Files/Google/Chrome/Application/chrome.exeLOCALAPPDATA z%/Google/Chrome/Application/chrome.exez</Applications/Google Chrome.app/Contents/MacOS/Google Chromezgoogle-chromereturnc                   C   s*   t jdr	tjS t jdrtjS tjS )Nwindarwin)sysplatform
startswithr   r   r   r   r   r   r   r   windows_mac_or_linux<   s
   r   c                   @   s   e Zd ZedZdS )URLsZCreateBrowserBotsSessionN)r   r   r   r   create_browser_botsr   r   r   r   r   E   s    r   s   closed_by_browser_launcheri  c                       s.   e Zd Z fddZdd ZdddZ  ZS )	OtreeWebSocketClientc                   s*   || _ t | _d| _t j|i | d S )Nr   )session_sizesetseen_participant_codesparticipants_finishedsuper__init__)selfr"   argskwargs	__class__r   r   r'   N   s   zOtreeWebSocketClient.__init__c                 C   sX   t |d }|| jvr(| j| |  jd7  _| j| jkr*| jttd dS dS dS )zQ
        This is called automatically when the client receives a message
        Zparticipant_code   )reasoncodeN)	jsonloadsr$   addr%   r"   closeWEBSOCKET_COMPLETED_MESSAGEWEBSOCKET_1000)r(   messager/   r   r   r   received_messageT   s   
z%OtreeWebSocketClient.received_messageNc                 C   s2   |t krtd| d| d td dS dS )zl
        make sure the websocket closed properly,
        not because of server-side exception etc.
        z#Lost connection with server. code: z, reason: "z)".Check the oTree server logs for errors.N)r5   loggererrorr   exit)r(   r/   r.   r   r   r   closed_   s   zOtreeWebSocketClient.closedN)r   r   r   r'   r7   r<   __classcell__r   r   r+   r   r!   M   s    r!   c                 C   s6   t   }t| |d}|  |  tt   | dS )zfor easy patching)r"   r-   )timer!   connectZrun_foreverround)websocket_urlr"   Zbot_start_timeZ	ws_clientr   r   r   #run_websocket_client_until_finishedq   s
   rC   c                   @   sd   e Zd Zdd Zdd Zdd Zdefdd	Zd
d ZdddZ	dd Z
dd Zdd Zdd ZdS )Launcherc                C   s   || _ || _|| _d S r=   )session_config_name
server_urlnum_participants)r(   rE   rF   rG   r   r   r   r'   {   s   
zLauncher.__init__c                 C   s   |    |   t | _| jjdti g }| j}|r-|tvr)d	|}t
||g}nt }tdd |D | _|D ]!}t| }| }t|D ]}| jpS|d }||||d qKq=d}	|D ]}
|	| jd
i |
7 }	qctjd	t|	d	 d S )Nzotree-rest-keyzNo session config named "{}"c                 s   s    | ]}t |V  qd S r=   )len).0Zconfig_namer   r   r   	<genexpr>   s    
zLauncher.run.<locals>.<genexpr>Znum_demo_participantsrE   rG   case_numberr   zTotal: {} seconds
r-   r   )check_browserset_urlsrequests_sessionclientheadersupdateREST_KEYrE   r   format
ValueErrorkeysmaxmax_name_lengthZget_num_bot_casesrangerG   appendrun_sessionr   stdoutwriterA   )r(   Zsessions_to_createrE   msgZsession_config_namesZsession_configZnum_bot_casesrL   rG   Ztotal_time_spentZsession_to_creater   r   r   run   s@   

zLauncher.runc           	      C   sv   |    t }| ||}d| jd  }tj||| | j|||d}| 	||}tjd| |
  |S )Nz{:<%d} {:>2} participants...r-   rK   z...finished in {} seconds
)close_existing_sessionr	   launch_browserrX   r   r\   r]   rT   create_bb_sessionwebsocket_listen	terminate)	r(   rE   rG   rL   secret_codeZbrowser_processZrow_fmtsession_codeZ
time_spentr   r   r   r[      s   zLauncher.run_sessionr   c                 C   s2   t | jt|}|dddd}t||dS )Nhttp://zws://zhttps://zwss://)rB   r"   )r   rF   channel_utilsZbrowser_bots_launcher_pathreplacerC   )r(   rf   rG   rB   r   r   r   rc      s   zLauncher.websocket_listenc                 C   s"   | j }|dsd| }|| _ d S )Nhttprg   )rF   r   )r(   rF   r   r   r   rN      s   

zLauncher.set_urlsNc                 C   s    |pi }| j jt| j||dS )Nr0   )rP   postr   rF   )r(   urlr0   r   r   r   rl      s   zLauncher.postc                 K   s(   | j tj|d}|jsJ d|j}|S )Nrk   z0Failed to create session. Check the server logs.)rl   r   r    oktext)r(   payloadresprf   r   r   r   rb      s   zLauncher.create_bb_sessionc                 C   s   t  }ttdd }|r|g| _nt| d | _| jd  }d|v r%d}n	d|v r,d}nd S |tjkr7dg}ndd	g}t|	t
jjd
}| | v }|r[t
jdj|d d S d S )NZBROWSER_COMMANDr   r   ZChromeZfirefoxZFirefoxZtasklistZpsZaxwignorezlWARNING: it looks like {browser} is already running. You should quit {browser} before running this command.
)Zbrowser)r   getattrr   browser_cmdsBROWSER_CMDSlowerr   r   r   decoder   r\   encodingr]   rT   )r(   r   Zcustom_browser_cmdZfirst_browser_typeZbrowser_typeZprocess_list_argsZ	ps_outputZ
is_runningr   r   r   rM      s2   

zLauncher.check_browserc                 C   s2   |  td}|jsdt||j}t|d S )NZCloseBrowserBotsSessionzFRequest to close existing browser bots session failed. Response: {} {})rl   r   rn   rT   reprro   AssertionError)r(   rq   r^   r   r   r   r`     s   zLauncher.close_existing_sessionc              	   C   s   t | jtd}| jD ]6}|g}tjdr%|d |d |d t|D ]}|| q)zt	|W   S  t
yA   Y qw dd| j}t
|)NZBrowserBotStartLinkZBROWSER_BOTS_USE_HEADLESSz
--headlessz--disable-gpuz--remote-debugging-port=9222zCould not find a browser at the following path(s):

{}

Note: in settings.py, you can set BROWSER_COMMAND to the path to your browser executable. Otherwise, oTree will try to launch Chrome from its usual path.
)r   rF   r   rt   osenvirongetrZ   rY   r   FileNotFoundErrorrT   join)r(   rG   re   Zwait_room_urlZbrowser_cmdr)   ir^   r   r   r   ra     s$   




zLauncher.launch_browserr=   )r   r   r   r'   r_   r[   floatrc   rN   rl   rb   rM   r`   ra   r   r   r   r   rD   z   s    6
	#
rD   )2loggingr0   r|   r   r?   enumr   
subprocessr   r   urllib.parser   Zotreer   Z
otree.asgir   Zotree.channels.utilsZchannelsutilsrh   Zotree.sessionr   Zotree.commonr	   ZAUTH_FAILURE_MESSAGEgetenvrS   	getLoggerr   r9   requestsr
   rO   Zws4py.client.threadedclientr   ModuleNotFoundErrorr;   r   r   r   r   ru   r   r   r4   r5   r!   r   rC   rD   r   r   r   r   <module>   sX    

	$	