Commit eaf344f3 by qlintonger xeno

开始配置ws

parent 811b4597
This source diff could not be displayed because it is too large. You can view the blob instead.
import {chatChannelState} from "AnyR/states/chatChannelStates";
import {webrtcStates} from "AnyR/states/webrtcStates";
import {userStates} from "AnyR/states/wsStates";
export class Agora {
notUploadLog = false;
logLevel = 1;
codec = '';
mode = '';
appId = '';
localPlayerId = '';
remotePlayerPrefix = ''
data = {
uid: null,
localTracks: {
videoTrack: undefined,
audioTrack: undefined,
},
}
AgoraClient = null
localAp = null
constructor(options) {
this.notUploadLog = options.notUploadLog
this.logLevel = options.logLevel
this.codec = options.codec
this.mode = options.mode
this.appId = options.appId
this.localPlayerId = options.localPlayerId
this.remotePlayerPrefix = options.remotePlayerPrefix
this.localAp = options.localAp
}
async #subscribe(user, mediaType) {
await this.AgoraClient.subscribe(user, mediaType);
const allUsers = userStates.value.onlineContacts
const foundUser = allUsers.find(i => i.fromID.toString() === user.uid.toString());
console.log('开始订阅远端用户', user, mediaType, foundUser);
const remoteUserIdInThisUser = this.remotePlayerPrefix + user.uid;
if (mediaType === 'video') {
user?.videoTrack?.play(remoteUserIdInThisUser);
}
if (mediaType === 'audio') {
user?.audioTrack?.play();
}
}
#clearTracks() {
for (const v of Object.values(this.data.localTracks)) {
if (v && !v._isClosed) {
v.stop();
v.close()
}
}
this.data.localTracks = {
videoTrack: undefined,
audioTrack: undefined,
};
}
async join(channelId, token = null, uid = null) {
let canProceed = true;
this.data.uid = uid ? uid.toString() : ''
const {isMicroAttached, isCameraAttached} = webrtcStates.value
console.log('创建条件', isMicroAttached, isCameraAttached, channelId, token, uid, this.appId);
if (this.localAp) {
this.AgoraClient.setLocalAccessPointsV2(this.localAp);
}
try {
if (isMicroAttached) {
this.data.localTracks.audioTrack = await AgoraRTC.createMicrophoneAudioTrack();
}
if (isCameraAttached) {
this.data.localTracks.videoTrack = await AgoraRTC.createCameraVideoTrack();
webrtcStates.value.currentUsingCameraName = this.data.localTracks.videoTrack._deviceName;
}
} catch (e) {
console.log('加入频道出现错误', e)
canProceed = false;
this.#clearTracks()
}
console.log('tracks here', this.data.localTracks);
if (!this.data.localTracks.videoTrack || !this.data.localTracks.audioTrack) {
alert('创建音视频轨道失败!离开会议!')
await this.leave()
return;
}
this.AgoraClient.enableAudioVolumeIndicator();
await this.AgoraClient.join(this.appId, channelId, token || null, Number(uid));
if (canProceed) {
console.log('创建音视频轨道成功!', this.data.localTracks)
if (this.data.localTracks.videoTrack) {
this.data.localTracks.videoTrack.play(this.localPlayerId, {fit: 'contain'})
}
console.log('开始播放本地媒体')
await this.AgoraClient.publish(Object.values(this.data.localTracks));
console.log('成功发布媒体')
}
}
currentUserToggleMute(v) {
if (this.data.localTracks.audioTrack) {
this.data.localTracks.audioTrack.setMuted(v);
}
}
async toggleScreenShare(v, endFunc, failedFunc, pageHideFunc) {
const videoTrack = this.AgoraClient.localTracks.find(i => i.trackMediaType === 'video');
if (videoTrack) {
videoTrack.stop();
const currentVideoTrack = this.AgoraClient.localTracks.find(i => i._ID === videoTrack._ID);
await this.AgoraClient.unpublish(currentVideoTrack);
webrtcStates.value.currentUsingCameraName = '';
videoTrack.close();
}
if (v) {
try {
const screenAudioTrack = await AgoraRTC.createScreenVideoTrack({}, 'disable');
screenAudioTrack.play(this.localPlayerId, {fit: 'contain'});
await this.AgoraClient.publish(screenAudioTrack);
webrtcStates.value.currentUsingCameraName = '';
screenAudioTrack.on('track-ended', async () => {
await this.toggleScreenShare(false, endFunc, failedFunc, pageHideFunc)
endFunc()
})
if (!document.hasFocus()) {
if (typeof pageHideFunc === 'function') {
pageHideFunc()
}
}
} catch (e) {
console.log('出现错误', e);
if (typeof failedFunc === 'function') {
failedFunc()
}
await this.toggleScreenShare(false, endFunc, failedFunc, pageHideFunc)
}
} else {
this.data.localTracks.videoTrack = await AgoraRTC.createCameraVideoTrack();
webrtcStates.value.currentUsingCameraName = this.data.localTracks.videoTrack._deviceName;
this.data.localTracks.videoTrack.play(this.localPlayerId, {fit: 'contain'})
await this.AgoraClient.publish(this.data.localTracks.videoTrack);
}
}
async currentUserToggleVoiceChatOnly(v) {
if (v) {
const videoTrack = this.AgoraClient.localTracks.find(i => i.trackMediaType === 'video');
videoTrack.stop();
await this.AgoraClient.unpublish(videoTrack);
webrtcStates.value.currentUsingCameraName = '';
videoTrack.close();
this.data.localTracks.videoTrack = undefined;
} else {
this.data.localTracks.videoTrack = await AgoraRTC.createCameraVideoTrack();
webrtcStates.value.currentUsingCameraName = this.data.localTracks.videoTrack._deviceName;
await this.AgoraClient.publish(this.data.localTracks.videoTrack);
this.data.localTracks.videoTrack.play(this.localPlayerId, {fit: 'contain'})
}
}
async leave() {
this.#clearTracks()
await this.AgoraClient.leave();
console.log('成功离开频道')
}
async forceReplay(id, vid) {
const foundUser = this.AgoraClient.remoteUsers.find(i => i.uid.toString() === id.toString());
console.log('强制播放用户', foundUser)
await foundUser?.videoTrack?.play(vid);
}
async switchDeviceForCamera(id) {
if (typeof this.data.localTracks.videoTrack !== void 0) {
await this.data.localTracks.videoTrack.setDevice(id);
webrtcStates.value.currentUsingCameraName = webrtcStates.value.cameraDeviceSet.find(a => a.deviceId === id)?.label
}
}
async preload() {
return new Promise((resolve) => {
const v = setInterval(() => {
if (window.AgoraRTC) {
clearInterval(v);
if (this.notUploadLog) {
AgoraRTC.disableLogUpload();
}
AgoraRTC.setLogLevel(this.logLevel);
this.AgoraClient = AgoraRTC.createClient({mode: this.mode, codec: this.codec});
this.AgoraClient.on('volume-indicator', function (volumes) {
chatChannelState.value.volumeSet = volumes;
})
console.log('client 已经创建', this.AgoraClient)
window.navigator.mediaDevices.enumerateDevices()
.then(function (info) {
const wholeCameraSet = info.filter(a => a.kind === 'videoinput');
webrtcStates.value.cameraDeviceSet = wholeCameraSet;
webrtcStates.value.isCameraAttached = wholeCameraSet.length > 0
webrtcStates.value.isMicroAttached = info.filter(a => a.kind === 'audioinput').length > 0;
console.log('当前设备状况', info, chatChannelState.value)
})
AgoraRTC.onCameraChanged = function () {
window.navigator.mediaDevices.enumerateDevices()
.then(function (info) {
const wholeCameraSet = info.filter(a => a.kind === 'videoinput');
webrtcStates.value.cameraDeviceSet = wholeCameraSet;
webrtcStates.value.isCameraAttached = wholeCameraSet.length > 0
})
}
AgoraRTC.onMicrophoneChanged = function () {
window.navigator.mediaDevices.enumerateDevices()
.then(function (info) {
webrtcStates.value.isMicroAttached = info.filter(a => a.kind === 'audioinput').length > 0;
})
}
this.AgoraClient.on('user-joined', (user) => {
const uidS = user.uid.toString()
const targetUser = userStates.value.onlineContacts.find(a => a.fromID.toString() === uidS);
console.log('在线用户加入了频道', targetUser)
targetUser.callState = 'calling'
if (!chatChannelState.value.currentChatters.includes(uidS)) {
chatChannelState.value.currentChatters.push(uidS)
}
})
this.AgoraClient.on('user-left', (user) => {
const uidS = user.uid.toString()
const targetUser = userStates.value.onlineContacts.find(a => a.fromID.toString() === uidS);
console.log('在线用户离开了频道', targetUser)
if (chatChannelState.value.currentChatters.includes(uidS)) {
chatChannelState.value.currentChatters.splice(chatChannelState.value.currentChatters.indexOf(uidS), 1)
}
})
this.AgoraClient.on('user-published', (user, mediaType) => {
console.log('检测到远程用户发布媒体', user, mediaType);
if (user.uid.toString() !== this.data.uid.toString()) {
this.#subscribe(user, mediaType)
}
if (mediaType === 'audio') {
chatChannelState.value.mutedUserIdSet = chatChannelState.value.mutedUserIdSet.filter(i => i !== user.uid);
}
})
this.AgoraClient.on('user-unpublished', async (user, mediaType) => {
console.log('检测到远程用户取消发布媒体', user, mediaType);
if (user.uid.toString() !== this.data.uid.toString()) {
await this.AgoraClient.unsubscribe(user, mediaType);
}
if (mediaType === 'audio') {
if (!chatChannelState.value.mutedUserIdSet.includes(user.uid)) {
chatChannelState.value.mutedUserIdSet.push(user.uid);
}
user?.audioTrack?.stop()
}
if (mediaType === 'video') {
user?.videoTrack?.stop()
}
})
this.AgoraClient.on('network-quality', quality => {
if (chatChannelState.value.currentChatters.length === 0) {
return;
}
const {downlinkNetworkQuality: down, uplinkNetworkQuality: up} = quality
webrtcStates.value.networkQuality = {
down, up
};
})
resolve();
}
})
})
}
}
\ No newline at end of file
import {Agora} from "AnyR/agora";
import {chatChannelState, isUserHost} from "AnyR/states/chatChannelStates";
import {userStates} from "AnyR/states/wsStates";
import {generateMessageId} from "AnyR/utils/generateMessageId";
import {CallState} from "AnyR/constants/chatChannelRelated";
import {clearStateOfChatChannel} from "AnyR/functionals/chatChannel";
import {handleCommonCall} from "AnyR/functionals/callMsg";
import {addMessageItemInMeeting} from "AnyR/functionals/callMsg";
import {convertObj2FU} from "AnyR/utils/cnvertObjectToFormData";
export class AgoraHandle {
agoraOptions = {}
agoraApp = null
AnyRemote = null
recordConfig = {}
currentRecordingData = {}
constructor(AnyRemote) {
this.AnyRemote = AnyRemote;
}
async configure(options = {
notUploadLog: false,
logLevel: 0,
codec: 'vp8',
mode: 'rtc',
appId: '',
localPlayerId: 'localPlayerId',
remotePlayerPrefix: 'remotePlayerPrefix',
localAp: null
}, recordConfig = {
callBackUrl: 'https://hna-platform.anyremote.cn/call/saveScreenRecordNoToken',
fileDomain: 'https://video.anyremote.cn:444',
recordStartUrl: 'https://video.anyremote.cn:8081/recorder/v1/start',
recordStopUrl: 'https://video.anyremote.cn:8081/recorder/v1/stop'
}) {
this.recordConfig = recordConfig
this.agoraOptions = options;
this.agoraApp = new Agora(options)
await this.agoraApp.preload();
}
onMessageHandle(msgData) {
let {msgType, toID, fromID, fromName} = msgData
let channelID = ''
fromName = window.decodeURIComponent(fromName);
let currentId = userStates.value.currentUserId
switch (msgType) {
case 'WannaJoin': {
console.log('某人想要你加入频道', msgData)
this.sendCallRequest(fromID, msgData.msgData.channelId, {
isMR: true, chatRoomName: msgData.msgData.chatRoomName
})
break;
}
case 'BlinkSpot': {
console.log('有用户要求闪烁blink', msgData)
chatChannelState.value.blinkSpotSet.push(msgData.msgData)
break;
}
case 'VoiceChatOnly': {
console.log('有用户仅语音聊天', msgData)
if (!chatChannelState.value.voiceChatOnlySet.includes(fromID)) {
chatChannelState.value.voiceChatOnlySet.push(fromID)
}
break
}
case "NotVoiceChatOnly": {
console.log('有用户取消仅语音聊天', msgData)
if (chatChannelState.value.voiceChatOnlySet.includes(fromID)) {
chatChannelState.value.voiceChatOnlySet.splice(chatChannelState.value.voiceChatOnlySet.indexOf(fromID), 1)
}
break
}
case 'Recording': {
console.log('有用户发起录制', msgData)
if (currentId !== fromID) {
console.log('其他用户发起了录制', fromName)
}
chatChannelState.value.recordingData = {
id: fromID, name: fromName
}
break
}
case "NotRecording": {
console.log('有用户取消录制', msgData)
chatChannelState.value.recordingData = {}
if (currentId !== fromID) {
console.log('其他用户取消了录制', fromName)
}
break;
}
case "CmdCall": {
console.log('主动呼叫他人的反馈', msgData);
if (chatChannelState.value.currentState === CallState.calling) {
console.log('正在通话中,无须改变状态')
break;
}
handleCommonCall(msgData, toID, fromID)
if (!chatChannelState.value.currentChatters.includes(toID)) {
chatChannelState.value.currentChatters.push(toID)
}
if (!chatChannelState.value.currentChatters.includes(fromID)) {
chatChannelState.value.currentChatters.push(fromID)
}
chatChannelState.value.channelInitiator = toID;
chatChannelState.value.currentState = CallState.callOut
break
}
case "Call" : {
console.log('被别人呼叫的反馈', msgData)
if (chatChannelState.value.currentState === CallState.calling) {
console.log('正在通话中,无须改变状态')
break;
}
handleCommonCall(msgData)
if (!chatChannelState.value.currentChatters.includes(fromID)) {
chatChannelState.value.currentChatters.push(fromID)
}
chatChannelState.value.channelInitiator = fromID
toID.split(',')
.forEach(function (id) {
if (!chatChannelState.value.currentChatters.includes(id)) {
chatChannelState.value.currentChatters.push(id)
}
});
if (fromID !== currentId) {
chatChannelState.value.currentState = CallState.callIn
} else {
chatChannelState.value.currentState = CallState.callOut
}
if (window.Notification) {
window.Notification.requestPermission()
.then(function (result) {
if (result === 'granted') {
const a = new window.Notification(`收到${msgData.fromName}呼叫请求`, {
body: '收到呼叫请求,点击回到标签页',
});
a.addEventListener('click', function () {
a.close();
window.focus()
})
}
})
}
break;
}
case 'CmdHangup': {
console.log('收到服务器挂断指令', msgData)
if (currentId === toID) {
this.agoraApp.leave()
.then(function () {
clearStateOfChatChannel()
})
}
break
}
case "CmdCancelCall" : {
console.log('呼叫方取消呼叫', msgData)
if (currentId === toID) {
if (chatChannelState.value.currentState === CallState.callOut) {
this.agoraApp.leave()
.then(function () {
clearStateOfChatChannel()
})
break
}
if (chatChannelState.value.currentState === CallState.calling) {
fromID.split(',')
.forEach(function (id) {
chatChannelState.value.currentChatters = chatChannelState.value.currentChatters.filter(function (item) {
return item !== id;
})
})
}
}
break
}
case "CmdConnect" : {
console.log('收到服务器主动连接指令', msgData)
channelID = msgData.msgData.channelID;
chatChannelState.value.chatChannelId = channelID;
chatChannelState.value.rtcToken = msgData.msgData.rtcToken
chatChannelState.value.currentState = CallState.calling
break
}
case 'CmdRefuse' : {
console.log('对方拒接了', msgData)
const targetPersonnel = userStates.value.onlineContacts.find(function (q) {
return q.fromID === fromID
})
if (targetPersonnel) {
console.log('有人拒绝了你的对话邀请', targetPersonnel.fromName, targetPersonnel)
}
chatChannelState.value.currentChatters = chatChannelState.value.currentChatters.filter(function (item) {
return item !== fromID;
})
console.log('剩下来的会议参会人', chatChannelState.value.currentChatters)
if (chatChannelState.value.currentChatters.length === 1 && chatChannelState.value.currentChatters[0] === userStates.value.currentUserId) {
this.AnyRemote.sendWSFromCall('0', 'CancelCall')
}
break
}
case 'CmdLeave': {
console.log('某人离开了', fromID)
if (toID === userStates.value.currentUserId) {
console.log('主持人提出了你!');
this.agoraApp.leave()
.then(function () {
clearStateOfChatChannel()
})
break
}
const targetPersonnel = userStates.value.onlineContacts.find(function (q) {
return q.fromID === fromID
})
if (targetPersonnel) {
console.log('有人退出了对话', targetPersonnel.fromName, targetPersonnel)
}
chatChannelState.value.currentChatters = chatChannelState.value.currentChatters.filter(function (item) {
return item !== fromID;
})
break
}
case 'CmdEndMeeting' : {
console.log('主持人要求结束通话', msgData)
if (!isUserHost.value) {
console.log('主持人结束了通话,之后可以再次发起')
}
this.agoraApp.leave()
.then(function () {
clearStateOfChatChannel()
})
break
}
case "CmdKickOut" : {
console.log('主持人将某人提出房间', msgData);
const targetPersonnel = userStates.value.onlineContacts.find(function (q) {
return q.fromID === fromID
})
chatChannelState.value.currentChatters = chatChannelState.value.currentChatters.filter(function (item) {
return item !== msgData.msgData.toID
})
if (msgData.msgData.toID !== currentId) {
console.log(`主持人踢出了${targetPersonnel.fromName}`)
} else {
console.log('主持人踢出了你')
}
break;
}
case "CmdMuteAll": {
console.log('主持人要求所有人静音', msgData)
this.agoraApp.currentUserToggleMute(true)
chatChannelState.value.currentChatters.forEach(function (id) {
if (!chatChannelState.value.mutedUserIdSet.includes(id)) {
chatChannelState.value.mutedUserIdSet.push(id)
}
})
break
}
case 'MuteSelf':
case 'CmdMuteSelf': {
console.log('某人静音了自己', msgData)
chatChannelState.value.mutedUserIdSet.push(fromID)
if (fromID === currentId) {
this.agoraApp.currentUserToggleMute(true)
}
break
}
case 'ScreenShareStart': {
console.log('某人开始发起屏幕共享', msgData)
chatChannelState.value.screenShareId = fromID
break
}
case 'ScreenShareEnd': {
console.log('某人停止了屏幕共享', msgData)
chatChannelState.value.screenShareId = ''
chatChannelState.value.screenCaptureShotURL = ''
break
}
case 'MarkBg': {
console.log('某人要求截图', msgData)
chatChannelState.value.screenshotInitiatorId = msgData.msgData.initId;
chatChannelState.value.screenshotURL = msgData.msgData.url;
break
}
case 'MarkImage': {
console.log('接收到截图资料点', msgData)
if (currentId !== fromID) {
chatChannelState.value.screenshotRecord = {
...chatChannelState.value.screenshotRecord,
[fromID]: msgData.msgData.records
}
}
break
}
case 'CloseMark': {
console.log('标注者要求退出', msgData)
chatChannelState.value.screenshotInitiatorId = ''
chatChannelState.value.screenshotRecord = {}
chatChannelState.value.screenshotURL = ''
break
}
case 'EndScreenShareMark': {
console.log('屏幕共享要求退出', msgData)
chatChannelState.value.screenCaptureRecord = {}
chatChannelState.value.screenCaptureShotURL = ''
break
}
case 'StartScreenShareMark': {
console.log('有用户发起了屏幕共享截图', msgData)
chatChannelState.value.screenCaptureShotURL = msgData.msgData.url;
break
}
case 'ChatAudio':
case 'ChatFile':
case 'ChatTxt':
case 'ChatVideo':
case 'ArchiveImage':
case 'StoreScreenShareMark':
case 'ChatImage':
{
console.log('收到ws消息点', msgData)
addMessageItemInMeeting(msgData)
break
}
case 'ContinueScreenShareMark': {
if (fromID === toID) {
break
}
console.log('用户发送屏幕共享截图标记点', msgData)
if (currentId !== fromID) {
chatChannelState.value.screenCaptureRecord = {
...chatChannelState.value.screenCaptureRecord,
[fromID]: msgData.msgData.records
}
}
break;
}
case 'UnMuteSelf':
case 'CmdUnMuteSelf': {
console.log('某人取消静音', fromID)
if (fromID === currentId) {
this.agoraApp.currentUserToggleMute(false)
}
chatChannelState.value.mutedUserIdSet = chatChannelState.value.mutedUserIdSet.filter(function (q) {
return q !== fromID
})
break;
}
case 'CmdMute': {
console.log('主持人要求静音', msgData);
if (fromID === currentId) {
this.agoraApp.currentUserToggleMute(true)
}
if (!chatChannelState.value.mutedUserIdSet.includes(fromID)) {
chatChannelState.value.mutedUserIdSet.push(fromID)
}
break
}
default:
break;
}
}
sendCallRequest(toID) {
const channelId = chatChannelState.value.chatChannelId
this.AnyRemote.sendWSFromCall(toID, 'Call', undefined, channelId)
}
async forceReplay(id) {
await this.agoraApp.forceReplay(id, `${this.agoraOptions.remotePlayerPrefix}${id}`)
}
async joinChatRoom() {
await this.agoraApp.join(
chatChannelState.value.chatChannelId,
'',
Number(userStates.value.currentUserId)
)
}
sendTextInChatRoom(text) {
this.AnyRemote.sendWSFromCall(
'-2',
'ChatTxt',
{
tip: text,
quoteId: '',
channelID: chatChannelState.value.chatChannelId,
fromName: userStates.value.currentUserName,
msgId: generateMessageId()
}
)
}
sendImage(data) {
const channelID = chatChannelState.value.chatChannelId;
const fromName = userStates.value.currentUserName
this.AnyRemote.sendWSFromCall(
'-2',
'ChatImage', {
msgId: generateMessageId(),
quoteId: "",
channelID,
fromName,
tip: {
fileUrl: data.fileUrl,
fileName: data.fileName,
fileSize: data.fileSize,
fileType: "image"
}
}
)
}
sendVideo(data, fileType = 'video') {
const channelID = chatChannelState.value.chatChannelId;
const fromName = userStates.value.currentUserName
const md = {
msgId: generateMessageId(),
quoteId: "",
channelID,
fromName,
tip: {
fileUrl: data.fileUrl,
fileName: data.fileName,
fileSize: data.fileSize,
fileType
}
}
this.AnyRemote.sendWSFromCall(
'-2',
'ChatVideo', md
)
}
endMark(cancelType = 'video') {
if (cancelType === 'video') {
this.AnyRemote.sendWSFromCall('-2', 'CloseMark')
} else {
this.AnyRemote.sendWSFromCall('-2', 'EndScreenShareMark')
}
}
startMark(url, type = 'video') {
this.AnyRemote.sendWSFromCall(
'-2',
type === 'video' ? 'MarkBg' : "StartScreenShareMark",
{
url, initId: userStates.value.currentUserId
}
)
}
continueMark(records, type = 'video') {
this.AnyRemote.sendWSFromCall(
'-2',
type === 'video' ? 'MarkImage' : "ContinueScreenShareMark",
{
records
}
)
}
cancelCurrentCall() {
const toBeSentUserId = chatChannelState.value.currentChatters.filter(a => a !== userStates.value.currentUserId);
this.AnyRemote.sendWSFromCall(toBeSentUserId.join(','), 'CancelCall')
}
cancelExactCall(id) {
this.AnyRemote.sendWSFromCall(id.toString(), 'CancelCall')
}
refuseCurrentCall() {
const toID = chatChannelState.value.currentChatters[0]
this.AnyRemote.sendWSFromCall(toID.toString(), 'Refuse')
}
endCurrentCall() {
this.AnyRemote.sendWSFromCall('0', 'EndMeeting')
}
hangUpCurrentCall() {
this.AnyRemote.sendWSFromCall('0', 'Hangup')
}
acceptCurrentCall() {
const [toId, rtcToken, channelID] = [
chatChannelState.value.currentChatters[0], chatChannelState.value.rtcToken, chatChannelState.value.chatChannelId
]
this.AnyRemote.sendWSFromCall(toId, 'Connect', {rtcToken, channelID})
}
toggleMuteSelf(v) {
this.AnyRemote.sendWSFromCall(
'-2',
v ? 'MuteSelf' : "UnMuteSelf"
)
}
toggleVoiceChatOnly(v) {
this.AnyRemote.sendWSFromCall(
'-2',
v ? "VoiceChatOnly" : "NotVoiceChatOnly"
)
}
muteAllUser() {
this.AnyRemote.sendWSFromCall(
'-2',
'MuteAll'
)
}
muteTargetUser(pid) {
this.AnyRemote.sendWSFromCall(pid.toString(), 'Mute')
}
kickCurrentUser(toId) {
this.AnyRemote.sendWSFromCall(toId.toString(), 'KickOut', {toID: toId})
}
async recordCurrent() {
const channel_id = chatChannelState.value.chatChannelId
const uid_screen = userStates.value.currentUserId
const record_mode = '1'
const reqData = {
appid: this.agoraOptions.appId,
channel_id,
uid_screen,
callback_url: this.recordConfig.callBackUrl,
record_mode,
file_domain: this.recordConfig.fileDomain
};
this.currentRecordingData = {
channel_id, uid_screen, record_mode
}
const resp = await window.fetch(
this.recordConfig.recordStartUrl, {
method: 'post',
headers: {
'content-type': "application/x-www-form-urlencoded"
},
body: convertObj2FU(reqData)
}
)
const res = await resp.json()
console.log('开始录制返回结果', res)
if (res.success) {
chatChannelState.value.recordSid = res.data.sid;
this.AnyRemote.sendWSFromCall('-2', 'Recording')
return true
}
return false
}
async stopRecordCurrent() {
const {channel_id, uid_screen, record_mode} = this.currentRecordingData
const reqData = {
appid: this.agoraOptions.appId,
channel_id,
uid_screen,
callback_url: this.recordConfig.callBackUrl,
record_mode,
file_domain: this.recordConfig.fileDomain
};
const hautResp = await window.fetch(
this.recordConfig.recordStopUrl,
{
method: 'post',
headers: {
'content-type': "application/x-www-form-urlencoded"
},
body: convertObj2FU(reqData)
}
);
const resp = await hautResp.json()
console.log('结束录制返回结果', resp)
this.AnyRemote.sendWSFromCall('-2', 'NotRecording')
if (resp.success) {
return resp.data
}
return false
}
async archiveMark(fileData, type = 'video') {
this.AnyRemote.sendWSFromCall(
'-2',
type === 'video' ? 'ArchiveImage' : "StoreScreenShareMark",
{
msgId: generateMessageId(),
tip: {
fileType: 'image',
fileUrl: fileData.fileUrl,
fileName: `截图标注-${new Date().toLocaleString()}`,
fileSize: fileData.fileSize
},
quoteId: "",
channelID: chatChannelState.value.chatChannelId,
fromName: userStates.value.currentUserName
}
)
}
screenShareHandle(v) {
this.AnyRemote.sendWSFromCall(
'-2',
v ? "ScreenShareStart" : "ScreenShareEnd"
)
}
sendBlinkSpot(v) {
this.AnyRemote.sendWSFromCall(
'-2',
'BlinkSpot',
v
)
}
}
\ No newline at end of file
export class SocketBroadcaster {
bc = null;
msgListener = [];
constructor(name) {
this.bc = new BroadcastChannel(name);
this.bc.onmessage = (e) => {
for (const f of this.msgListener) {
f(e.data);
}
}
window.addEventListener('beforeunload', function () {
this.destroy();
}.bind(this))
}
addListener(f) {
if (!this.msgListener.includes(f))
this.msgListener.push(f)
}
removeListener(f) {
this.msgListener = this.msgListener.filter((f2) => f2 !== f)
}
send(msg) {
if (this.bc) {
this.bc.postMessage(JSON.stringify(msg))
}
}
destroy() {
if (this.bc) {
this.bc.close()
this.bc = null;
this.msgListener = [];
}
}
}
\ No newline at end of file
export const CallState = {
callIn: 'callIn',
callOut: "callout",
calling: "calling",
idle: "idle",
}
\ No newline at end of file
import {chatChannelState} from "AnyR/states/chatChannelStates";
import {getNowDate} from "AnyR/utils/dateRelated";
export function handleCommonCall(msgData) {
if (msgData.msgData?.isMR) {
chatChannelState.value.isUnderMeetingRoom = true;
chatChannelState.value.chatRoomName = msgData.msgData.chatRoomName;
chatChannelState.value.chatChannelId = msgData.msgData.channelId;
}
if (msgData.msgData?.isGroup) {
chatChannelState.value.isUnderGroupChat = true;
chatChannelState.value.chatRoomName = msgData.msgData.chatRoomName;
chatChannelState.value.chatChannelId = msgData.msgData.channelId;
}
}
function convertTypeLocally(item) {
if (item === 'ChatTxt')
return 'txt'
if (['ChatImage', 'StoreScreenShareMark', 'ArchiveImage'].includes(item)) {
return 'image'
}
if (item === 'ChatVideo')
return 'video'
if (item === 'ChatAudio')
return 'audio'
return 'file'
}
export function addMessageItemInMeeting(data) {
const toBeMerged = {
type: convertTypeLocally(data.msgType),
title: data.msgData.tip,
from_name: data.fromName ? decodeURIComponent(data.fromName)
: data.msgData.fromName ? decodeURIComponent(data.msgData.fromName)
: '未知用户',
uid: data.fromID,
record_id: data.msgData.msgId,
url: data.msgData.tip,
happened_time: getNowDate()
}
if (!chatChannelState.value.messageQueue.find(a => a.record_id === toBeMerged.record_id)) {
chatChannelState.value.messageQueue.push(toBeMerged)
}
}
\ No newline at end of file
import {chatChannelState} from "AnyR/states/chatChannelStates";
import {CallState} from "AnyR/constants/chatChannelRelated";
export function clearStateOfChatChannel() {
chatChannelState.value.volumeSet = [];
chatChannelState.value.voiceChatOnlySet = [];
chatChannelState.value.currentChatters = [];
chatChannelState.value.mutedUserIdSet = [];
chatChannelState.value.blinkSpotSet = [];
chatChannelState.value.chatChannelId = '';
chatChannelState.value.recordSid = "";
chatChannelState.value.recordingData = {};
chatChannelState.value.currentState = CallState.idle;
chatChannelState.value.isUnderMeetingRoom = false;
chatChannelState.value.chatRoomName = '';
chatChannelState.value.isUnderGroupChat = false;
chatChannelState.value.channelInitiator = '';
chatChannelState.value.rtcToken = "";
chatChannelState.value.screenShareId = "";
chatChannelState.value.screenCaptureShotURL = "";
chatChannelState.value.screenshotInitiatorId = "";
chatChannelState.value.screenshotURL = "";
chatChannelState.value.screenshotRecord = {};
chatChannelState.value.screenCaptureRecord = {};
chatChannelState.value.messageQueue = [];
}
\ No newline at end of file
import {WSInt} from "AnyR/ws";
import {AgoraHandle} from "AnyR/agoraHandle";
import {userStates} from "AnyR/states/wsStates";
export class AnyRemote {
wsInt = null
agora = null
configureWS(url, tabVisibleCB = () => true, connectionLostCB = () => true, wsSocketChannelName = '') {
this.wsInt = new WSInt(url, this.onMessageGeneral.bind(this), tabVisibleCB, connectionLostCB, wsSocketChannelName)
this.wsInt.connect()
}
sendWSFromCall(toID, msgType, msgData, channelID) {
this.wsInt.send({
fromID: userStates.value.currentUserId,
fromName: userStates.value.currentUserName,
msgData,
toID,
channelID,
msgType
})
}
/**
* 配置Agora
* @param options
* @param recordConfig
* @return {Promise<void>}
*/
async configureAgora(options = {
notUploadLog: false,
logLevel: 0,
codec: 'vp8',
mode: 'rtc',
appId: '',
localPlayerId: 'localPlayerId',
remotePlayerPrefix: 'remotePlayerPrefix',
localAp: null
}, recordConfig = {
callBackUrl: 'https://hna-platform.anyremote.cn/call/saveScreenRecordNoToken',
fileDomain: 'https://video.anyremote.cn:444',
recordStartUrl: 'https://video.anyremote.cn:8081/recorder/v1/start',
recordStopUrl: 'https://video.anyremote.cn:8081/recorder/v1/stop'
}) {
this.agora = new AgoraHandle(this);
await this.agora.configure(options, recordConfig)
}
onMessageGeneral(data) {
let {msgType} = data
if (msgType === 'ForceUpdateOnlineUsers') {
console.log('需要主动拉取在线用户列表', data)
this.sendWSFromCall('0', 'GetCompanyUserList')
} else if (msgType === 'GetCompanyUserList' || msgType === 'CmdUpdateUserList') {
console.log('在线用户列表更新', data)
userStates.value.onlineContacts = data.msgData
}
if (this.agora) {
this.agora.onMessageHandle(data)
}
}
}
export function useAnyR() {
return inject("AnyR")
}
\ No newline at end of file
import {AnyRemote} from "./index";
import {watch} from "vue";
export default {
install(app, options) {
const anyRemote = new AnyRemote()
const {wsOpts, agoraConfig, recordConfig, wsOpen} = options
watch(() => wsOpen.value, function (value) {
console.log('value here', value)
if (value) {
const {url, tabVisibleCB, connectionLostCB, wsSocketChannelName} = wsOpts()
anyRemote.configureWS(
url, tabVisibleCB, connectionLostCB, wsSocketChannelName
);
}
}, {
immediate: true
})
app.provide('AnyR', anyRemote);
anyRemote.configureAgora(agoraConfig, recordConfig)
.then(function () {
})
}
}
\ No newline at end of file
import {computed, ref} from "vue";
import {CallState} from "AnyR/constants/chatChannelRelated";
import {userStates} from "AnyR/states/wsStates";
export const chatChannelState = ref({
volumeSet: [],
voiceChatOnlySet: [],
currentChatters: [],
mutedUserIdSet: [],
blinkSpotSet: [],
chatChannelId: '',
recordSid: "",
recordingData: {},
currentState: CallState.idle,
isUnderMeetingRoom: false,
chatRoomName: '',
isUnderGroupChat: false,
channelInitiator: '',
rtcToken: "",
screenShareId: "",
screenCaptureShotURL: "",
screenshotInitiatorId: "",
screenshotURL: "",
screenshotRecord: {},
screenCaptureRecord: {},
messageQueue: []
})
export const isUserHost = computed(function () {
return userStates.value.onlineContacts.find(a=>a.fromID === userStates.value.currentUserId)?.isHost === '1'
})
export const isCurrentUserMuted = computed(function () {
const allMutedId = chatChannelState.value.mutedUserIdSet;
return allMutedId.includes(userStates.value.currentUserId)
})
export const allOtherChattersIdSet = computed(function () {
return chatChannelState.value.currentChatters.filter(a=>a!==userStates.value.currentUserId)
})
export const allChattersInCompany = computed(function () {
return userStates.value.onlineContacts
.map(a=> {
return {
...a,
isAlreadyInChat: allOtherChattersIdSet.value.includes(a.fromID),
callable: a.callState === 'idle'
}
})
})
\ No newline at end of file
import {ref} from "vue";
export const wsShouldOpen = ref(false)
\ No newline at end of file
import {ref} from "vue"
export const webrtcStates = ref({
cameraDeviceSet: [],
networkQuality: {},
currentUsingCameraName: "",
isCameraAttached: false,
isMicroAttached: false,
})
\ No newline at end of file
import {ref} from "vue";
export const userStates = ref({
onlineContacts: [],
currentUserId: '',
currentUserName: '',
})
\ No newline at end of file
export function convertObj2FU(obj) {
return Object.entries(obj).reduce((q, w) => {
// @ts-ignore
return q.concat(`${encodeURIComponent(w[0])}=${encodeURIComponent(w[1])}`)
}, []).join('&')
}
\ No newline at end of file
export function getNowDate() {
const d = new Date()
return `${d.getFullYear()}-${(d.getMonth() + 1).toString().padStart(2, '0')}-${d.getDate().toString().padStart(2, '0')} ${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}:${d.getSeconds().toString().padStart(2, '0')}`
}
\ No newline at end of file
import {makeSID} from "AnyR/utils/makeSID";
export function generateMessageId() {
return `sid${makeSID(16)}${Date.now()}`
}
\ No newline at end of file
export const makeSID = function (length = 32) {
if (window.crypto && window.crypto.getRandomValues !== undefined) {
const buffer = new Uint8Array(length)
window.crypto.getRandomValues(buffer)
return buffer.reduce((q, w) => q + w.toString(16).padStart(2, '0'), "")
}
return Math.random() * 1000 + Math.random()
}
const BrowserKeyId = 'B-K-ID-$$$';
export function getBrowserDeviceId() {
let browserId = localStorage[BrowserKeyId];
if (!browserId) {
browserId = makeSID(16);
localStorage[BrowserKeyId] = browserId;
}
return browserId
}
\ No newline at end of file
export const otherTabSend = 'OtherWSSend'
export const currentWSTabReceive = 'currentWSTabReceive'
export const currentTabIdNameGet = 'NameGet'
export const chatMessageAhead = 'PutChat'
export const wsTabCloseSet = 'WSTabClose'
export const wsOtherLoginNow = 'OtherLoginNow'
export const otherTabClose = 'otherClose'
export const wsConnected = 'WSConnected'
export const wsQueryForMain = 'wsQueryForMain';
export const wsAnswerForMain = 'wsAnswerForMain'
\ No newline at end of file
import {SocketBroadcaster} from "AnyR/bc";
import {
currentTabIdNameGet,
currentWSTabReceive,
otherTabClose,
otherTabSend,
wsAnswerForMain,
wsConnected,
wsOtherLoginNow,
wsQueryForMain,
wsTabCloseSet,
} from "AnyR/ws/eventTypes";
import {userStates} from "AnyR/states/wsStates";
export class WSInt {
static BCName = 'WSInt'
static subWindowKeyIdentifierInWindow = '$SubWSInt'
scName = ''
ws = null
url = ''
bc = null
allWSNameSet = []
timeIndex = Number.NEGATIVE_INFINITY
countDownTimerForQueryWSOwnershipTag = 0
isWSTabShifting = false
bufferedDataWhenShift = []
wsCallQueuedData = []
currentServerHeartReceivedTime = 0
heartLogGroup = []
isConnectionFailed = false;
connectionFailedContinuousTimes = 0
heartFailedCountDownMutex = 3
heartTimer = 0
nextHeartNotReceiveTimer = 0;
enforceReconnect = false
isReOpen = false
lastNameBeforeCurrentTabBeingMainTab = ''
constructor(url,
onMessageFunc,
tabVisibleCB = () => true,
connectionLostCB = () => true,
wsSocketChannelName = ''
) {
this.url = url;
this.onMessageFunc = onMessageFunc;
this.whenTabVisible = tabVisibleCB
this.connectionLostCB = connectionLostCB
this.scName = wsSocketChannelName || WSInt.BCName
this.#setupSBC();
window.addEventListener('beforeunload', this.#unloadHandle.bind(this));
window.addEventListener('online', () => {
console.log('重新连接网络')
if (!this.currentTabWSName && this.url) {
this.connect()
}
})
window.addEventListener('offline', () => {
if (!this.currentTabWSName) {
this.close(true)
}
})
document.addEventListener('visibilitychange', () => {
if (this.currentTabWSName)
return;
if (document.visibilityState === 'visible') {
const nowTime = Date.now()
const timeInterval = nowTime - this.currentServerHeartReceivedTime
console.log('上一次心跳判断', this.currentServerHeartReceivedTime, timeInterval)
const shouldPersist = this.whenTabVisible()
if (this.isConnectionFailed && this.connectionFailedContinuousTimes === 5) {
console.log('连续5次没有成功连接,挂断ws')
this.ws?.close()
this.ws = null;
return;
}
if (this.currentServerHeartReceivedTime !== 0 && shouldPersist && timeInterval > 7000 && this.heartFailedCountDownMutex === 0) {
console.log('没有连续收到心跳,在页面被激活情况下,应当强制重连')
this.enforceReconnect = true;
this.#persistReopen()
}
}
})
this.connect();
}
get currentTabWSName() {
return window.sessionStorage[WSInt.subWindowKeyIdentifierInWindow]
}
set currentTabWSName(v) {
window.sessionStorage[WSInt.subWindowKeyIdentifierInWindow] = v;
}
connectionLostCB = () => true
whenTabVisible = () => {
return true
}
onMessageFunc = () => {
}
#reSetUpWS() {
this.lastNameBeforeCurrentTabBeingMainTab = this.currentTabWSName
this.currentTabWSName = '';
this.connect()
}
#setupSBC() {
this.bc = new SocketBroadcaster(this.scName);
this.bc.addListener((msg) => {
const v = JSON.parse(msg);
if (v.type === wsConnected) {
const {data: name} = v;
if (name) {
this.allWSNameSet = this.allWSNameSet.filter(a => a !== name);
}
} else if (v.type === currentTabIdNameGet) {
this.allWSNameSet.push(v.data);
this.allWSNameSet.sort(function (a, q) {
const at = a.split('-')[0] * 1;
const qt = q.split('-')[0] * 1;
if (qt && at) {
return at - qt;
}
return a - q;
});
if (!window[WSInt.subWindowKeyIdentifierInWindow]) {
this.bc.send({
type: wsAnswerForMain
})
}
if (this.timeIndex === Number.NEGATIVE_INFINITY && this.currentTabWSName) {
const currentTime = Number(this.currentTabWSName.split('-')[0]);
this.timeIndex = this.allWSNameSet.find(a => {
return currentTime > Number(a.split('-')[0]);
});
clearTimeout(this.countDownTimerForQueryWSOwnershipTag)
this.countDownTimerForQueryWSOwnershipTag = setTimeout(() => {
this.bc.send({
type: wsAnswerForMain
})
this.#reSetUpWS()
}, 5000 + this.timeIndex * 1000);
}
} else if (v.type === otherTabClose) {
const {data: name} = v;
if (name) {
this.allWSNameSet.splice(this.allWSNameSet.indexOf(name), 1);
this.allWSNameSet.sort(function (a, q) {
const at = a.split('-')[0] * 1;
const qt = q.split('-')[0] * 1;
if (qt && at) {
return at - qt;
}
return a - q;
});
}
} else if (v.type === wsQueryForMain) {
if (!this.currentTabWSName) {
this.bc.send({
type: wsAnswerForMain
})
}
} else if (v.type === wsAnswerForMain) {
clearTimeout(this.countDownTimerForQueryWSOwnershipTag)
}
if (this.currentTabWSName) {
if (this.isWSTabShifting && v.type === otherTabSend) {
this.bufferedDataWhenShift.push(v.data)
}
if (v.type === currentWSTabReceive) {
} else if (v.type === wsTabCloseSet) {
this.isWSTabShifting = true;
const allNamesP = v.data;
if (allNamesP[0] && this.currentTabWSName === allNamesP[0]) {
this.#reSetUpWS()
}
} else if (v.type === wsOtherLoginNow) {
location.href = ''
window.close()
}
} else {
if (this.ws instanceof WebSocket) {
if (v.type === otherTabSend) {
console.log('其他标签页代理发送消息', v)
this.send(v.data)
}
}
}
});
}
#heartAction() {
console.log('开始发送心跳')
clearTimeout(this.nextHeartNotReceiveTimer)
const {currentUserId, currentUserName} = userStates.value
this.send({
fromID: currentUserId, fromName: currentUserName,
toID: '0', msgType: 'Heart'
})
this.heartLogGroup.length = 0;
this.heartLogGroup.push('客户端发送心跳')
console.log('客户端发送心跳完毕')
this.nextHeartNotReceiveTimer = setTimeout(() => {
this.heartFailedCountDownMutex--;
if (this.heartFailedCountDownMutex > 0) {
return this.#heartAction()
}
if (this.ws instanceof WebSocket) {
console.log('连续三次没有收到服务器心跳,准备重新连接!');
this.isConnectionFailed = true;
this.connectionFailedContinuousTimes++;
this.enforceReconnect = true;
this.close()
this.#persistReopen()
}
}, 7000)
}
#sendHeart(initial = false) {
if (initial) {
this.#heartAction()
} else {
clearTimeout(this.heartTimer);
this.heartTimer = setTimeout(() => {
this.#heartAction()
}, 5000)
}
}
send(data) {
console.log('待发送的ws消息组', data)
if (this.currentTabWSName) {
console.log('当前为子窗口,需要代理发送')
this.bc.send({
type: otherTabSend, data
})
return
}
if (this.ws instanceof WebSocket) {
console.log('ws已经不为空,准备发送')
if (this.ws.readyState !== 1) {
console.log('ws没有被打开,拉入发送缓存')
this.wsCallQueuedData.push(data)
return;
}
console.log('ws已经连接,开始清空所有缓存信息')
if (this.wsCallQueuedData.length) {
this.wsCallQueuedData.forEach((data) => {
this.ws.send(JSON.stringify(data));
})
this.wsCallQueuedData.length = 0
}
this.ws.send(JSON.stringify(data));
console.log('发送ws消息完毕')
} else {
console.log('ws为空,需要将其推入缓存')
this.wsCallQueuedData.push(data)
}
}
close(noAutoReconnect = false) {
console.log('关闭ws中,是否需要重新连接', noAutoReconnect)
this.heartFailedCountDownMutex = 3;
if (this.currentTabWSName)
return;
window.removeEventListener('unload', this.#unloadHandle)
if (noAutoReconnect) {
console.log('不需要重新自动连接!', noAutoReconnect)
this.enforceReconnect = false
clearTimeout(this.nextHeartNotReceiveTimer);
this.currentServerHeartReceivedTime = 0;
}
console.log('关闭ws中')
if (this.ws instanceof WebSocket) {
this.ws.close()
this.ws = null
console.log('ws已经关闭!')
}
}
#persistReopen() {
console.log('进入重新连接ws的判断')
clearTimeout(this.nextHeartNotReceiveTimer)
this.currentServerHeartReceivedTime = 0
if (!this.connectionLostCB()) {
this.enforceReconnect = false
}
if (this.isConnectionFailed && this.connectionFailedContinuousTimes === 5) {
console.log('已经连续5次无法成功连接ws,彻底摆烂!')
this.ws?.close()
this.ws = null
return;
}
if (this.enforceReconnect) {
console.log('需要重连,做出判断开始')
this.isReOpen = true;
this.connect();
}
}
#unloadHandle() {
if (this.ws instanceof WebSocket) {
this.bc.send({
type: wsTabCloseSet,
data: this.allWSNameSet
})
if (this.allWSNameSet.length > 0) {
this.currentTabWSName = `${Date.now()}-Browser`
} else {
this.bc.send({
type: wsOtherLoginNow
})
}
} else {
this.bc.send({
type: otherTabClose,
data: this.currentTabWSName
})
}
}
connect() {
console.log('开始连接ws');
clearTimeout(this.countDownTimerForQueryWSOwnershipTag);
if (this.ws !== null && !this.isReOpen) {
console.log('ws已经连接!')
} else {
if (this.currentTabWSName) {
console.log('当前标签页为子页面,无须连接!');
this.bc.send({
type: currentTabIdNameGet,
data: this.currentTabWSName
})
this.bc.send({
type: wsQueryForMain,
data: this.currentTabWSName
})
this.countDownTimerForQueryWSOwnershipTag = setTimeout(() => {
this.bc.send({
type: wsAnswerForMain
})
this.#reSetUpWS()
}, 5000)
return;
}
console.log('非子标签页,需要连接ws')
this.ws = new WebSocket(this.url)
console.log('实例化ws完毕')
this.ws.addEventListener('message', (e) => {
const dataParsed = JSON.parse(e.data)
this.bc.send({
type: currentWSTabReceive, data: dataParsed
})
if (dataParsed.msgType === 'Heart') {
this.currentServerHeartReceivedTime = Date.now();
this.heartLogGroup.push('收到服务器心跳');
console.log(this.heartLogGroup.join(' <==> '))
this.isConnectionFailed = false
this.connectionFailedContinuousTimes = 0;
this.heartFailedCountDownMutex = 3;
this.#sendHeart()
} else {
this.onMessageFunc(dataParsed)
}
})
this.ws.addEventListener('open', () => {
console.log('ws连接成功!')
if (this.isReOpen) {
console.log('ws重新连接成功')
}
this.heartFailedCountDownMutex = 3;
this.isReOpen = false
this.isConnectionFailed = false;
this.connectionFailedContinuousTimes = 0;
this.enforceReconnect = false
clearTimeout(this.nextHeartNotReceiveTimer)
this.#sendHeart(true)
if (this.lastNameBeforeCurrentTabBeingMainTab) {
this.bc.send({
type: wsConnected,
data: this.lastNameBeforeCurrentTabBeingMainTab
})
this.lastNameBeforeCurrentTabBeingMainTab = ''
}
if (this.isWSTabShifting) {
this.isWSTabShifting = FileSystemSyncAccessHandle
for (const data of this.bufferedDataWhenShift) {
this.send(data)
}
this.bufferedDataWhenShift = []
}
});
this.ws.addEventListener('close', (e) => {
console.log('ws连接关闭!', e, '是否需要重新连接?', this.enforceReconnect)
})
this.ws.addEventListener('error', (e) => {
console.log('ws连接错误!', e, '是否需要重新连接?', this.enforceReconnect)
})
}
}
}
\ No newline at end of file
......@@ -9,5 +9,6 @@
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
<script defer async src="./AgoraRTC_N-4.19.1.js"></script>
</body>
</html>
This source diff could not be displayed because it is too large. You can view the blob instead.
<template>
<a-config-provider :locale="localeVal">
<router-view />
<global-setting />
</a-config-provider>
<a-config-provider :locale="localeVal">
<router-view/>
<global-setting/>
</a-config-provider>
</template>
<script setup lang="ts">
<script lang="ts" setup>
import enUS from '@arco-design/web-vue/es/locale/lang/en-us'
import zhCN from '@arco-design/web-vue/es/locale/lang/zh-cn'
......@@ -14,34 +14,35 @@ import GlobalSetting from '@/components/global-setting/index.vue'
import useLocale from '@/hooks/locale'
import useAppStore from '@/store/app/index'
import { activedTheme } from '../project.ui.config'
import {activedTheme} from '../project.ui.config'
import config from '../project.app.config'
import useUserStore from '@/store/user'
import {wsShouldOpen} from "AnyR/states/coreState";
const { changeTheme } = useAppStore()
const {changeTheme} = useAppStore()
// 国际化
const { currentLocale } = useLocale()
const {currentLocale} = useLocale()
const localeVal = computed(() => {
switch (currentLocale.value) {
case 'zh-CN':
return zhCN
case 'en-US':
return enUS
default:
return zhCN
}
switch (currentLocale.value) {
case 'zh-CN':
return zhCN
case 'en-US':
return enUS
default:
return zhCN
}
})
const userStore = useUserStore()
onMounted(() => {
if (userStore.token) {
changeTheme(activedTheme.value)
}
if (userStore.token) {
changeTheme(activedTheme.value)
}
})
watch(activedTheme, (newVal) => {
changeTheme(newVal)
changeTheme(newVal)
})
const router = useRouter()
......@@ -49,29 +50,30 @@ const router = useRouter()
// @ts-ignore
//全局前置守卫
router.beforeEach(async (to, from, next) => {
const userStore = useUserStore()
const token = userStore.token
if (token) {
// 登录
if (to.name == 'Login') {
next({ path: './' })
} else {
next()
}
const userStore = useUserStore()
const token = userStore.token
if (token) {
wsShouldOpen.value = true;
// 登录
if (to.name == 'Login') {
next({path: './'})
} else {
next()
}
} else {
//未登录
if (to.name == 'Login') {
next()
} else {
//未登录
if (to.name == 'Login') {
next()
} else {
next({ name: 'Login' })
}
next({name: 'Login'})
}
}
})
//全局后置守卫
router.afterEach(async (to) => {
// 动态标题
let pageTitle = !to.meta.hideBaseTitle ? config.baseTitle + ' - ' : ''
if (to.meta.title != '') pageTitle += to.meta.title
window.document.title = pageTitle
// 动态标题
let pageTitle = !to.meta.hideBaseTitle ? config.baseTitle + ' - ' : ''
if (to.meta.title != '') pageTitle += to.meta.title
window.document.title = pageTitle
})
</script>
......@@ -5,6 +5,12 @@
// Generated by unplugin-auto-import
export {}
declare global {
const AD: typeof import('@arco-design/web-vue')['D']
const AE: typeof import('@arco-design/web-vue')['E']
const AL: typeof import('@arco-design/web-vue')['L']
const AN: typeof import('@arco-design/web-vue')['N']
const AP: typeof import('@arco-design/web-vue')['P']
const AR: typeof import('@arco-design/web-vue')['R']
const EffectScope: typeof import('vue')['EffectScope']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
......
......@@ -3,6 +3,10 @@ import App from './App.vue'
import router from './router'
import { setupPinia } from './store/'
import i18n from './locale'
import {wsShouldOpen} from "AnyR/states/coreState.js"
import AnyRemotePlugin from "AnyR/plugin"
import {getBrowserDeviceId} from "AnyR/utils/makeSID";
import useStore from "@/store/user/index"
// import directive from './directive';
......@@ -20,5 +24,46 @@ const app = createApp(App)
app.use(router)
setupPinia(app)
app.use(i18n)
app.use(AnyRemotePlugin, {
wsOpts() {
const user = useStore()
return {
url: `wss://ifar.test.com:440/wesocket?seatId=1&realUserId=${user.user_info.id}&fromID=${user.user_info.id}&username=${user.user_info.nickname}&fromName=${user.user_info.username}&deviceID=${getBrowserDeviceId()}&companyID=1&userCallGroup=1&hasMike=1&hasCamera=1&wsPwd=7ahU8LVba_mbpn_ZX6wyE&isInChat=1`,
tabVisibleCB() {
return true;
},
connectionLostCB() {
return true;
},
wsSocketChannelName: `NameUserT${user.user_info.id}`,
}
},
wsOpen: wsShouldOpen,
agoraConfig: {
notUploadLog: false,
logLevel: 0,
codec: 'vp8',
mode: 'rtc',
appId: '8db91fa9518f457e9fd489198409acf0',
localPlayerId: 'LocalVideo',
remotePlayerPrefix: 'RemoteVideo',
localAp: {
"log": {},
"report": {},
"accessPoints": {
"serverList": [
"ifar.test.com"
],
"domain": "test.com"
}
}
},
recordConfig: {
callBackUrl: 'https://hna-platform.anyremote.cn/call/saveScreenRecordNoToken',
fileDomain: 'https://video.anyremote.cn:444',
recordStartUrl: 'https://ifar.test.com:3001/recorder/v1/start',
recordStopUrl: 'https://ifar.test.com:3001/recorder/v1/stop'
}
})
// app.use(directive);
app.mount('#app')
......@@ -2,6 +2,7 @@ import { defineStore } from 'pinia'
import type { UserState, UserInfo } from './types'
import useAppStore from '@/store/app/index'
import { activedTheme } from '../../../project.ui.config'
import {wsShouldOpen} from "AnyR/states/coreState.js"
const useContactsStore = defineStore('user', {
state: (): UserState => {
......@@ -31,6 +32,9 @@ const useContactsStore = defineStore('user', {
const { changeTheme } = useAppStore()
changeTheme(activedTheme.value)
this.router.push('/')
.then(function () {
wsShouldOpen.value = true;
})
},
//退出登录
handleLogOut() {
......
......@@ -21,9 +21,11 @@
"noUnusedLocals": false,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"allowJs": true,
"paths": {
"@/*": ["src/*"]
"@/*": ["src/*"],
"AnyR/*" : ["anyremote/*"]
},
"baseUrl": "."
},
......
......@@ -60,7 +60,8 @@ export default defineConfig({
],
resolve: {
alias: {
'@': resolve('src')
'@': resolve('src'),
'AnyR': resolve(__dirname, 'anyremote')
}
},
base: './', // 打包路径
......@@ -68,5 +69,8 @@ export default defineConfig({
port: 3000, // 启动端口
open: true, // 自动打开
cors: true // 跨域
},
optimizeDeps: {
exclude: ['AnyR/agora/AgoraRTC_N-4.19.1.js']
}
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment