
    KhI                        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m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 ddlZ ej.                  ej0                          ej2                  e      Z ee      Zd	ej:                  d
<   dej:                  d<    eej<                  dddd      e_         ee        G d d      Z e       Z ejC                  ddg      d        Z"ejC                  d      d        Z#ejC                  d      d        Z$ejC                  d      d        Z%ejC                  d      d        Z&ejC                  ddg      d        Z'ejC                  d dg      d!        Z(ejC                  d"dg      d#        Z)ejC                  d$dg      d%        Z*ejC                  d&dg      d'        Z+ejC                  d(dg      d)        Z,ejC                  d*dg      d+        Z-d, Z.ejC                  d-dg      d.        Z/ejC                  d-dg      d/        Z0ejC                  d0dg      d1        Z1ejC                  d0dg      d2        Z2ejC                  d3dg      d4        Z3ejC                  d5dg      d6        Z4ejC                  d7dg      d8        Z5ejC                  d9dg      d:        Z6ejC                  d;dg      d<        Z7ejC                  d=dg      d>        Z8ejC                  d?dg      d@        Z9ejC                  dAdg      dB        Z:ejC                  dCdg      dD        Z;edEk(  rr ejx                  e.dFG      Z=e=j}                           e?dH        e?dI        e?dJ        e?dK        e?dL        e?dM        e?dN       ej                  dOdPd	dFQ       yy)RuB   
Asset Management Server
자산관리 서버 - RESTful API 기반
    N)Flaskrequestjsonifyrender_template_stringsend_from_directory)CORS)ProxyFix)RLock)Queue)levelFJSON_AS_ASCIIi   MAX_CONTENT_LENGTH   )x_forx_protox_hostx_prefixc                       e Zd Zd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dZddZd Zy)AssetDatabasec                    dd l }dd l}|j                  j                  |j                  j	                  t
                    }|j                  j                  ||      | _        t        d| j                          t               | _
        t        d      | _        d| _        t        d      | _        d| _        d| _        | j#                          | j%                          | j'                          y )Nr   zDatabase path:    )maxsizeFi  z5C:\Users\Administrator\Desktop\item\instance\icons.db)ostempfilepathdirnameabspath__file__joindb_pathprintr
   _lockr   _connection_pool_pool_initializedupdate_queuebatch_processor_runningicon_db_pathinit_database_init_connection_pool_start_batch_processor)selfr    r   r   current_dirs        2/mnt/c/Users/Administrator/Desktop/help_/server.py__init__zAssetDatabase.__init__#   s     ggoobggooh&?@ww||K9~./ W
 %c 2!& "$/',$ U""$##%    c                 N   	 t         j                  d|        t         j                  d| j                          t        j                  j                  | j                        s#t         j                  d| j                          yt         j                  d       t        j                  | j                        }|j                         }|j                  d       |j                         }t         j                  d|        	 |j                  d       |j                         }t         j                  d	|        	 |j                  d       |j                         }t         j                  d|        t         j                  d| d       |j                  d|f       |j                         }t         j                  d|        |j                          |r t         j                  d|d           |d   S t         j                  d| d       y# t        $ r#}t         j                  d
|        Y d}~d}~ww xY w# t        $ r"}t         j                  d|        Y d}~d}~ww xY w# t        $ r%}t         j                  d| d|        Y d}~yd}~ww xY w)u0   icons.db에서 hostname으로 RUST 정보 조회u+   🔍 RUST 정보 조회 시작 - hostname: u   📁 icons.db 경로: u   ❌ Icon database not found: Nu$   ✅ icons.db 파일 존재 확인됨z2SELECT name FROM sqlite_master WHERE type='table';u!   📋 사용 가능한 테이블: zPRAGMA table_info(icon);u   🏷️ icon 테이블 컬럼: u)   ❌ icon 테이블 정보 조회 실패: z1SELECT comp_no, remote_address FROM icon LIMIT 5;u&   📊 icon 테이블 샘플 데이터: u$   ❌ 샘플 데이터 조회 실패: u-   🔎 검색 쿼리 실행 - WHERE comp_no = ''zq
                SELECT remote_address 
                FROM icon 
                WHERE comp_no = ?
            u   🎯 쿼리 결과: u   ✅ RUST 정보 찾음: r   u   ❌ hostname 'u   '에 대한 RUST 정보 없음u)   ❌ Error querying icons.db for hostname : )loggerinfor'   r   r   existswarningsqlite3connectcursorexecutefetchall	Exceptionerrorfetchoneclose)	r+   hostnameconnr9   tablescolumnsesample_dataresults	            r-   get_rust_infozAssetDatabase.get_rust_info>   sJ   8	KKEhZPQKK01B1B0CDE77>>$"3"34!>t?P?P>QRSKK>@??4#4#45D[[]F NNOP__&FKK;F8DEN9: //+=gYGH
IRS$oo/D[MRS
 KKGzQRSTNN  	 __&FKK.vh78JJL6vaykBCay z9WXY;  NHLMMN  ICA3GHHI.  	LLDXJbQRPSTU	st   BI6 A=I6 9H  9I 9BI6 ?I6 	I"I :I6  II6 	I3I.)I6 .I33I6 6	J$?JJ$c                    t        j                  | j                        }|j                         }|j	                  d       |j	                  d       |j	                  d       |j	                  d       |j	                  d       |j	                  d       |j	                  d       |j                          |j                          t        j                  d       | j                          | j                          y	)
u   데이터베이스 초기화aw  
        CREATE TABLE IF NOT EXISTS assets (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            hostname TEXT UNIQUE NOT NULL,
            ip_address TEXT,
            mac_address TEXT,
            last_seen TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            status TEXT DEFAULT 'active',
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        )
        a  
        CREATE TABLE IF NOT EXISTS hardware_info (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            asset_id INTEGER,
            cpu_info TEXT,
            ram_total INTEGER,
            ram_used INTEGER,
            ram_percent REAL,
            disk_total INTEGER,
            disk_used INTEGER,
            disk_percent REAL,
            gpu_info TEXT,
            motherboard TEXT,
            updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            FOREIGN KEY (asset_id) REFERENCES assets (id)
        )
        a  
        CREATE TABLE IF NOT EXISTS network_info (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            asset_id INTEGER,
            interface_name TEXT,
            ip_address TEXT,
            mac_address TEXT,
            subnet_mask TEXT,
            gateway TEXT,
            dns_servers TEXT,
            network_speed TEXT,
            is_connected BOOLEAN,
            updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            FOREIGN KEY (asset_id) REFERENCES assets (id)
        )
        uj  
        CREATE TABLE IF NOT EXISTS software_info (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            asset_id INTEGER,
            software_list TEXT,  -- JSON 형태로 저장
            software_count INTEGER,
            updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            FOREIGN KEY (asset_id) REFERENCES assets (id)
        )
        ax  
        CREATE TABLE IF NOT EXISTS com_ports (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            asset_id INTEGER,
            port_name TEXT,
            description TEXT,
            hwid TEXT,
            is_active BOOLEAN,
            updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            FOREIGN KEY (asset_id) REFERENCES assets (id)
        )
        a  
        CREATE TABLE IF NOT EXISTS admin_settings (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            setting_key TEXT UNIQUE NOT NULL,
            setting_value TEXT NOT NULL,
            updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        )
        a  
        CREATE TABLE IF NOT EXISTS software_management_requests (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            hostname TEXT NOT NULL,
            software_name TEXT NOT NULL,
            action_type TEXT NOT NULL,
            requested_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            status TEXT DEFAULT 'pending',
            completed_at TIMESTAMP,
            FOREIGN KEY (hostname) REFERENCES assets (hostname)
        )
        z!Database initialized successfullyN)r7   r8   r    r9   r:   commitr?   r3   r4   _create_indexes_create_agent_logs_tabler+   rA   r9   s      r-   r(   zAssetDatabase.init_databasez   s    t||, 	 
 
	 	  	& 	  	$ 	 	 		 	  	 	  	 	  	 	

78 	 	%%'r/   c                 L   t        j                  | j                        }|j                         }g d}|D ]  }	 |j	                  |        |j                          |j                          y# t         j
                  $ r"}t        j                  d|        Y d}~hd}~ww xY w)u+   성능 최적화를 위한 인덱스 생성)zBCREATE INDEX IF NOT EXISTS idx_assets_hostname ON assets(hostname)zDCREATE INDEX IF NOT EXISTS idx_assets_last_seen ON assets(last_seen)z>CREATE INDEX IF NOT EXISTS idx_assets_status ON assets(status)zPCREATE INDEX IF NOT EXISTS idx_software_info_asset_id ON software_info(asset_id)zPCREATE INDEX IF NOT EXISTS idx_hardware_info_asset_id ON hardware_info(asset_id)zIndex creation failed: N)
r7   r8   r    r9   r:   Errorr3   r6   rI   r?   )r+   rA   r9   indexes	index_sqlrD   s         r-   rJ   zAssetDatabase._create_indexes   s    t||,
 ! 	>I>y)	> 	

	 == >!8<==>s   A..B#BB#c                 *   t        j                  | j                        }|j                         }|j	                  d       |j	                  d       |j	                  d       |j	                  d       |j                          |j                          y)u9   에이전트 로그 테이블 생성 (PC당 50개 제한)a  
        CREATE TABLE IF NOT EXISTS agent_logs (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            hostname TEXT NOT NULL,
            log_level TEXT NOT NULL,
            log_type TEXT NOT NULL,
            message TEXT NOT NULL,
            details TEXT,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            FOREIGN KEY (hostname) REFERENCES assets (hostname)
        )
        zJCREATE INDEX IF NOT EXISTS idx_agent_logs_hostname ON agent_logs(hostname)zNCREATE INDEX IF NOT EXISTS idx_agent_logs_created_at ON agent_logs(created_at)zHCREATE INDEX IF NOT EXISTS idx_agent_logs_level ON agent_logs(log_level)N)r7   r8   r    r9   r:   rI   r?   rL   s      r-   rK   z&AssetDatabase._create_agent_logs_table  sm    t||, 	  	 	cdghab

r/   c                 x   | j                   ry| j                  5  | j                   r
	 ddd       yt        d      D ]  }	 t        j                  | j
                  d      }|j                  d       |j                  d       |j                  d       |j                  d       |j                  d	       | j                  j                  |        d| _         t        j                  d       ddd       y# t        j                  $ r"}t        j                  d
|        Y d}~d}~ww xY w# 1 sw Y   yxY w)u   연결 풀 초기화N   Fcheck_same_threadPRAGMA journal_mode=WALPRAGMA synchronous=NORMALPRAGMA cache_size=20000PRAGMA temp_store=MEMORYPRAGMA mmap_size=268435456zFailed to create connection: TzConnection pool initialized)r$   r"   ranger7   r8   r    r:   r#   putrN   r3   r=   r4   )r+   _rA   rD   s       r-   r)   z#AssetDatabase._init_connection_pool   s   !!ZZ 	7%%	7 	7
 2Y 
F	F"??4<<5QDLL!:;LL!<=LL!:;LL!;<LL!=>))--d3
F &*D"KK56%	7 	7 }} FLL#@!DEEF	7 	7s;   D0D0 BC8D08D-D(#D0(D--D00D9c                    	 | j                   j                  d      }|S #  	 t        j                  | j                  d      }|j                  d       |j                  d       |j                  d       |j                  d       |j                  d	       |cY S # t        j                  $ r}t        j                  d
|         d}~ww xY wxY w)u$   연결 풀에서 연결 가져오기r   timeoutFrT   rV   rW   rX   rY   rZ   z!Failed to create new connection: N)	r#   getr7   r8   r    r:   rN   r3   r=   )r+   rA   rD   s      r-   get_connectionzAssetDatabase.get_connection9  s    	((,,Q,7DK	
t||uM678967789:== @DEs-     CA7BCC0C		CCc                     	 | j                   j                         dk  r| j                   j                  |       y|j                          y#  	 |j                          Y y#  Y Y yxY wxY w)u   연결을 풀에 다시 반환r   N)r#   qsizer\   r?   )r+   rA   s     r-   return_connectionzAssetDatabase.return_connectionM  sY    		$$**,s2%%))$/

	

s(   8A A A)A!!A&#A)&A)c                     | j                   ryd| _         t        j                  | j                  d      }|j	                          t
        j                  d       y)u   배치 처리 스레드 시작NTtargetdaemonzBatch processor started)r&   	threadingThread_batch_processorstartr3   r4   )r+   batch_threads     r-   r*   z$AssetDatabase._start_batch_processorZ  sG    '''+$ ''t/D/DTR-.r/   c                    g }t        j                          }| j                  r	 	 | j                  j                  d      }|j	                  |       t        j                          }t        |      dk\  s
|r||z
  dk\  r|r| j                  |       g }|}| j                  ryy#  Y VxY w# t        $ r$}t        j                  d|        g }Y d}~>d}~ww xY w)u   배치 처리 워커皙?r_   2   g       @zBatch processor error: N)
timer&   r%   ra   appendlen_process_batchr<   r3   r=   )r+   batchlast_process_timeupdate_datacurrent_timerD   s         r-   rl   zAssetDatabase._batch_processord  s     IIK**"&"3"3"7"7"7"DKLL-  $yy{ J"$|.??3F++E2 ",8)% **  6qc:;s*   -B$ AB+ $B(&B+ +	C4CCc                    | j                         }	 |j                         }g }g }|D ]b  }|d   dk(  r|j                  |d   |d   |d   f       )|d   dk(  s2|j                  |d   |d   |d	   |d
   |d   |d   |d   |d   f       d |r|j                  d|       |r1|D ],  }|d   }|j	                  d|f       |j	                  d|       . |j                          t        j                  dt        |       d       | j                  |       y# t        $ r2}	t        j                  d|	        |j                          Y d}	~	Hd}	~	ww xY w# | j                  |       w xY w)u   배치 데이터 처리typeasset_status
ip_addressmac_addressr@   hardware_infoasset_idcpu_info	ram_totalram_usedram_percent
disk_total	disk_useddisk_percentz
                    UPDATE assets 
                    SET ip_address = ?, mac_address = ?, last_seen = CURRENT_TIMESTAMP, status = 'active'
                    WHERE hostname = ?
                r   ,DELETE FROM hardware_info WHERE asset_id = ?a  
                        INSERT INTO hardware_info 
                        (asset_id, cpu_info, ram_total, ram_used, ram_percent, disk_total, disk_used, disk_percent, updated_at)
                        VALUES (?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
                    zProcessed batch of z itemszBatch processing error: N)rb   r9   rs   executemanyr:   rI   r3   r4   rt   r<   r=   rollbackre   )
r+   rv   rA   r9   asset_updateshardware_updatesitemhw_datar   rD   s
             r-   ru   zAssetDatabase._process_batch  s   ""$6	)[[]F M! <>1!((\*]+Z(* 
 &\_4$++Z(Z([)Z(]+\*[)^,	- 	( "" $ #	$  / 	"G&qzHNN#QT\S^_NN $ !	"	" KKMKK-c%j\@A ""4(	  	LL3A378MMOO	 ""4(s1   AD B,D 	E!(E	E EE E)c                    | j                         }	 |j                         }|j                  d|f       |j                         }|r+|d   }|j                  d|||f       |j	                          n1|j                  d|||f       |j
                  }|j	                          | j                  |       |S # | j                  |       w xY w)u8   자산 등록 또는 업데이트 (배치 처리 적용)(SELECT id FROM assets WHERE hostname = ?r   z
                    UPDATE assets 
                    SET ip_address = ?, mac_address = ?, last_seen = CURRENT_TIMESTAMP, status = 'active'
                    WHERE id = ?
                z
                    INSERT INTO assets (hostname, ip_address, mac_address) 
                    VALUES (?, ?, ?)
                )rb   r9   r:   r>   rI   	lastrowidre   )r+   r@   r}   r~   rA   r9   rF   r   s           r-   register_assetzAssetDatabase.register_asset  s    ""$	)[[]F NNE{S__&F!!9    !+x8	:
     
K8: "++ ""4( ""4(s   BB6 6C	c                    	 | j                   j                  d||j                  dd      |j                  dd      |j                  dd      |j                  dd      |j                  d	d      |j                  d
d      |j                  dd      |j                  dd      |j                  dd      dd       y# t        $ r4}t        j                  d|        | j                  ||       Y d}~yd}~ww xY w)u7   하드웨어 정보 업데이트 (배치 처리 사용)r   r    r   r   r   r           r   r   r   gpu_infomotherboard)r{   r   r   r   r   r   r   r   r   r   r   r   r_   z!Queue full, processing directly: N)r%   r\   ra   r<   r3   r6   _update_hardware_info_direct)r+   r   hardware_datarD   s       r-   update_hardware_infoz"AssetDatabase.update_hardware_info  s    	G!!'$)--j"=*..{A>)--j!<,00D+//a@*..{A> - 1 1.# F)--j"=,00C#  "   	GNN>qcBC--hFF	Gs   B9B< <	C9*C44C9c                 2   | j                         }	 |j                         }|j                  d|f       |j                  d||j                  dd      |j                  dd      |j                  dd      |j                  dd	      |j                  d
d      |j                  dd      |j                  dd	      |j                  dd      |j                  dd      f
       |j	                          | j                  |       y# | j                  |       w xY w)u?   하드웨어 정보 직접 업데이트 (큐 실패 시 백업)r   a"  
                INSERT INTO hardware_info 
                (asset_id, cpu_info, ram_total, ram_used, ram_percent, 
                 disk_total, disk_used, disk_percent, gpu_info, motherboard, updated_at)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
            r   r   r   r   r   r   r   r   r   r   r   r   N)rb   r9   r:   ra   rI   re   )r+   r   r   rA   r9   s        r-   r   z*AssetDatabase._update_hardware_info_direct  s   ""$	)[[]F NNIH;WNN  !!*b1!!+q1!!*a0!!-5!!,2!!+q1!!.#6!!*b1!!-4$ KKM""4(D""4(s   CD Dc                 4   | j                         }|j                         }|j                  d|f       |j                  dg       D ]  }|j                  d||j                  dd      |j                  dd      |j                  dd      |j                  dd      |j                  d	d      t	        j
                  |j                  d
g             |j                  dd      |j                  dd      f	        |j                          |j                          y)u    네트워크 정보 업데이트z+DELETE FROM network_info WHERE asset_id = ?
interfacesa   
                INSERT INTO network_info 
                (asset_id, interface_name, ip_address, mac_address, subnet_mask, 
                 gateway, dns_servers, network_speed, is_connected)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
            namer   ipmacsubnetgatewaydnsspeed	connectedFN)rb   r9   r:   ra   jsondumpsrI   r?   )r+   r   network_datarA   r9   	interfaces         r-   update_network_infoz!AssetDatabase.update_network_info  s    ""$ 	DxkR &)),; 	INN  fb)dB'eR(h+i,

9==34gr*k51
	$ 	

r/   c                 4   | j                         }|j                         }|j                  d|f       |j                  dg       }|j                  d|t	        j
                  |d      t        |      f       |j                          |j                          y)u#   소프트웨어 정보 업데이트z,DELETE FROM software_info WHERE asset_id = ?software_listzv
            INSERT INTO software_info (asset_id, software_list, software_count)
            VALUES (?, ?, ?)
        Fensure_asciiN)	rb   r9   r:   ra   r   r   rt   rI   r?   )r+   r   software_datarA   r9   r   s         r-   update_software_infoz"AssetDatabase.update_software_info3  s    ""$ 	E{S%))/2>  

=uEs=GYZ	\
 	

r/   c                    | j                         }|j                         }|j                  d|f       |j                  dg       D ]Y  }|j                  d||j                  dd      |j                  dd      |j                  dd      |j                  dd	      f       [ |j	                          |j                          y
)u   COM 포트 정보 업데이트z(DELETE FROM com_ports WHERE asset_id = ?portsz
                INSERT INTO com_ports (asset_id, port_name, description, hwid, is_active)
                VALUES (?, ?, ?, ?, ?)
            portr   descriptionhwidactiveTN)rb   r9   r:   ra   rI   r?   )r+   r   com_datarA   r9   r   s         r-   update_com_portszAssetDatabase.update_com_portsD  s    ""$ 	AH;O LL"- 
	DNN  $+$4(	
	 	

r/   c                 t   | j                         }	 |j                         }|j                  d       |j                         }g }|D ]E  }|d   }|j                  d|f       |j                         }d}d}	|r|D ]  }
|
d   r|
d   nd}|j	                         }d|v sd|v sd|v sd	|v rAd
}d|v r7d|v r3|j                  d      }|j                  d      }||k  r	||dz   | }	nd}	nd}	 nNd|v sd|v sd|v s	d|v sd|v sd} n5 n3|d   }|r,|dk7  r'|dk7  r"|d   rt        fddD              rd
}d}	nd}|d   r| j                        nd}|j                  |d   |d   xs d|d   |d   |d   |d   |d    ||	|xs dd!       H || j                  |       S # | j                  |       w xY w)"u8   자산 요약 정보 반환 (네트워크 정보 포함)a  
                SELECT 
                    a.id, a.hostname, a.ip_address, a.mac_address, a.last_seen, a.status,
                    h.ram_total, h.disk_total,
                    s.software_count
                FROM assets a
                LEFT JOIN (
                    SELECT asset_id, ram_total, disk_total
                    FROM hardware_info h1
                    WHERE h1.updated_at = (
                        SELECT MAX(updated_at) 
                        FROM hardware_info h2 
                        WHERE h2.asset_id = h1.asset_id
                    )
                ) h ON a.id = h.asset_id
                LEFT JOIN (
                    SELECT asset_id, software_count
                    FROM software_info s1
                    WHERE s1.updated_at = (
                        SELECT MAX(updated_at) 
                        FROM software_info s2 
                        WHERE s2.asset_id = s1.asset_id
                    )
                ) s ON a.id = s.asset_id
                ORDER BY a.last_seen DESC
            r   z
                    SELECT interface_name, ip_address, is_connected
                    FROM network_info 
                    WHERE asset_id = ? AND is_connected = 1
                    ORDER BY interface_name
                u	   미연결r   zwi-fiwirelesswlanwifiu   무선()r   z(Wi-Fi)ethernetethz
local areau   유선u   유선 연결   z	127.0.0.1-c              3   B   K   | ]  }|j                         v   y wN)upper).0keywordr@   s     r-   	<genexpr>z3AssetDatabase.get_assets_summary.<locals>.<genexpr>  s     +{GGx~~7G,G+{s   )LAPLAPTOPNBNOTEBOOKu   (추정)N                  )r@   r}   r~   	last_seenstatusr   r   software_countconnection_typessidrust_address)
rb   r9   r:   r;   lowerfindanyrG   rs   re   )r+   rA   r9   resultsassetsrowr   network_infor   r   netinterface_nameinterface_lower
ssid_startssid_endr}   r   r@   s                    @r-   get_assets_summaryz AssetDatabase.get_assets_summary\  sV   ""$m	)[[]FNN  6 oo'GF Hq6   
 ["  &0"-  + "36q6Qr*8*>*>*@ $6*:W[aet[t"o5.6O  #n49N-;-@-@-E
+9+>+>s+C#-#8+9*Q,x+PD+4D'0!(O;u?W[gkz[z&/9_P_=_.6O!/"4 "%QJ!jK&?JRUDU#&q6 $+{Wz+{({.6O#-D /7O q6?Gt11(;T ("%a&#&q6=S!$Q!!f!$Q"%a&&)!f'6 $0$7C yHT ""4(D""4(s   C-F$ BF$ $F7Nc                 
   | j                         }	 |j                         }|j                  d|||||f       |j                  d||f       |j                          | j	                  |       y# | j	                  |       w xY w)u)   에이전트 로그 추가 (50개 제한)z
                INSERT INTO agent_logs (hostname, log_level, log_type, message, details)
                VALUES (?, ?, ?, ?, ?)
            a  
                DELETE FROM agent_logs 
                WHERE hostname = ? AND id NOT IN (
                    SELECT id FROM agent_logs 
                    WHERE hostname = ? 
                    ORDER BY created_at DESC 
                    LIMIT 50
                )
            N)rb   r9   r:   rI   re   )r+   r@   	log_levellog_typemessagedetailsrA   r9   s           r-   add_agent_logzAssetDatabase.add_agent_log  s    ""$	)[[]F NN  Ix'BD NN  H%' KKM ""4(D""4(s   AA/ /Bc           	      8   | j                         }	 |j                         }|j                  d||f       g }|j                         D ](  }|j	                  |d   |d   |d   |d   |d   d       * || j                  |       S # | j                  |       w xY w)$   특정 에이전트의 로그 조회z
                SELECT log_level, log_type, message, details, created_at
                FROM agent_logs 
                WHERE hostname = ? 
                ORDER BY created_at DESC 
                LIMIT ?
            r   r   r   r   r   )r   r{   r   r   	timestamprb   r9   r:   r;   rs   re   )r+   r@   limitrA   r9   logsr   s          r-   get_agent_logszAssetDatabase.get_agent_logs  s    ""$	)[[]FNN  E"$ D(  VF"1v"1v!$Q   ""4(D""4(s   A"B Bc                 "   | j                         }	 |j                         }|j                  d       g }|j                         D ]   }|j	                  |d   |d   |d   d       " || j                  |       S # | j                  |       w xY w)u8   로그가 있는 모든 에이전트 호스트명 조회z
                SELECT DISTINCT hostname, COUNT(*) as log_count,
                       MAX(created_at) as last_log_time
                FROM agent_logs 
                GROUP BY hostname 
                ORDER BY last_log_time DESC
            r   r   r   )r@   	log_countlast_log_timer   )r+   rA   r9   agentsr   s        r-   !get_all_agent_hostnames_with_logsz/AssetDatabase.get_all_agent_hostnames_with_logs  s    ""$	)[[]FNN   F(  #A!$Q%(V   ""4(D""4(s   AA; ;B)zasset_management.dbr   )rq   )__name__
__module____qualname__r.   rG   r(   rJ   rK   r)   rb   re   r*   rl   ru   r   r   r   r   r   r   r   r   r   r    r/   r-   r   r   "   ss    &6:xr(h.672(/:9)v"HG,)><"0p)d)8):)r/   r   /GET)methodsc                  v    t        dddt        j                  j                         j                         d      S )u   서버 상태 확인runningzAsset Management Server1.0.0)r   serviceversionr   )r   datetimenow	isoformatr   r/   r-   indexr  %  s:     ,&&**,668	  r/   z
/dashboardc                     	 t         j                  j                  t         j                  j                  t                    } t         j                  j                  | dd      }t        d|        t        dt         j                  j                  |              t         j                  j                  |      rFt        |dd      5 }|j                         }t        dt        |              |d	d
difcddd       S t        dd| i      dfS # 1 sw Y   yxY w# t        $ r<}t        dt        |              t        ddt        |       i      dfcY d}~S d}~ww xY w)u    메인 대시보드 웹페이지staticzdashboard.htmlzLooking for dashboard at: zFile exists: rutf-8encodingzDashboard content length:    Content-Typetext/html; charset=utf-8Nr=   zDashboard not found at   zDashboard error:   )r   r   r   r   r   r   r!   r5   openreadrt   r   r<   strr,   dashboard_pathfcontentrD   s        r-   	dashboardr  /  sA   Eggoobggooh&?@k8=MN*>*:;<bggnn^<=>?77>>.)ncG< R&&(23w<.ABn6P%QQR R
 G'>~>N%OPQSVVVR R  E!#a&*+#4SVH!=>?DDEsB   CD 	.D7	D D DD D 	E$(1EE$E$z/software-dashboardc                      	 t         j                  j                  t         j                  j                  t                    } t         j                  j                  | dd      }t         j                  j                  |      r/t        |dd      5 }|j                         }|dddifcd	d	d	       S t        d
d| i      dfS # 1 sw Y   y	xY w# t        $ r%}t        d
dt        |       i      dfcY d	}~S d	}~ww xY w)u0   소프트웨어 관리 대시보드 웹페이지r	  zsoftware_dashboard.htmlr
  r  r  r  r  r  Nr=   z Software dashboard not found at r  zSoftware dashboard error: r  r   r   r   r   r   r   r5   r  r  r   r<   r  r  s        r-   software_dashboardr  F  s    Nggoobggooh&?@k8=VW77>>.)ncG< R&&(n6P%QQR R G'GGW%XYZ\___	R R  N#=c!fX!FGH#MMNB   BC C'	C 1C CC C 	C=C82C=8C=z/logs-dashboardc                      	 t         j                  j                  t         j                  j                  t                    } t         j                  j                  | dd      }t         j                  j                  |      r/t        |dd      5 }|j                         }|dddifcd	d	d	       S t        d
d| i      dfS # 1 sw Y   y	xY w# t        $ r%}t        d
dt        |       i      dfcY d	}~S d	}~ww xY w)u    로깅 대시보드 웹페이지r	  zlogs_dashboard.htmlr
  r  r  r  r  r  Nr=   zLogs dashboard not found at r  zLogs dashboard error: r  r  r  s        r-   logs_dashboardr   W  s    Jggoobggooh&?@k8=RS77>>.)ncG< R&&(n6P%QQR R G'CNCS%TUVX[[[	R R  J#9#a&!BCDcIIJr  z/static/<path:filename>c                     t         j                  j                  t         j                  j                  t              d      }t        ||       S )u   정적 파일 서빙r	  )r   r   r   r   r   r   )filename
static_dirs     r-   static_filesr$  h  s2     bggooh7BJz844r/   z/api/asset/registerPOSTc                     	 t        j                         } g d}|D ]  }|| vst        dd| i      dfc S  t        j	                  | d   | d   | d         }t
        j                  d| d    d	| d
       t        d|dd      S # t        $ r:}t
        j                  d|        t        dt        |      i      dfcY d}~S d}~ww xY w)u   자산 등록)r@   r}   r~   r=   Missing required field:   r@   r}   r~   zAsset registered:  (ID: r   TzAsset registered successfullysuccessr   r   zAsset registration error: r  N)
r   get_jsonr   dbr   r3   r4   r<   r=   r  )datarequired_fieldsfieldr   rD   s        r-   r   r   n  s    /! D$ 	SED +CE7)KLMsRR	S
 $$
 	(j)9(:&
!LM 6
  	  /1!56Q()3../s(   !B B AB 	C
/C?C
C
z/api/asset/updatec                     	 t        j                         } d| vrt        ddi      dfS t        j	                  | d   | j                  dd      | j                  dd            }d| v rt        j                  || d          d	| v rt        j                  || d	          d
| v rt        j                  || d
          d| v rt        j                  || d          t        j                  d| d    d| d       t        d|dd      S # t        $ r:}t        j                  d|        t        dt        |      i      dfcY d}~S d}~ww xY w)u   자산 정보 업데이트r@   r=   Missing hostnamer(  r}   r   r~   r   r   software_info	com_portszAsset updated: r)  r   TzAsset updated successfullyr*  zAsset update error: r  N)r   r,  r   r-  r   ra   r   r   r   r   r3   r4   r<   r=   r  )r.  r   rD   s      r-   update_assetr5    s\   %/! T!G%7893>> $$HH\2&HH]B'
 d"##Hd?.CDT!""8T.-ABd"##Hd?.CD$${*;<od:&6%7vhZqIJ 3
  	  /+A3/0Q()3../s#   &D CD 	E/E=EEz/api/asset/batch-updatec            	      >   	 t        j                         } | j                  dg       }|st        ddi      dfS t	        |      dkD  rt        ddi      dfS d}g }|D ]  }	 |j                  d      }|s|j                  d	d
d       ,t        j                  ||j                  dd      |j                  dd            }d|v rt        j                  ||d          |dz  } t        j                  d| dt	        |       d       t        d|t	        |      |d| dd      S # t        $ r'}|j                  t        |      d       Y d}~d}~ww xY w# t        $ r:}t        j                  d|        t        dt        |      i      dfcY d}~S d}~ww xY w)u4   다중 자산 배치 업데이트 (성능 최적화)r   r=   zNo assets data providedr(  rq   zBatch size too large (max 50)r   r@   unknownr2  )r@   r=   r}   r   r~   r   r   NzBatch update completed: r   z assetsTz assets processed)r+  	processedtotalerrorsr   zBatch update error: r  )r   r,  ra   r   rt   rs   r-  r   r   r<   r  r3   r4   r=   )r.  assets_dataprocessed_countr:  
asset_datar@   r   rD   s           r-   batch_update_assetsr>    s   1/!hhx,G%>?@#EE {b G%DEFKK% 	GJG%>>*5MMyCU"VW ,,NN<4NN="5 #j0++Hj6QR1$%	G. 	..?q[AQ@RRYZ[(%1/1BBST
  	  G8c!fEFFG  /+A3/0Q()3../s`   6E E 	E  'D&E AD&!AE &	E/EE EE 	F"/FFFz/api/asset/heartbeatc                  `   	 t        j                         } | j                  d      }|st        ddi      dfS t	        j
                  dd      }t        j                  |       t        j                  || j                  dd      | j                  d	d            }t	        j                  d
d      }t        d||t        j                  j                         j                         d      S # t        $ r:}t        j!                  d|        t        dt#        |      i      dfcY d}~S d}~ww xY w)u6   경량 하트비트 (최소한의 상태 업데이트)r@   r=   r2  r(  rp   g      ?r}   r   r~   i,  ih  T)r+  r   next_heartbeatserver_timezHeartbeat error: r  N)r   r,  ra   r   randomuniformrr   sleepr-  r   randintr  r  r  r<   r3   r=   r  )r.  r@   delayr   r@  rD   s         r-   asset_heartbeatrG    s   /!88J'G%7893>> sC(

5 $$HH\2&HH]B'
  S1 ,#,,002<<>	
  	  /(,-Q()3../s#   5C* B1C* *	D-3/D("D-(D-z/api/assetsc                      	 t         j                         } t        dt        |       | d      S # t        $ r:}t
        j                  d|        t        dt        |      i      dfcY d}~S d}~ww xY w)u   자산 목록 조회T)r+  countr   zGet assets error: r=   r  N)r-  r   r   rt   r<   r3   r=   r  )r   rD   s     r-   
get_assetsrJ    ss    
/&&([
  	  /)!-.Q()3../   +. 	A1/A,&A1,A1z/api/asset/<hostname>c           
         	 t         j                         }|j                         }|j                  d| f       |j	                         }|st        ddi      dfS |d   }|j                  d|f       |j	                         }|j                  d|f       |j                         }|j                  d|f       |j	                         }|j                  d	|f       |j                         }|j                          t        d
|d   |d   |d   |d   |d   d|||r|d   rt        j                  |d         ng |dd      S # t        $ r:}	t        j                  d|	        t        dt        |	      i      dfcY d}	~	S d}	~	ww xY w)u"   특정 자산 상세 정보 조회z'SELECT * FROM assets WHERE hostname = ?r=   zAsset not foundr  r   zOSELECT * FROM hardware_info WHERE asset_id = ? ORDER BY updated_at DESC LIMIT 1z-SELECT * FROM network_info WHERE asset_id = ?zOSELECT * FROM software_info WHERE asset_id = ? ORDER BY updated_at DESC LIMIT 1z*SELECT * FROM com_ports WHERE asset_id = ?Tr   r   r   r   r   )r@   r}   r~   r   r   )
basic_infohardwarenetworksoftwarer4  )r+  assetzGet asset detail error: r  N)r-  rb   r9   r:   r>   r   r;   r?   r   loadsr<   r3   r=   r  )
r@   rA   r9   rQ  r   rN  rO  rP  r4  rD   s
             r-   get_asset_detailrS    s   3/  " 	@8+N!G%678#==8 	hksjuv??$ 	FT//# 	hksjuv??$ 	Ch[QOO%	 	

 !&a"'(#(8!&q#Ah %"7?HQKDJJx{3UW&
  	"  //s34Q()3../s%   AE C(E 	F/F;FFz
/api/statsc            	      &   	 t         j                         } | j                         }|j                  d       |j	                         d   }|j                  d       |j	                         d   }||z
  }|j                  d       |j	                         d   }| j                          t        d||||t        j                         dd      S # t        $ r:}t        j                  d|        t        d	t        |      i      d
fcY d}~S d}~ww xY w)u   서버 통계 정보zSELECT COUNT(*) FROM assetsr   zu
            SELECT COUNT(*) FROM assets 
            WHERE datetime(last_seen) > datetime('now', '-1 hour')
        zu
            SELECT COUNT(*) FROM assets 
            WHERE datetime(created_at) > datetime('now', '-1 day')
        T)total_assetsactive_assetsinactive_assetsrecent_registrationsserver_uptime)r+  statszGet stats error: r=   r  N)r-  rb   r9   r:   r>   r?   r   rr   r<   r3   r=   r  )rA   r9   rU  rV  rW  recent_assetsrD   s          r-   	get_statsr\  W  s   (/  " 	45(+ 	  	 )!, '6 	  	 )!,

 ,!.#2(5!%	
 	 		  /(,-Q()3../s   C
C 	D/DDDc            	         t         j                  d       	 	 t        j                         } 	 | j	                         }|j                  d       |j                  d       |j                  }|j                  d       |j                  }|j                  d       t        j                  j                         j                  d      }t         j                  d| d| d	|        |j                  d
       |j                         }dj                  |D cg c]  \  }}| d|  c}}      }|rt         j                  d|        t        j                  |        	 	 ddl}
|
j!                         j#                         j$                  dz  dz  }|dkD  rt         j'                  d|dd       t)        j*                  d       c c}}w # t        $ r!}		 j                  d       |	#  Y |	xY wd}	~	ww xY w# t        j                  |        w xY w# t        $ r"}	t         j                  d|	        Y d}	~	d}	~	ww xY w#  Y xY w)u3   개선된 데이터 정리 (백그라운드 작업)u   🧹 Cleanup thread startedzBEGIN IMMEDIATEz
                    UPDATE assets 
                    SET status = 'inactive' 
                    WHERE (julianday('now') - julianday(last_seen)) * 24 * 60 > 10 
                    AND status = 'active'
                z
                    UPDATE assets 
                    SET status = 'active' 
                    WHERE (julianday('now') - julianday(last_seen)) * 24 * 60 <= 5 
                    AND status = 'inactive'
                COMMITz%H:%M:%Su   🧹 [z] Cleanup: deactivated=z, activated=z3SELECT status, COUNT(*) FROM assets GROUP BY statusz, r2   u   📊 Asset status: ROLLBACKNu   ❌ Cleanup error: r   i   u   ⚠️ High memory usage: z.1fMB<   )r3   r4   r-  rb   r9   r:   rowcountr  r  strftimer;   r   r<   re   r=   psutilProcessmemory_inforssr6   rr   rD  )rA   r9   deactivated	activatedry   status_summaryr   rI  
status_strrD   rd  	memory_mbs               r-   cleanup_old_datarm    s   
KK-.
4	4$$&D/+ 01     %oo     #OO	 x(  (00446??
Kf\N2I+Vbclbmno TU!'!2!YYR`'a6("UG(<'ab
KK"5j\ BC $$T*	(446::TADHI4!;Ic?"MN 	

2E L (b  NN:.  $$T* 	4LL.qc233	4	sx   H C(G G
&"G H AI G 	G7G*(G2*G/,G22G77G: :HH 	H?H::H?Iz/api/admin/keywordsc                     	 t         j                         } | j                         }|j                  d       |j                  d       |j	                         }|rt        j                  |d         }ng dg dg dd}| j                          t        d|d	      S # t        $ r:}t        j                  d
|        t        dt        |      i      dfcY d}~S d}~ww xY w)u!   관리자 키워드 설정 조회#  
            CREATE TABLE IF NOT EXISTS admin_settings (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                setting_key TEXT UNIQUE NOT NULL,
                setting_value TEXT NOT NULL,
                updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        zOSELECT setting_value FROM admin_settings WHERE setting_key = 'license_keywords'r   )	microsoftofficeadobeautocadwindows)chromefirefoxvlcz7-zipz	notepad++)pythonnodegitvscodezvisual studio code)
commercialfree
opensourceT)r+  keywordszGet admin keywords error: r=   r  Nr-  rb   r9   r:   r>   r   rR  r?   r   r<   r3   r=   r  )rA   r9   rF   r  rD   s        r-   get_admin_keywordsr    s    %/  " 	  	 	hi"zz&),H UJWH 	

 
  	
  /1!56Q()3../s   BB 	C &/CC C c                  6   	 t        j                         } | j                  di       }t        j	                         }|j                         }|j                  d       |j                  dt        j                  |d      f       |j                          |j                          t        j                  dt        |       d       t        dd	d
      S # t        $ r:}t        j!                  d|        t        dt#        |      i      dfcY d}~S d}~ww xY w)u!   관리자 키워드 설정 저장r  ro  z
            INSERT OR REPLACE INTO admin_settings (setting_key, setting_value, updated_at)
            VALUES ('license_keywords', ?, CURRENT_TIMESTAMP)
        Fr   zAdmin keywords updated: z categoriesTzKeywords saved successfullyr+  r   zSave admin keywords error: r=   r  Nr   r,  ra   r-  rb   r9   r:   r   r   rI   r?   r3   r4   rt   r   r<   r=   r  )r.  r  rA   r9   rD   s        r-   save_admin_keywordsr    s    #/!88J+  " 	  	 	  jj68	:
 	

.s8}o[IJ4
  	
  /21#67Q()3../   CC 	D/DDDz!/api/admin/manual-classificationsc                     	 t         j                         } | j                         }|j                  d       |j                  d       |j	                         }|rt        j                  |d         }ni }| j                          t        d|d      S # t        $ r:}t        j                  d|        t        dt        |      i      dfcY d	}~S d	}~ww xY w)
u   수동 분류 설정 조회ro  zUSELECT setting_value FROM admin_settings WHERE setting_key = 'manual_classifications'r   T)r+  classificationsz"Get manual classifications error: r=   r  Nr  )rA   r9   rF   r  rD   s        r-   get_manual_classificationsr    s    /  " 	  	 	no""jj3O O

.
  	
  /9!=>Q()3../s   BB 	C/CCCc                  6   	 t        j                         } | j                  di       }t        j	                         }|j                         }|j                  d       |j                  dt        j                  |d      f       |j                          |j                          t        j                  dt        |       d       t        dd	d
      S # t        $ r:}t        j!                  d|        t        dt#        |      i      dfcY d}~S d}~ww xY w)u   수동 분류 설정 저장r  ro  z
            INSERT OR REPLACE INTO admin_settings (setting_key, setting_value, updated_at)
            VALUES ('manual_classifications', ?, CURRENT_TIMESTAMP)
        Fr   z Manual classifications updated: z	 softwareTz)Manual classifications saved successfullyr  z#Save manual classifications error: r=   r  Nr  )r.  r  rA   r9   rD   s        r-   save_manual_classificationsr  C  s    #/!((#4b9  " 	  	 	  jju=?	A
 	

6s?7K6LIVWB
  	
  /:1#>?Q()3../r  z/api/admin/settings-backupc                     	 t         j                         } | j                         }|j                  d       |j	                         }i }|D ]   }t        j                  |d         ||d   <   " t        j                  j                         j                         |d<   d|d<   | j                          t        d|d      S # t        $ r:}t        j                  d	|        t        d
t        |      i      dfcY d}~S d}~ww xY w)u   관리자 설정 백업z5SELECT setting_key, setting_value FROM admin_settingsr   r   backup_dater  r  T)r+  backupzBackup admin settings error: r=   r  N)r-  rb   r9   r:   r;   r   rR  r  r  r  r?   r   r<   r3   r=   r  )rA   r9   r   backup_datar   rD   s         r-   backup_admin_settingsr  k  s    /  "NO//# 	5C"&**SV"4KA	5 &.%6%6%:%:%<%F%F%HM"!(I

!
  	
  /4QC89Q()3../s   B=C   	D	/C>8D>Dz/api/admin/settings-restorec            	      X   	 t        j                         } | j                  di       }t        j	                         }|j                         }|j                  d       |j                         D ]3  \  }}|dvs|j                  d|t        j                  |d      f       5 |j                          |j                          t        j                  d       t        dd	d
      S # t        $ r:}t        j!                  d|        t        dt#        |      i      dfcY d}~S d}~ww xY w)u   관리자 설정 복원r  ro  )r  r  z
                    INSERT OR REPLACE INTO admin_settings (setting_key, setting_value, updated_at)
                    VALUES (?, ?, CURRENT_TIMESTAMP)
                Fr   z#Admin settings restored from backupTzSettings restored successfullyr  zRestore admin settings error: r=   r  N)r   r,  ra   r-  rb   r9   r:   itemsr   r   rI   r?   r3   r4   r   r<   r=   r  )r.  r  rA   r9   keyvaluerD   s          r-   restore_admin_settingsr    s   %/!(B'  " 	  	 !,,. 	CJC44   4::e%@AC	C 	

9;7
  	
  /5aS9:Q()3../s%   A5C& 8A-C& &	D)//D$D)$D)z/api/software/deletion-requestc                      	 t        j                         } | j                  d      }| j                  d      }|r|st        ddi      dfS t        j                         }|j                         }|j                  d|f       |j                         }|j                          |st        ddi      dfS t        j                         }|j                         }|j                  d	||f       |j                          |j                          t        j                  d
| d|        t        d| d| dd      S # t        $ r:}t        j                  d|        t        dt        |      i      dfcY d}~S d}~ww xY w)u   소프트웨어 삭제 요청r@   software_namer=   ,   hostname과 software_name이 필요합니다r(  r   (   해당 자산을 찾을 수 없습니다r  z
            INSERT OR REPLACE INTO software_management_requests (
                hostname, software_name, action_type, requested_at, status
            ) VALUES (?, ?, 'deletion_request', CURRENT_TIMESTAMP, 'pending')
        zSoftware deletion request:  on Tu   에 u'    삭제 요청이 전송되었습니다r  z!Software deletion request error: r  Nr   r,  ra   r   r-  rb   r9   r:   r>   r?   rI   r3   r4   r<   r=   r  r.  r@   r  rA   r9   rQ  rD   s          r-   request_software_deletionr    sq   &/!88J'1}G%STUWZZZ   "AH;O!

G%OPQSVVV   "  &		(
 	

1-XJOP"46]^
  	
  /8<=Q()3../,   AD: A'D: 3BD: :	E=/E82E=8E=z/api/software/force-removalc                      	 t        j                         } | j                  d      }| j                  d      }|r|st        ddi      dfS t        j                         }|j                         }|j                  d|f       |j                         }|j                          |st        ddi      dfS t        j                         }|j                         }|j                  d	||f       |j                          |j                          t        j                  d
| d|        t        d| d| dd      S # t        $ r:}t        j                  d|        t        dt        |      i      dfcY d}~S d}~ww xY w)u   소프트웨어 강제 제거r@   r  r=   r  r(  r   r  r  z
            INSERT OR REPLACE INTO software_management_requests (
                hostname, software_name, action_type, requested_at, status
            ) VALUES (?, ?, 'force_removal', CURRENT_TIMESTAMP, 'pending')
        zSoftware force removal: r  Tu   에서 u'    강제 제거가 요청되었습니다r  zSoftware force removal error: r  Nr  r  s          r-   force_software_removalr    sq   &/!88J'1}G%STUWZZZ   "AH;O!

G%OPQSVVV   "  &		(
 	

.}oT(LM"7=/9`a
  	
  /5aS9:Q()3../r  z,/api/software/management-requests/<hostname>c                    	 t         j                         }|j                         }|j                  d| f       |j	                         }|j                          g }|D ]$  }|j                  |d   |d   |d   |d   d       & t        d|d      S # t        $ r:}t        j                  d	|        t        d
t        |      i      dfcY d}~S d}~ww xY w)u:   특정 호스트의 관리 요청 조회 (에이전트용)z
            SELECT id, software_name, action_type, requested_at 
            FROM software_management_requests 
            WHERE hostname = ? AND status = 'pending'
            ORDER BY requested_at ASC
        r   r   r   r   )idr  action_typerequested_atT)r+  requestszGet management requests error: r=   r  N)r-  rb   r9   r:   r;   r?   rs   r   r<   r3   r=   r  )r@   rA   r9   r  rF   reqrD   s          r-   get_management_requestsr    s    /  " 
 [	 ??$

 	CMM!f!$Q"1v #A	 	 
  	
  /6qc:;Q()3../s   BB 	C/C
CCz;/api/software/management-requests/<int:request_id>/completec                    	 t        j                         }|j                  dd      }t        j	                         }|j                         }|j                  d|| f       |j                          |j                          t        j                  d|  d|        t        ddd      S # t        $ r:}t        j                  d	|        t        d
t        |      i      dfcY d}~S d}~ww xY w)u-   관리 요청 완료 처리 (에이전트용)rF   	completedz
            UPDATE software_management_requests 
            SET status = ?, completed_at = CURRENT_TIMESTAMP
            WHERE id = ?
        zManagement request z completed with result: Tu&   요청이 완료 처리되었습니다r  z#Complete management request error: r=   r  N)r   r,  ra   r-  rb   r9   r:   rI   r?   r3   r4   r   r<   r=   r  )
request_idr.  rF   rA   r9   rD   s         r-   complete_management_requestr  +  s    /!(K0  "  j!		#
 	

)*5MfXVW?
  	
  /:1#>?Q()3../s   B&B) )	C,2/C'!C,'C,z/api/agent/logc            	         	 t        j                         } g d}|D ]  }|| vst        dd| i      dfc S  t        j	                  | d   | d   | d   | d   | j                  d	      
       t        ddd      S # t        $ r:}t        j                  d|        t        dt        |      i      dfcY d}~S d}~ww xY w)u   에이전트 로그 제출)r@   r   r{   r   r=   r'  r(  r@   r   r{   r   r   )r@   r   r   r   r   TzLog submitted successfullyr  zAgent log submission error: r  N)
r   r,  r   r-  r   ra   r<   r3   r=   r  )r.  r/  r0  rD   s       r-   submit_agent_logr  H  s    /! C$ 	SED +CE7)KLMsRR	S
 	*%7m&\OHHY' 	 	
 3
  	
  /3A378Q()3../s(   !A< A< AA< <	B?/B:4B?:B?z/api/agent/logs/<hostname>c                     	 t         j                  |       }t        d| |t        |      d      S # t        $ r:}t
        j                  d|        t        dt        |      i      dfcY d}~S d}~ww xY w)r   T)r+  r@   r   rI  zGet agent logs error: r=   r  N)r-  r   r   rt   r<   r3   r=   r  )r@   r   rD   s      r-   get_agent_logs_apir  f  sx    /  * Y	
  	  /-aS12Q()3../s   -0 	A3/A.(A3.A3z/api/agent/logsc                      	 t         j                         } t        d| t        |       d      S # t        $ r:}t
        j                  d|        t        dt        |      i      dfcY d}~S d}~ww xY w)u2   로그가 있는 모든 에이전트 목록 조회T)r+  r   rI  zGet all agent logs error: r=   r  N)r-  r   r   rt   r<   r3   r=   r  )r   rD   s     r-   get_all_agent_logsr  w  ss    /557[
  	  /1!56Q()3../rK  __main__Trg   u(   🚀 Asset Management Server Starting...u3   🌐 Web Dashboard: http://localhost:5000/dashboarduA   📦 Software Dashboard: http://localhost:5000/software-dashboardu9   📋 Logs Dashboard: http://localhost:5000/logs-dashboardu1   📊 Assets API: http://localhost:5000/api/assetsu/   📈 Stats API: http://localhost:5000/api/statsu#   🔧 Ready to receive asset data...z0.0.0.0i  )hostr   debugthreaded)A__doc__r   r7   r  hashlibflaskr   r   r   r   r   
flask_corsr   werkzeug.middleware.proxy_fixr	   rj   rr   loggingr   r
   queuer   rB  basicConfigINFO	getLoggerr   r3   appconfigwsgi_appr   r-  router  r  r  r   r$  r   r5  r>  rG  rJ  rS  r\  rm  r  r  r  r  r  r  r  r  r  r  r  r  r  rk   cleanup_threadrm   r!   runr   r/   r-   <module>r     s  
     V V  2    	      ',, '			8	$Ho#

? #3

   AqQO S	~) ~)B _3  ! <E E,  !N "N  J J  $%5 &5
  6(3/ 4/< 1'/ 2'/R $vh73/ 83/j !F84 / 5 /D =5'*/ +/ "UG45/ 55/n <%)*/ **/XFR  5'2'/ 3'/R  6(3%/ 4%/N .@!/ A!/F .A%/ B%/N '%9/ :/6 (6(;'/ <'/T +fX>(/ ?(/T (6(;(/ <(/T 9E7K / L /D HSYRZ[/ \/8 fX./ //: '%9/ :/  ug./ // z%Y%%-=dKN	
45	
?@	
MN	
EF	
=>	
;<	
/0 GGUTGB r/   