๊ฐ์
์ด๋ฒ์ ์งํํ ํ๋ก์ ํธํด์ 2๊ฐ์ง๋ฅผ ๊ฐ๋ฐํด์ผํ๋ค.
1. ์๊ฒฉ ์๋ฒ์ ์๋ ํ์ผ์ ๋ก์ปฌ์ ๋ค์ด๋ก๋ํด์ผํ๋ค. (ํ์ผ์ด ์ปค์ ์ค๋ ๊ฑธ๋ฆฌ๋, progress bar๋ก ์งํ ์ฌํญ์ ๋ณด์ฌ์ฃผ์)
2. PySide6๋ก gui๋ฅผ ์ฌ๋ฆฐ๋ค.
1๏ธโฃ ํ์ผ ๋ค์ด๋ก๋
import paramiko
import time
def download_file(hostname, port, username, password, remote_file_path, local_file_path, progress_callback):
try:
start = time.perf_counter()
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname, port, username, password)
sftp = ssh.open_sftp()
remote_file_size = sftp.stat(remote_file_path).st_size
with sftp.open(remote_file_path, "rb") as remote_file, open(local_file_path, "wb") as local_file:
downloaded_size = 0
chunk_size = 8192
while True:
data = remote_file.read(chunk_size)
if not data:
break
local_file.write(data)
downloaded_size += len(data)
# ์งํ๋ฅ ๊ณ์ฐ ๋ฐ ์ฝ๋ฐฑ ํธ์ถ
progress = int((downloaded_size / remote_file_size) * 100)
progress_callback(progress)
print(f"File downloaded successfully from {remote_file_path} to {local_file_path}")
sftp.close()
ssh.close()
end = time.perf_counter()
print(f"model ๋ค์ด๋ก๋ ์๊ฐ: {end - start:.6f} ์ด")
except Exception as e:
print(f"An error occurred: {e}")
- paramiko ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํด์ ssh ์ ์ ์ ๋ณด๋ฅผ ์ ๋ ฅํด ์๊ฒฉ ์๋ฒ์ ์๋ ํ์ผ์ ์ ๊ทผํ๋ ๋ฐฉ์์ผ๋ก ์งํํ๋ค.
- ๋ค์ด๋ก๋ ํด์ผํ๋ ํ์ผ์ ํฌ๊ธฐ์ ๋ก์ปฌ์ ๋ค์ด๋ก๋ ๋ฐ์์ง๋ ํ์ผ์ ํฌ๊ธฐ๋ฅผ ๊ณ์ฐํด์ ์งํ๋ฅ ์ ๊ณ์ฐํ๋ค.
2๏ธโฃ PySide6์ผ๋ก GUI ์ฌ๋ฆฌ๊ธฐ
from PySide6.QtWidgets import (
QApplication, QVBoxLayout, QWidget, QProgressBar, QPushButton, QLabel, QDialog, QLineEdit, QFormLayout, QMessageBox
)
from PySide6.QtCore import QThread, Signal
from download_file_pyside6 import download_file
class DownloadThread(QThread):
progress = Signal(int)
completed = Signal()
def __init__(self, hostname, port, username, password, remote_file_path, local_file_path):
super().__init__()
self.hostname = hostname
self.port = port
self.username = username
self.password = password
self.remote_file_path = remote_file_path
self.local_file_path = local_file_path
def run(self):
download_file(
hostname=self.hostname,
port=self.port,
username=self.username,
password=self.password,
remote_file_path=self.remote_file_path,
local_file_path=self.local_file_path,
progress_callback=self.progress.emit
)
self.completed.emit()
class DownloadDialog(QDialog):
def __init__(self, parent, hostname, port, username, password, remote_file_path, local_file_path):
super().__init__(parent)
self.setWindowTitle("Downloading File")
self.resize(400, 150)
self.layout = QVBoxLayout(self)
# ์ํ ๋ ์ด๋ธ
self.status_label = QLabel("Preparing to download...", self)
self.layout.addWidget(self.status_label)
# ํ๋ก๊ทธ๋์ค๋ฐ
self.progress_bar = QProgressBar(self)
self.progress_bar.setValue(0)
self.progress_bar.setMaximum(100)
self.layout.addWidget(self.progress_bar)
# ๋ซ๊ธฐ ๋ฒํผ
self.close_button = QPushButton("Close", self)
self.close_button.setEnabled(False)
self.close_button.clicked.connect(self.close)
self.layout.addWidget(self.close_button)
# ๋ค์ด๋ก๋ ์ค๋ ๋ ์ค์
self.download_thread = DownloadThread(
hostname, port, username, password, remote_file_path, local_file_path
)
self.download_thread.progress.connect(self.update_progress)
self.download_thread.completed.connect(self.download_completed)
# ๋ค์ด๋ก๋ ์์
self.download_thread.start()
def update_progress(self, value):
self.progress_bar.setValue(value)
self.status_label.setText(f"Downloading... {value}%")
def download_completed(self):
self.status_label.setText("Download complete!")
self.close_button.setEnabled(True)
def closeEvent(self, event):
if self.download_completed:
event.accept()
else:
confirm = QMessageBox.question(
self,
"Confirm Close",
"Are you sure you want to stop downloading the model?",
QMessageBox.Yes | QMessageBox.No,
)
if confirm == QMessageBox.Yes:
event.accept()
os.remove(local_file_path)
else:
event.ignore()
class InputDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("Enter Download Details")
self.resize(400, 300)
self.layout = QFormLayout(self)
# ์
๋ ฅ ํ๋ ์์ฑ
self.hostname_input = QLineEdit(self)
self.port_input = QLineEdit(self)
self.port_input.setText("5022") # ๊ธฐ๋ณธ๊ฐ
self.username_input = QLineEdit(self)
self.password_input = QLineEdit(self)
self.password_input.setEchoMode(QLineEdit.Password)
self.remote_file_input = QLineEdit(self)
self.local_file_input = QLineEdit(self)
# ํ๋ ๋ ์ด์์ ์ถ๊ฐ
self.layout.addRow("Hostname:", self.hostname_input)
self.layout.addRow("Port:", self.port_input)
self.layout.addRow("Username:", self.username_input)
self.layout.addRow("Password:", self.password_input)
self.layout.addRow("Remote File Path:", self.remote_file_input)
self.layout.addRow("Local File Path:", self.local_file_input)
# ํ์ธ ๋ฐ ์ทจ์ ๋ฒํผ
self.ok_button = QPushButton("OK", self)
self.ok_button.clicked.connect(self.accept)
self.layout.addRow(self.ok_button)
self.setLayout(self.layout)
def get_inputs(self):
return {
"hostname": self.hostname_input.text(),
"port": int(self.port_input.text()),
"username": self.username_input.text(),
"password": self.password_input.text(),
"remote_file_path": self.remote_file_input.text(),
"local_file_path": self.local_file_input.text(),
}
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Main Window")
self.resize(400, 200)
self.layout = QVBoxLayout(self)
# ๋ค์ด๋ก๋ ๋ฒํผ
self.download_button = QPushButton("Download File", self)
self.download_button.clicked.connect(self.start_download_dialog)
self.layout.addWidget(self.download_button)
def start_download_dialog(self):
# ์
๋ ฅ ๋ํ ์์ ์ด๊ธฐ
input_dialog = InputDialog(self)
if input_dialog.exec(): # ์ฌ์ฉ์๊ฐ ํ์ธ ๋ฒํผ์ ๋๋ ๋์ง ํ์ธ
inputs = input_dialog.get_inputs()
dialog = DownloadDialog(
self,
hostname=inputs["hostname"],
port=inputs["port"],
username=inputs["username"],
password=inputs["password"],
remote_file_path=inputs["remote_file_path"],
local_file_path=inputs["local_file_path"],
)
dialog.exec()
if __name__ == "__main__":
app = QApplication([])
window = MainWindow()
window.show()
app.exec()
1. MainWindow๋ฅผ ์ฒซ ํ์ด์ง๋ก showํ๋ค.
2. Download File ๋ฒํผ์ ํด๋ฆญํ๋ฉด InputDialog ๊ฐ ์คํ๋๋ฉฐ ssh ์ ์ ์ ๋ณด๋ฅผ ์ ๋ ฅํ ์ ์๋ Dialog๊ฐ ๋์ด์ง๋ค.
default ๊ฐ (placeholder)๋ก ๊ฐ์ ๋ฃ์ ์ ์๊ณ , ์ ๋ ฅํ๋ ๊ฐ์ password๋ก ์ํธํํด์ ๋ณด์ฌ์ค ์๋ ์๋ค.
3. ์ ๋ณด๋ฅผ ์ ๋ ฅํ๊ณ OK๋ฅผ ํด๋ฆญํ๋ฉด DownloadDialog๊ฐ ์คํ๋๋ค
๋ค์ด๋ก๋ ์ค์๋ Close ๋ฒํผ์ด ๋นํ์ฑํ๋๊ณ , ๋ค์ด๋ก๋๊ฐ ์๋ฃ๋๋ฉด Close ๋ฒํผ์ด ํ์ฑํ๋๋ค.
๋ค์ด๋ก๋ ์งํ ์ค์ Downloading File dialog๋ฅผ ๋ซ์ผ๋ ค๊ณ ํ๋ค๋ฉด, "Are you sure you want to stop downloading the model?" ์ ๋ฌป๋๋ค. Yes → ๋ค์ด๋ก๋๋ ์ค์งํ๊ณ , ๋ค์ด๋ก๋ ์ค์ด์๋ ํ์ผ์ ์ญ์ ํ๋ค. No → ๋ค์ด๋ก๋๋ ๊ณ์ ์ด์ด๊ฐ๋ค.
'๐ฉ๐ปโ๐ป > python' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Celery๋ฅผ ์ด์ฉํ ํฌ๋กค๋ง ์์ (1) | 2025.02.05 |
---|---|
[python] gRPC ๊ฐ๋จํ๊ฒ ๊ตฌํํด๋ณด๊ธฐ (0) | 2025.01.02 |
[python] Fastapi ์ ํ๋ฆฌ์ผ์ด์ exe ํ์ผ๋ก ๋ฐฐํฌํ๊ธฐ (0) | 2024.11.05 |
[python] socket ๋์ ์ฐ๊ฒฐ (1) | 2024.10.22 |
[python] fastapi ์ค์๊ฐ ์คํธ๋ฆฌ๋ฐ ์ด๋ฏธ์ง ์ก์ถ (0) | 2024.10.21 |