add upload/download function

This commit is contained in:
backuppc
2026-01-20 14:42:44 +09:00
parent 4376babbcc
commit 237ed6ea8b
3 changed files with 197 additions and 3 deletions

124
App.tsx
View File

@@ -8,6 +8,7 @@ import SettingsModal from './components/SettingsModal';
import SiteManagerModal from './components/SiteManagerModal';
import HelpModal from './components/HelpModal';
import { CreateFolderModal, RenameModal, DeleteModal } from './components/FileActionModals';
import { formatBytes } from './utils/formatters';
const App: React.FC = () => {
// --- State ---
@@ -262,7 +263,7 @@ const App: React.FC = () => {
case 'success':
addLog('success', data.message);
if (connection.connected) {
if (connectionRef.current.connected) {
ws?.send(JSON.stringify({ command: 'LIST', path: remote.path }));
}
ws?.send(JSON.stringify({ command: 'LOCAL_LIST', path: local.path }));
@@ -271,6 +272,45 @@ const App: React.FC = () => {
case 'sites_list':
setSavedSites(data.sites);
break;
case 'transfer_progress':
setQueue(prev => prev.map(item => {
if (item.id === data.id) {
const total = data.bytesOverall;
const current = data.bytes;
const progress = total > 0 ? Math.round((current / total) * 100) : 0;
return { ...item, progress, status: 'transferring', speed: `${formatBytes(current)} transferred` };
}
return item;
}));
break;
case 'transfer_success':
setQueue(prev => prev.map(item => {
if (item.id === data.id) {
return { ...item, progress: 100, status: 'completed', speed: 'Completed' };
}
return item;
}));
addLog('success', data.message);
// Refresh lists
if (data.path) {
ws?.send(JSON.stringify({ command: 'LOCAL_LIST', path: local.path }));
if (connectionRef.current.connected) {
ws?.send(JSON.stringify({ command: 'LIST', path: remote.path }));
}
}
break;
case 'transfer_error':
setQueue(prev => prev.map(item => {
if (item.id === data.id) {
return { ...item, status: 'failed', speed: data.message };
}
return item;
}));
addLog('error', data.message);
break;
}
} catch (e) {
console.error("WS Message Error", e);
@@ -365,6 +405,74 @@ const App: React.FC = () => {
if (wsRef.current) wsRef.current.send(JSON.stringify({ command: 'LOCAL_LIST', path }));
};
const handleDownload = () => {
if (!connection.connected || selectedRemoteIds.size === 0) return;
selectedRemoteIds.forEach(id => {
const file = remote.files.find(f => f.id === id);
if (file && file.type === FileType.FILE) {
const transferId = `down-${Date.now()}-${Math.random()}`;
const separator = local.path.includes('\\') ? '\\' : '/';
const cleanPath = local.path.endsWith(separator) ? local.path : local.path + separator;
const localTarget = cleanPath + file.name;
const remoteTarget = remote.path === '/' ? `/${file.name}` : `${remote.path}/${file.name}`;
// Add to Queue
setQueue(prev => [...prev, {
id: transferId,
direction: 'download',
filename: file.name,
progress: 0,
status: 'queued',
speed: 'Pending...'
}]);
addLog('command', `DOWNLOAD ${file.name} -> ${localTarget}`);
wsRef.current?.send(JSON.stringify({
command: 'DOWNLOAD',
localPath: localTarget,
remotePath: remoteTarget,
transferId
}));
}
});
setSelectedRemoteIds(new Set());
};
const handleUpload = () => {
if (!connection.connected || selectedLocalIds.size === 0) return;
selectedLocalIds.forEach(id => {
const file = local.files.find(f => f.id === id);
if (file && file.type === FileType.FILE) {
const transferId = `up-${Date.now()}-${Math.random()}`;
const separator = local.path.includes('\\') ? '\\' : '/';
const cleanPath = local.path.endsWith(separator) ? local.path : local.path + separator;
const localSource = cleanPath + file.name;
const remoteTarget = remote.path === '/' ? `/${file.name}` : `${remote.path}/${file.name}`;
// Add to Queue
setQueue(prev => [...prev, {
id: transferId,
direction: 'upload',
filename: file.name,
progress: 0,
status: 'queued',
speed: 'Pending...'
}]);
addLog('command', `UPLOAD ${file.name} -> ${remoteTarget}`);
wsRef.current?.send(JSON.stringify({
command: 'UPLOAD',
localPath: localSource,
remotePath: remoteTarget,
transferId
}));
}
});
setSelectedLocalIds(new Set());
};
// --- File Action Handlers ---
const initiateCreateFolder = (isLocal: boolean) => {
if (!isLocal && !connection.connected) return;
@@ -744,10 +852,20 @@ const App: React.FC = () => {
{/* Middle Actions */}
<div className="flex md:flex-col items-center justify-center gap-2 p-1">
<button className="p-3 bg-white border border-slate-300 shadow-sm rounded hover:bg-blue-50 text-slate-400">
<button
className="p-3 bg-white border border-slate-300 shadow-sm rounded hover:bg-blue-50 text-slate-400 hover:text-blue-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
onClick={handleUpload}
disabled={!connection.connected || selectedLocalIds.size === 0}
title="업로드 (Local -> Remote)"
>
<ArrowRight size={24} strokeWidth={2.5} />
</button>
<button className="p-3 bg-white border border-slate-300 shadow-sm rounded hover:bg-green-50 text-slate-400">
<button
className="p-3 bg-white border border-slate-300 shadow-sm rounded hover:bg-green-50 text-slate-400 hover:text-green-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
onClick={handleDownload}
disabled={!connection.connected || selectedRemoteIds.size === 0}
title="다운로드 (Remote -> Local)"
>
<ArrowLeft size={24} strokeWidth={2.5} />
</button>
</div>