设置了默认地址并修复退出房间异常问题,已部署成功
This commit is contained in:
parent
b7f087536b
commit
985ff72906
3
.gitignore
vendored
3
.gitignore
vendored
@ -36,9 +36,6 @@ src-tauri/target/
|
|||||||
.env.local
|
.env.local
|
||||||
.env.*.local
|
.env.*.local
|
||||||
|
|
||||||
# Config
|
|
||||||
config.json
|
|
||||||
|
|
||||||
# OS
|
# OS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|||||||
@ -75,6 +75,26 @@ io.on('connection', (socket) => {
|
|||||||
socket.emit('room-users', roomUsers);
|
socket.emit('room-users', roomUsers);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on('leave-room', ({ roomId, userId, socketId }) => {
|
||||||
|
const user = users.get(socketId);
|
||||||
|
if (user && user.roomId === roomId) {
|
||||||
|
const room = rooms.get(roomId);
|
||||||
|
if (room) {
|
||||||
|
room.delete(socketId);
|
||||||
|
socket.to(roomId).emit('user-left', {
|
||||||
|
userId: user.userId,
|
||||||
|
socketId: socketId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (room.size === 0) {
|
||||||
|
rooms.delete(roomId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
users.delete(socketId);
|
||||||
|
socket.leave(roomId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
socket.on('signal', ({ targetSocketId, signal }) => {
|
socket.on('signal', ({ targetSocketId, signal }) => {
|
||||||
const targetUser = users.get(targetSocketId);
|
const targetUser = users.get(targetSocketId);
|
||||||
if (targetUser) {
|
if (targetUser) {
|
||||||
|
|||||||
35
src/App.vue
35
src/App.vue
@ -1,5 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, onUnmounted } from 'vue';
|
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
||||||
import { io } from 'socket.io-client';
|
import { io } from 'socket.io-client';
|
||||||
|
|
||||||
// 导入组件
|
// 导入组件
|
||||||
@ -16,7 +16,7 @@ import { useWebRTC } from './composables/useWebRTC.js';
|
|||||||
import { useFileTransfer } from './composables/useFileTransfer.js';
|
import { useFileTransfer } from './composables/useFileTransfer.js';
|
||||||
|
|
||||||
// 使用组合式函数
|
// 使用组合式函数
|
||||||
const { socket, userId, nickname, connected, roomUsers, roomId, joinRoom, serverUrl, connectToServer, disconnectFromServer } = useSocket();
|
const { socket, userId, nickname, connected, roomUsers, roomId, joinRoom, leaveRoom, onUserLeft, serverUrl, connectToServer, disconnectFromServer } = useSocket();
|
||||||
const localServerUrl = ref(serverUrl.value);
|
const localServerUrl = ref(serverUrl.value);
|
||||||
|
|
||||||
// 处理连接按钮点击
|
// 处理连接按钮点击
|
||||||
@ -35,7 +35,8 @@ const {
|
|||||||
createPeerConnection,
|
createPeerConnection,
|
||||||
handleSignal,
|
handleSignal,
|
||||||
setupDataChannel,
|
setupDataChannel,
|
||||||
closePeerConnection
|
closePeerConnection,
|
||||||
|
closeAllPeerConnections
|
||||||
} = useWebRTC();
|
} = useWebRTC();
|
||||||
const {
|
const {
|
||||||
transfers,
|
transfers,
|
||||||
@ -45,7 +46,8 @@ const {
|
|||||||
sendFile,
|
sendFile,
|
||||||
acceptFile,
|
acceptFile,
|
||||||
rejectFile,
|
rejectFile,
|
||||||
selectFile
|
selectFile,
|
||||||
|
clearTransfers
|
||||||
} = useFileTransfer();
|
} = useFileTransfer();
|
||||||
|
|
||||||
// 连接用户
|
// 连接用户
|
||||||
@ -100,8 +102,29 @@ function handleDisconnectUser(socketId) {
|
|||||||
closePeerConnection(socketId);
|
closePeerConnection(socketId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听信号
|
// 判断是否有文件正在传输
|
||||||
|
const hasActiveTransfer = computed(() => {
|
||||||
|
return transfers.value.some(t =>
|
||||||
|
t.status === 'sending' || t.status === 'receiving'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 处理退出房间事件
|
||||||
|
function handleLeaveRoom() {
|
||||||
|
if (hasActiveTransfer.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
closeAllPeerConnections();
|
||||||
|
clearTransfers();
|
||||||
|
leaveRoom();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置用户离开回调和监听信号
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
onUserLeft.value = (socketId) => {
|
||||||
|
closePeerConnection(socketId);
|
||||||
|
};
|
||||||
|
|
||||||
if (socket.value) {
|
if (socket.value) {
|
||||||
socket.value.on('signal', async ({ senderSocketId, signal }) => {
|
socket.value.on('signal', async ({ senderSocketId, signal }) => {
|
||||||
await handleSignal(
|
await handleSignal(
|
||||||
@ -182,8 +205,10 @@ onUnmounted(() => {
|
|||||||
:peer-connections="peerConnections"
|
:peer-connections="peerConnections"
|
||||||
:room-id="roomId"
|
:room-id="roomId"
|
||||||
:current-socket-id="socket?.id"
|
:current-socket-id="socket?.id"
|
||||||
|
:has-active-transfer="hasActiveTransfer"
|
||||||
@connect-user="connectToUser"
|
@connect-user="connectToUser"
|
||||||
@disconnect-user="handleDisconnectUser"
|
@disconnect-user="handleDisconnectUser"
|
||||||
|
@leave-room="handleLeaveRoom"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FileSend
|
<FileSend
|
||||||
|
|||||||
@ -1,6 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="section" v-if="roomId">
|
<div class="section" v-if="roomId">
|
||||||
|
<div class="room-header">
|
||||||
<h2>{{ $t('room.users_in_room') }}</h2>
|
<h2>{{ $t('room.users_in_room') }}</h2>
|
||||||
|
<button
|
||||||
|
@click="leaveRoom"
|
||||||
|
:disabled="hasActiveTransfer"
|
||||||
|
class="leave-room-btn"
|
||||||
|
:title="hasActiveTransfer ? $t('room.cannot_leave_room') : ''"
|
||||||
|
>
|
||||||
|
{{ $t('room.leave_room') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<div class="room-info">
|
<div class="room-info">
|
||||||
<span class="room-id">{{ $t('room.room_id') }}: {{ roomId }}</span>
|
<span class="room-id">{{ $t('room.room_id') }}: {{ roomId }}</span>
|
||||||
<span class="user-count">{{ $t('room.users_in_room') }}: {{ roomUsers.length }}</span>
|
<span class="user-count">{{ $t('room.users_in_room') }}: {{ roomUsers.length }}</span>
|
||||||
@ -57,11 +67,15 @@ const props = defineProps({
|
|||||||
currentSocketId: {
|
currentSocketId: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
|
},
|
||||||
|
hasActiveTransfer: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 定义组件emit事件
|
// 定义组件emit事件
|
||||||
const emit = defineEmits(['connectUser', 'disconnectUser']);
|
const emit = defineEmits(['connectUser', 'disconnectUser', 'leaveRoom']);
|
||||||
|
|
||||||
// 判断是否为当前用户
|
// 判断是否为当前用户
|
||||||
function isCurrentUser(socketId) {
|
function isCurrentUser(socketId) {
|
||||||
@ -77,6 +91,11 @@ function connectToUser(socketId) {
|
|||||||
function disconnectFromUser(socketId) {
|
function disconnectFromUser(socketId) {
|
||||||
emit('disconnectUser', socketId);
|
emit('disconnectUser', socketId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理退出房间事件
|
||||||
|
function leaveRoom() {
|
||||||
|
emit('leaveRoom');
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@ -88,6 +107,42 @@ function disconnectFromUser(socketId) {
|
|||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.room-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.room-header h2 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leave-room-btn {
|
||||||
|
padding: 8px 16px;
|
||||||
|
background: #ff9800;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leave-room-btn:disabled {
|
||||||
|
background: #ccc;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leave-room-btn:hover:not(:disabled) {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.leave-room-btn:active:not(:disabled) {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
.room-info {
|
.room-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 15px;
|
gap: 15px;
|
||||||
|
|||||||
@ -319,6 +319,11 @@ export function useFileTransfer() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearTransfers() {
|
||||||
|
transfers.value = [];
|
||||||
|
pendingTransfers.value = [];
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
transfers,
|
transfers,
|
||||||
pendingTransfers,
|
pendingTransfers,
|
||||||
@ -327,6 +332,7 @@ export function useFileTransfer() {
|
|||||||
sendFile,
|
sendFile,
|
||||||
acceptFile,
|
acceptFile,
|
||||||
rejectFile,
|
rejectFile,
|
||||||
selectFile
|
selectFile,
|
||||||
|
clearTransfers
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,12 @@
|
|||||||
import { ref, onMounted, onUnmounted } from 'vue';
|
import { ref, onMounted, onUnmounted } from 'vue';
|
||||||
import { io } from 'socket.io-client';
|
import { io } from 'socket.io-client';
|
||||||
import { generateUserId } from '../utils';
|
import { generateUserId } from '../utils';
|
||||||
import config from '../../config.json';
|
|
||||||
|
|
||||||
function isTauri() {
|
function isTauri() {
|
||||||
return window.__TAURI__ !== undefined;
|
return window.__TAURI__ !== undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDefaultServerUrl() {
|
|
||||||
return config.defaultServerUrl || 'http://localhost:3000';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useSocket() {
|
export function useSocket() {
|
||||||
const socket = ref(null);
|
const socket = ref(null);
|
||||||
const userId = ref('');
|
const userId = ref('');
|
||||||
@ -18,7 +14,8 @@ export function useSocket() {
|
|||||||
const connected = ref(false);
|
const connected = ref(false);
|
||||||
const roomUsers = ref([]);
|
const roomUsers = ref([]);
|
||||||
const roomId = ref('');
|
const roomId = ref('');
|
||||||
const serverUrl = ref(localStorage.getItem('p2p-server-url') || getDefaultServerUrl());
|
const serverUrl = ref(localStorage.getItem('p2p-server-url') || 'wss://p2p-file-transfer.cloyir.com');
|
||||||
|
const onUserLeft = ref(null);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
userId.value = generateUserId();
|
userId.value = generateUserId();
|
||||||
@ -83,6 +80,9 @@ export function useSocket() {
|
|||||||
|
|
||||||
socket.value.on('user-left', ({ userId: leftUserId, socketId }) => {
|
socket.value.on('user-left', ({ userId: leftUserId, socketId }) => {
|
||||||
roomUsers.value = roomUsers.value.filter(u => u.socketId !== socketId);
|
roomUsers.value = roomUsers.value.filter(u => u.socketId !== socketId);
|
||||||
|
if (onUserLeft.value) {
|
||||||
|
onUserLeft.value(socketId);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,6 +107,18 @@ export function useSocket() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function leaveRoom() {
|
||||||
|
if (roomId.value && socket.value) {
|
||||||
|
socket.value.emit('leave-room', {
|
||||||
|
roomId: roomId.value,
|
||||||
|
userId: userId.value,
|
||||||
|
socketId: socket.value.id
|
||||||
|
});
|
||||||
|
roomId.value = '';
|
||||||
|
roomUsers.value = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
socket,
|
socket,
|
||||||
userId,
|
userId,
|
||||||
@ -115,8 +127,10 @@ export function useSocket() {
|
|||||||
roomUsers,
|
roomUsers,
|
||||||
roomId,
|
roomId,
|
||||||
serverUrl,
|
serverUrl,
|
||||||
joinRoom,
|
onUserLeft,
|
||||||
connectToServer,
|
connectToServer,
|
||||||
disconnectFromServer
|
disconnectFromServer,
|
||||||
|
joinRoom,
|
||||||
|
leaveRoom
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -137,6 +137,8 @@ export function useWebRTC() {
|
|||||||
channel.onclose = () => {
|
channel.onclose = () => {
|
||||||
console.log('Data channel closed with:', socketId);
|
console.log('Data channel closed with:', socketId);
|
||||||
dataChannelReady.value.delete(socketId);
|
dataChannelReady.value.delete(socketId);
|
||||||
|
dataChannels.value.delete(socketId);
|
||||||
|
peerConnections.value.delete(socketId);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,6 +155,20 @@ export function useWebRTC() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function closeAllPeerConnections() {
|
||||||
|
peerConnections.value.forEach((pc, socketId) => {
|
||||||
|
pc.close();
|
||||||
|
});
|
||||||
|
peerConnections.value.clear();
|
||||||
|
|
||||||
|
dataChannels.value.forEach((dc) => {
|
||||||
|
dc.close();
|
||||||
|
});
|
||||||
|
dataChannels.value.clear();
|
||||||
|
|
||||||
|
dataChannelReady.value.clear();
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
peerConnections,
|
peerConnections,
|
||||||
dataChannels,
|
dataChannels,
|
||||||
@ -160,6 +176,7 @@ export function useWebRTC() {
|
|||||||
createPeerConnection,
|
createPeerConnection,
|
||||||
handleSignal,
|
handleSignal,
|
||||||
setupDataChannel,
|
setupDataChannel,
|
||||||
closePeerConnection
|
closePeerConnection,
|
||||||
|
closeAllPeerConnections
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,9 @@ export default {
|
|||||||
nickname: 'Nickname',
|
nickname: 'Nickname',
|
||||||
join: 'Join',
|
join: 'Join',
|
||||||
leave: 'Leave',
|
leave: 'Leave',
|
||||||
users_in_room: 'Users in Room'
|
users_in_room: 'Users in Room',
|
||||||
|
leave_room: 'Leave Room',
|
||||||
|
cannot_leave_room: 'Cannot leave room while transferring files'
|
||||||
},
|
},
|
||||||
file_transfer: {
|
file_transfer: {
|
||||||
connect: 'Connect',
|
connect: 'Connect',
|
||||||
|
|||||||
@ -17,7 +17,9 @@ export default {
|
|||||||
nickname: '昵称',
|
nickname: '昵称',
|
||||||
join: '加入',
|
join: '加入',
|
||||||
leave: '离开',
|
leave: '离开',
|
||||||
users_in_room: '房间内用户'
|
users_in_room: '房间内用户',
|
||||||
|
leave_room: '退出房间',
|
||||||
|
cannot_leave_room: '正在传输文件,无法退出房间'
|
||||||
},
|
},
|
||||||
file_transfer: {
|
file_transfer: {
|
||||||
connect: '连接',
|
connect: '连接',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user