o
    ø�1ji0  ã                   @   sú   d Z ddlZddlZddlZddlZ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mZmZ ddlmZ ddlmZ ddlmZ ejejdd� e e¡Zd	Zd
ZdZdZdZdZdZdZdd„ Z dd„ Z!G dd„ dƒZ"dd„ Z#edkr{e#ƒ  dS dS )zµ
Plucker - Standalone Miner Diagnostic Tool

Listens for UDP broadcasts from the Whatsminer IP Found button,
collects diagnostics, and displays a formatted report (M60-only fleet).
é    N)ÚscrolledtextÚ
filedialogÚ
messagebox)Údatetime)Úcollect_whatsminer)Úformat_reportz'%(asctime)s [%(levelname)s] %(message)s)ÚlevelÚformati¸"  z#1e1e1ez#2d2d2dz#d4d4d4z#569cd6z#6a9955z#d7ba7dz#f44747c                  C   s2   zdd l } | jj d¡ W d S  ty   Y d S w )Nr   é   )ÚctypesÚwindllÚshcoreÚSetProcessDpiAwarenessÚ	Exception)r   © r   ú)/var/www/html/ngon/plucker/app/plucker.pyÚ_set_dpi_awareness.   s   ÿr   c                    s  | sdS | j ddd�}t d|¡}|r| d¡ ¡  dd¡S t d	|¡}|r1| d
¡ ¡  dd¡S t d|¡}|rP| d¡ ¡ ‰ d ‡ fdd„td
ddƒD ƒ¡S t| ƒdkrtt| ƒd ƒD ] }| ||d … }|dkr~|dkr~d dd„ |D ƒ¡}|  S q^dS )zDTry multiple strategies to extract a MAC address from a UDP payload.Nzutf-8Úignore)Úerrorsz/MAC:\s*(([0-9a-fA-F]{2}[:\-]){5}[0-9a-fA-F]{2})r
   ú-ú:z&([0-9a-fA-F]{2}[:\-]){5}[0-9a-fA-F]{2}r   z0(?<![0-9a-fA-F])([0-9a-fA-F]{12})(?![0-9a-fA-F])c                 3   s    � | ]}ˆ ||d  … V  qdS )é   Nr   )Ú.0Úi©Úrawr   r   Ú	<genexpr>P   s   € z*_parse_mac_from_payload.<locals>.<genexpr>é   r   é   é   s         s   ÿÿÿÿÿÿc                 s   s   � | ]}|d ›V  qdS )Ú02XNr   )r   Úbr   r   r   r   X   s   € )	ÚdecodeÚreÚsearchÚgroupÚupperÚreplaceÚjoinÚrangeÚlen)ÚpayloadÚtextÚmÚoffsetÚ	candidateÚmacr   r   r   Ú_parse_mac_from_payload9   s*    €r1   c                   @   sz   e Zd Zdd„ Zdd„ Zdd„ Zdd„ Zefd	d
„Z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dS )Ú
PluckerAppc                 C   sT   || _ | j  d¡ | j jtd� | j  dd¡ | j  d¡ d | _|  ¡  |  ¡  d S )NzPLUCKER - Miner Diagnostic Tool©Úbgi¼  i&  Ú800x650)	ÚrootÚtitleÚ	configureÚBG_DARKÚminsizeÚgeometryÚ_scan_threadÚ
_build_guiÚ_start_listener)Úselfr6   r   r   r   Ú__init__b   s   zPluckerApp.__init__c                 C   s2  t j| jtd�}|jt jddd� t j|ddttd�jt jd� t j|d	d
tt	d�| _
| j
jt jd� t j| jtt jdd�}|jt jddd� t j|ddttt jd�| _| jjt jddd� t j|ddttt jd�| _| jjt jddd� t j|ddttt jd�| _| jjt jddd� tj| jt jdttttt jdt jd�
| _| jjt jdddd� t j| jtd�}|jt jddd� tdtttdt jdddd�	}t j|fd| jd œ|¤Žjt jd!d"� t j|fd#| jd œ|¤Žjt jd!d"� t j|fd$| jd œ|¤Žjt jd� t j| jd%d&td'd�| _| jjt jd(d)� d S )*Nr3   é
   )rA   r   )ÚfillÚpadxÚpadyÚPLUCKER)ÚConsolasé   Úbold)r,   Úfontr4   Úfg)ÚsideúListening...)rF   é   r
   )r4   ÚreliefÚbd)é   r   zIP: --)rF   rA   )r,   rI   r4   rJ   Úanchoré   )rK   rC   rD   zMAC: --zFirmware: --r   )	ÚwraprI   r4   rJ   ÚinsertbackgroundÚselectbackgroundrN   rO   ÚstateTrP   )rB   ÚexpandrC   rD   )r   rA   Úwhiter   Úhand2)	rI   r4   rJ   ÚactivebackgroundÚactiveforegroundrN   rC   rD   ÚcursorzCopy to Clipboard)r,   Úcommand)r   r   )rK   rC   zSave to FileÚClearzJHint: If no miners are detected, check your firewall allows UDP port 8888.)rF   rP   z#666666)r   rR   )rK   rD   ) ÚtkÚFramer6   r9   ÚpackÚXÚLabelÚ	FG_ACCENTÚLEFTÚFG_STATUS_OKÚstatus_labelÚRIGHTÚ	BG_WIDGETÚFLATÚFG_TEXTÚWÚlbl_ipÚlbl_macÚlbl_fwr   ÚScrolledTextÚWORDÚDISABLEDÚreport_textÚBOTHÚdictÚButtonÚ_copy_reportÚ_save_reportÚ_clear_reportÚ
hint_labelÚBOTTOM)r?   Útitle_frameÚ
info_frameÚ	btn_frameÚ	btn_styler   r   r   r=   q   sX   þýþ
ü
ý&&$ýzPluckerApp._build_guic                 C   sP   | j jtjd� | j  dtj¡ | j  tj|¡ | j jtjd� | j  d¡ d S )N©rV   ú1.0)	rs   Úconfigr_   ÚNORMALÚdeleteÚENDÚinsertrr   Úsee©r?   r,   r   r   r   Ú_set_report¯   s
   zPluckerApp._set_reportc                 C   s4   | j jtjd� | j  tj|¡ | j jtjd� d S )Nr€   )rs   r‚   r_   rƒ   r†   r…   rr   rˆ   r   r   r   Ú_append_report¶   s   zPluckerApp._append_reportc                 C   s   | j j||d� d S )N)r,   rJ   )rg   r‚   )r?   r,   Úcolorr   r   r   Ú_set_status»   s   zPluckerApp._set_statusNc                 C   s\   |d ur| j jd|› �d� |d ur| jjd|› �d� |d ur,| jjd|› �d� d S d S )NzIP: )r,   zMAC: z
Firmware: )rm   r‚   rn   ro   )r?   Úipr0   Úfwr   r   r   Ú	_set_info¾   s   ÿzPluckerApp._set_infoc                 C   sb   | j jtjd� | j  dtj¡ ¡ }| j jtjd� |r/| j 	¡  | j 
|¡ |  dt¡ d S d S )Nr€   r�   zCopied to clipboard)rs   r‚   r_   rƒ   Úgetr…   Ústriprr   r6   Úclipboard_clearÚclipboard_appendrŒ   rf   )r?   Úcontentr   r   r   rw   È   s   
ýzPluckerApp._copy_reportc                 C   sô   | j jtjd� | j  dtj¡ ¡ }| j jtjd� |sd S tj	 
tj	 d¡d¡}tj	 |¡r1|ntj	 d¡}dt ¡  d¡› d�}tj||ddd	gd
�}|rxt|dƒ�}| |¡ W d   ƒ n1 sdw   Y  |  dtj	 |¡› �t¡ d S d S )Nr€   r�   ú~ÚDesktopÚplucker_report_z%Y%m%d_%H%M%Sz.txt)z
Text filesz*.txt)z	All filesz*.*)Ú
initialdirÚinitialfileÚdefaultextensionÚ	filetypesÚwzSaved: )rs   r‚   r_   rƒ   r�   r…   r‘   rr   ÚosÚpathr(   Ú
expanduserÚisdirr   ÚnowÚstrftimer   ÚasksaveasfilenameÚopenÚwriterŒ   Úbasenamerf   )r?   r”   ÚdesktopÚinitial_dirÚdefault_nameÚfilepathÚfr   r   r   rx   Ñ   s(   üÿýzPluckerApp._save_reportc                 C   s(   |   d¡ |  ddd¡ |  dt¡ d S )NÚ z--rL   )r‰   r�   rŒ   rf   ©r?   r   r   r   ry   æ   s   
zPluckerApp._clear_reportc                 C   s   t j| jdd�}| ¡  d S )NT)ÚtargetÚdaemon)Ú	threadingÚThreadÚ_udp_listener_loopÚstart)r?   Úthreadr   r   r   r>   í   s   zPluckerApp._start_listenerc                    sö  g }t g}|D ]t}zGt tjtj¡}| tjtjd¡ z| tjtjd¡ W n	 ty/   Y nw | tjtj	d¡ | 
d|f¡ | ||f¡ t d|› �¡ W q ty{ } zt d|› d|› �¡ ˆ j d||f‡ fdd„	¡ W Y d }~qd }~ww |s‹ˆ j d‡ fd	d„¡ d S t d
t|ƒ› d�¡ 	 zHt dd„ |D ƒg g d¡\}}}|D ]3}| d¡\}	}
|
d }| ¡ d }t d|› d|› dt|	ƒ› d�¡ t|	ƒ}ˆ j dˆ j|||¡ qªW n tyù } zt d|› �¡ W Y d }~nd }~ww q—)Nr
   r¬   zListening on UDP port zCannot bind UDP port z: r   c                    s   ˆ   d|› d�t¡S )NzPort z( bind failed - another instance running?©rŒ   ÚFG_STATUS_ERR)ÚeÚpr­   r   r   Ú<lambda>  s    ÿz/PluckerApp._udp_listener_loop.<locals>.<lambda>c                      s   ˆ   dt¡S )NzFailed to bind any UDP portrµ   r   r­   r   r   r¹     s    ÿzUDP listener active on z port(s)Tc                 S   s   g | ]\}}|‘qS r   r   )r   ÚsÚ_r   r   r   Ú
<listcomp>  s    z1PluckerApp._udp_listener_loop.<locals>.<listcomp>g      ð?i   zUDP packet from z	 on port z (z bytes)zUDP listener error: )ÚPORT_WHATSMINERÚsocketÚAF_INETÚ
SOCK_DGRAMÚ
setsockoptÚ
SOL_SOCKETÚSO_REUSEADDRÚSO_REUSEPORTÚAttributeErrorÚSO_BROADCASTÚbindÚappendÚloggerÚinfoÚOSErrorÚerrorr6   Úafterr*   ÚselectÚrecvfromÚgetsocknamer1   Ú_on_miner_detectedr   )r?   ÚsocksÚportsÚportrº   r·   Úreadabler»   ÚsockÚdataÚaddrr�   r0   r   r­   r   r²   ñ   sP   ÿ(€þ "ú€ÿözPluckerApp._udp_listener_loopc                 C   sb   |pd}| j ||dd� |  dt¡ |  d|› d|› d�¡ tj| j||fdd�| _| j ¡  d S )	Nzdetecting...)r�   r0   rŽ   zDetected - scanning...zMiner detected at z (port z)
Scanning...
T)r®   Úargsr¯   )	r�   rŒ   ÚFG_STATUS_WARNr‰   r°   r±   Ú	_run_scanr<   r³   )r?   r�   r0   rÔ   Úmac_strr   r   r   rÑ     s   ÿzPluckerApp._on_miner_detectedc                 C   s  zO| j  d| jd d d¡ | j  d| jd¡ t|ƒ}|r$| d¡s$||d< | d¡r6| j  d| jd |d d ¡ t|ƒ}| j  d| j|¡ | j  d| jdt	¡ W d S  t
yƒ } z(t d|› �¡ | j  d| jd|› d|› �¡ | j  d| jdt¡ W Y d }~d S d }~ww )	Nr   Ú
whatsminerzCollecting data...
r0   zReport readyzScan failed for z:
ÚError)r6   rÍ   r�   rŠ   r   r�   r   r‰   rŒ   rf   r   rÉ   Ú	exceptionr¶   )r?   r�   r0   r×   Úreportr·   r   r   r   rÛ   *  s"   
"€ýzPluckerApp._run_scan)NNN)Ú__name__Ú
__module__Ú__qualname__r@   r=   r‰   rŠ   rf   rŒ   r�   rw   rx   ry   r>   r²   rÑ   rÛ   r   r   r   r   r2   a   s    >

	-r2   c                  C   s"   t ƒ  t ¡ } t| ƒ}|  ¡  d S )N)r   r_   ÚTkr2   Úmainloop)r6   Úappr   r   r   ÚmainG  s   rç   Ú__main__)$Ú__doc__r�   Úsysr#   r¾   ÚstructrÎ   r°   ÚloggingÚtkinterr_   r   r   r   r   Ú
miner_apisr   Úreport_builderr   ÚbasicConfigÚINFOÚ	getLoggerrá   rÉ   r½   r9   ri   rk   rd   rf   rÚ   r¶   r   r1   r2   rç   r   r   r   r   Ú<module>   sF   þ
( g
ÿ