diff --git a/client/main.js b/client/main.js
index f8cf119..4e2266f 100644
--- a/client/main.js
+++ b/client/main.js
@@ -149,9 +149,17 @@ function addPeer(id, name) {
${name}
`;
- // Click to send file
+ // Click to send file - start connection immediately when clicking on peer
el.addEventListener('click', () => {
currentTransferTarget = id;
+
+ // Start WebRTC connection immediately when user clicks on peer
+ // This gives time for connection to establish before file is selected
+ const peer = peers.get(id);
+ if (!peer.connection || peer.connection.connectionState !== 'connected') {
+ startConnection(id);
+ }
+
fileInput.click();
});
@@ -180,6 +188,16 @@ function getOrCreateConnection(peerId) {
if (!peer.connection) {
const pc = new RTCPeerConnection(rtcConfig);
+ // Track connection state
+ pc.onconnectionstatechange = () => {
+ console.log(`Connection state with ${peer.name}: ${pc.connectionState}`);
+ if (pc.connectionState === 'connected') {
+ showToast(`Connected to ${peer.name}`, 'success');
+ } else if (pc.connectionState === 'failed' || pc.connectionState === 'disconnected') {
+ showToast(`Connection lost with ${peer.name}`, 'error');
+ }
+ };
+
// Output ICE candidates to signaling server
pc.onicecandidate = (e) => {
if (e.candidate) {
@@ -263,20 +281,78 @@ fileInput.addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file || !currentTransferTarget) return;
- // If connection isn't established, establish it first
const peer = peers.get(currentTransferTarget);
- if (!peer.connection || peer.connection.connectionState !== 'connected') {
- await startConnection(currentTransferTarget);
- // Wait briefly for connection (in reality, should listen for connection state change)
- setTimeout(() => sendFileHeader(currentTransferTarget, file), 1000);
- } else {
+
+ // Check if connection exists and is connected
+ if (peer.connection && peer.connection.connectionState === 'connected') {
sendFileHeader(currentTransferTarget, file);
+ } else {
+ // Connection is being established (or was just started on peer click)
+ // Wait for connection to be ready with exponential backoff
+ let attempts = 0;
+ const maxAttempts = 10;
+ const checkConnection = () => {
+ attempts++;
+ if (peer.connection && peer.connection.connectionState === 'connected') {
+ sendFileHeader(currentTransferTarget, file);
+ } else if (attempts < maxAttempts) {
+ // Exponential backoff: 100ms, 200ms, 400ms, etc.
+ setTimeout(checkConnection, 100 * Math.pow(2, attempts));
+ } else {
+ showToast('Connection failed. Try again.', 'error');
+ }
+ };
+ checkConnection();
}
fileInput.value = ''; // Reset input
});
function sendFileHeader(peerId, file) {
+ const peer = peers.get(peerId);
+ if (!peer || !peer.dataChannel) {
+ showToast('Connection not ready. Trying again...', 'info');
+
+ // Try to start connection and wait for it
+ startConnection(peerId);
+ let attempts = 0;
+ const checkDataChannel = () => {
+ attempts++;
+ if (peer.dataChannel && peer.dataChannel.readyState === 'open') {
+ doSendFileHeader(peerId, file);
+ } else if (attempts < 10) {
+ setTimeout(checkDataChannel, 200);
+ } else {
+ showToast('Connection failed. Try again.', 'error');
+ }
+ };
+ setTimeout(checkDataChannel, 500);
+ return;
+ }
+
+ if (peer.dataChannel.readyState !== 'open') {
+ showToast('Connection not ready. Trying again...', 'info');
+
+ // Wait for data channel to open
+ let attempts = 0;
+ const checkDataChannel = () => {
+ attempts++;
+ if (peer.dataChannel.readyState === 'open') {
+ doSendFileHeader(peerId, file);
+ } else if (attempts < 10) {
+ setTimeout(checkDataChannel, 200);
+ } else {
+ showToast('Connection failed. Try again.', 'error');
+ }
+ };
+ setTimeout(checkDataChannel, 200);
+ return;
+ }
+
+ doSendFileHeader(peerId, file);
+}
+
+function doSendFileHeader(peerId, file) {
const peer = peers.get(peerId);
if (!peer || !peer.dataChannel || peer.dataChannel.readyState !== 'open') {
showToast('Connection not ready. Try again.', 'error');