Add peer-to-peer file transfer in browser mode
Implements both pull (browse & download from a shared folder) and push (send a file directly to a peer) using the yaw2 file protocol over WebRTC DataChannels. - PeerConn: handle browse/files/get/file-offer/file-accept/file-done control messages; stream files in 64KB chunks over f:xid binary DataChannels; auto-accept incoming offers (push and pull) - PeerConn.sendFilePush(): initiate an outbound file transfer without requiring the peer to browse first - BrowserAdapter: sharedFiles map, setSharedFiles(), requestBrowse(), requestGet(), sendFileTo() — propagates share map to all active peers - Store: activeFilePeer, setActiveFilePeer, setSharedFiles, browseFiles, sendFileTo; file_complete handler triggers browser download automatically - FileBrowser component: third-column panel listing a peer's shared files with name, size, and a download button - FolderPicker component: webkitdirectory input in the sidebar (browser mode only) for selecting a local folder to share - Sidebar: 📎 send-file button on peer rows (hover) with inline file picker - App.tsx: use browser mode when WASTE_CONFIG.signalURL is set, even on localhost — allows testing browser mode via npm run dev with config.js - deploy-daemon.sh: kill existing daemon before scp to avoid upload failure when the binary is locked; remove duplicate kill block in restart step Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { useWaste } from '../store'
|
||||
import type { PeerStatus } from '../store'
|
||||
import { FolderPicker } from './FolderPicker'
|
||||
|
||||
function makeYawCard(id: string, alias: string): string {
|
||||
const nick = encodeURIComponent(alias.trim().slice(0, 40))
|
||||
@@ -28,7 +29,7 @@ export function Sidebar() {
|
||||
localPeer, masterId, masterAlias,
|
||||
networks, activeNetworkId, activeRoom,
|
||||
connectedPeers, peerStatus,
|
||||
setActiveRoom, setActiveNetwork, messages, send,
|
||||
setActiveRoom, setActiveNetwork, messages, browseFiles, sendFileTo, adapterMode,
|
||||
} = useWaste()
|
||||
|
||||
const rooms = ['general']
|
||||
@@ -45,7 +46,7 @@ export function Sidebar() {
|
||||
}
|
||||
|
||||
function requestFiles(peerId: string) {
|
||||
send({ type: 'get_file_list', network_id: activeNetworkId ?? undefined, peer_id: peerId })
|
||||
browseFiles(peerId)
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -86,6 +87,13 @@ export function Sidebar() {
|
||||
))}
|
||||
</div>
|
||||
|
||||
{adapterMode === 'browser' && (
|
||||
<div className="sidebar-section">
|
||||
<span className="sidebar-label">Sharing</span>
|
||||
<div style={{ padding: '4px 12px' }}><FolderPicker /></div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="sidebar-section sidebar-peers">
|
||||
<span className="sidebar-label">Peers · {connectedPeers.length + 1}</span>
|
||||
|
||||
@@ -116,7 +124,15 @@ export function Sidebar() {
|
||||
<span className="peer-row-id">{p.id.slice(0, 8)}</span>
|
||||
<span className="peer-row-actions">
|
||||
<button className="peer-action" onClick={() => openDM(p.id)} title="DM">↩</button>
|
||||
<button className="peer-action" onClick={() => requestFiles(p.id)} title="Files">⊞</button>
|
||||
<button className="peer-action" onClick={() => requestFiles(p.id)} title="Browse files">⊞</button>
|
||||
<label className="peer-action" title="Send file" style={{ cursor: 'pointer' }}>
|
||||
📎
|
||||
<input type="file" style={{ display: 'none' }} onChange={e => {
|
||||
const f = e.target.files?.[0]
|
||||
if (f) sendFileTo(p.id, f)
|
||||
e.target.value = ''
|
||||
}} />
|
||||
</label>
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user