|
|
|
|
|
// composables/useSignalR.js
|
|
|
|
|
|
import { ref, onMounted, onUnmounted } from 'vue';
|
|
|
|
|
|
import { HubConnection, HubConnectionBuilder, HttpTransportType, LogLevel } from '@microsoft/signalr';
|
|
|
|
|
|
|
|
|
|
|
|
export function useSignalR() {
|
|
|
|
|
|
const connection = ref(null) // 存储连接实例
|
|
|
|
|
|
const connectionId = ref('') // 存储 connectionId
|
|
|
|
|
|
const isConnected = ref(false) // 连接状态
|
|
|
|
|
|
const sigMsg = ref('');
|
|
|
|
|
|
const error = ref(null);
|
|
|
|
|
|
const authStore = useAuthStore();
|
|
|
|
|
|
|
|
|
|
|
|
const config = useRuntimeConfig();
|
|
|
|
|
|
|
|
|
|
|
|
// 消息处理器集合(支持多个监听器)
|
|
|
|
|
|
const messageHandlers = ref({});
|
|
|
|
|
|
|
|
|
|
|
|
const hubUrl = config.public.signalRUrl;
|
|
|
|
|
|
|
|
|
|
|
|
console.log("SignalR地址:", hubUrl);
|
|
|
|
|
|
// 连接配置
|
|
|
|
|
|
const connect = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
connection.value = new HubConnectionBuilder()
|
|
|
|
|
|
.withUrl(hubUrl, {
|
|
|
|
|
|
accessTokenFactory: () => {
|
|
|
|
|
|
const token = authStore.token; // 使用 Nuxt 的 useCookie 获取 Token
|
|
|
|
|
|
return token.value;
|
|
|
|
|
|
},
|
|
|
|
|
|
skipNegotiation: true, // 仅当使用 CORS 时需要
|
|
|
|
|
|
transport: HttpTransportType.WebSockets, // 优先 WebSocket
|
|
|
|
|
|
// httpClient: {
|
|
|
|
|
|
// fetch: async (url, options) => {
|
|
|
|
|
|
// // 添加 Token 到请求头
|
|
|
|
|
|
// options.headers = {
|
|
|
|
|
|
// ...options.headers,
|
|
|
|
|
|
// Authorization: `Bearer ${useCookie('token')?.value}`
|
|
|
|
|
|
// }
|
|
|
|
|
|
// return fetch(url, options)
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
})
|
|
|
|
|
|
.withAutomaticReconnect({
|
|
|
|
|
|
nextRetryDelayInMilliseconds: (retryContext) => {
|
|
|
|
|
|
// 自定义重连间隔(例如:首次 2s,之后 5s、10s...)
|
|
|
|
|
|
return retryContext.retryCount === 0 ? 2000 : 5000 * retryContext.retryCount;
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.configureLogging(LogLevel.Information)
|
|
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
|
|
// 监听连接成功事件(关键!)
|
|
|
|
|
|
// connection.value.on('ConnectionOpened', () => {
|
|
|
|
|
|
// connectionId.value = connection.value?.connectionId as string
|
|
|
|
|
|
// isConnected.value = true
|
|
|
|
|
|
// console.log('SignalR 连接成功,connectionId:', connectionId.value)
|
|
|
|
|
|
// })
|
|
|
|
|
|
|
|
|
|
|
|
// 注册消息处理
|
|
|
|
|
|
connection.value.on('ReceiveProgress', (progress, msg) => {
|
|
|
|
|
|
// console.log("ReceiveProgress", progress, msg);
|
|
|
|
|
|
sigMsg.value = JSON.stringify({ progress, msg });
|
|
|
|
|
|
// messages.value.push({ progress, msg, time: new Date() });
|
|
|
|
|
|
// 触发自定义事件(可选)
|
|
|
|
|
|
if (messageHandlers.value['ReceiveProgress']) {
|
|
|
|
|
|
messageHandlers.value['ReceiveProgress'](progress, msg);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
connection.value.on("ReceiveConnectionId", (conId) => {
|
|
|
|
|
|
connectionId.value = conId;
|
|
|
|
|
|
console.log('SignalR 连接成功,connectionId:', conId)
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 连接状态变更
|
|
|
|
|
|
connection.value.onclose((err) => {
|
|
|
|
|
|
isConnected.value = false;
|
|
|
|
|
|
error.value = err?.message || '连接意外断开';
|
|
|
|
|
|
console.error('SignalR 连接关闭:', err);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 启动连接
|
|
|
|
|
|
await connection.value.start();
|
|
|
|
|
|
console.log('SignalR 连接成功,connectionId:', connection.value.connectionId)
|
|
|
|
|
|
|
|
|
|
|
|
isConnected.value = true;
|
|
|
|
|
|
error.value = null;
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
isConnected.value = false;
|
|
|
|
|
|
connectionId.value = '';
|
|
|
|
|
|
error.value = err.message || '连接失败';
|
|
|
|
|
|
console.error('SignalR 连接启动失败:', err);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 断开连接
|
|
|
|
|
|
const disconnect = async () => {
|
|
|
|
|
|
if (connection.value) {
|
|
|
|
|
|
await connection.value.stop();
|
|
|
|
|
|
isConnected.value = false;
|
|
|
|
|
|
connectionId.value = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 发送消息
|
|
|
|
|
|
const sendMessage = async (method, ...args) => {
|
|
|
|
|
|
if (!isConnected.value) {
|
|
|
|
|
|
throw new Error('未连接到 SignalR 服务');
|
|
|
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
|
|
|
await connection.value.invoke(method, ...args);
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
error.value = `发送失败: ${err.message}`;
|
|
|
|
|
|
throw err;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 注册消息监听器(支持自定义事件)
|
|
|
|
|
|
const on = (eventName, callback) => {
|
|
|
|
|
|
if (!messageHandlers.value[eventName]) {
|
|
|
|
|
|
messageHandlers.value[eventName] = [];
|
|
|
|
|
|
}
|
|
|
|
|
|
messageHandlers.value[eventName].push(callback);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 移除监听器
|
|
|
|
|
|
const off = (eventName, callback) => {
|
|
|
|
|
|
if (messageHandlers.value[eventName]) {
|
|
|
|
|
|
messageHandlers.value[eventName] = messageHandlers.value[eventName].filter(cb => cb !== callback);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 生命周期钩子:自动连接
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
connect();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 生命周期钩子:组件卸载时断开
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
disconnect();
|
|
|
|
|
|
messageHandlers.value = {}; // 清理监听器
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
isConnected,
|
|
|
|
|
|
sigMsg,
|
|
|
|
|
|
error,
|
|
|
|
|
|
connectionId,
|
|
|
|
|
|
connect,
|
|
|
|
|
|
disconnect,
|
|
|
|
|
|
sendMessage,
|
|
|
|
|
|
on,
|
|
|
|
|
|
off
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|