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.
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
...@@ -9,5 +9,6 @@ ...@@ -9,5 +9,6 @@
<body> <body>
<div id="app"></div> <div id="app"></div>
<script type="module" src="/src/main.ts"></script> <script type="module" src="/src/main.ts"></script>
<script defer async src="./AgoraRTC_N-4.19.1.js"></script>
</body> </body>
</html> </html>
This source diff could not be displayed because it is too large. You can view the blob instead.
<template> <template>
<a-config-provider :locale="localeVal"> <a-config-provider :locale="localeVal">
<router-view /> <router-view/>
<global-setting /> <global-setting/>
</a-config-provider> </a-config-provider>
</template> </template>
<script setup lang="ts"> <script lang="ts" setup>
import enUS from '@arco-design/web-vue/es/locale/lang/en-us' import enUS from '@arco-design/web-vue/es/locale/lang/en-us'
import zhCN from '@arco-design/web-vue/es/locale/lang/zh-cn' import zhCN from '@arco-design/web-vue/es/locale/lang/zh-cn'
...@@ -14,34 +14,35 @@ import GlobalSetting from '@/components/global-setting/index.vue' ...@@ -14,34 +14,35 @@ import GlobalSetting from '@/components/global-setting/index.vue'
import useLocale from '@/hooks/locale' import useLocale from '@/hooks/locale'
import useAppStore from '@/store/app/index' 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 config from '../project.app.config'
import useUserStore from '@/store/user' 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(() => { const localeVal = computed(() => {
switch (currentLocale.value) { switch (currentLocale.value) {
case 'zh-CN': case 'zh-CN':
return zhCN return zhCN
case 'en-US': case 'en-US':
return enUS return enUS
default: default:
return zhCN return zhCN
} }
}) })
const userStore = useUserStore() const userStore = useUserStore()
onMounted(() => { onMounted(() => {
if (userStore.token) { if (userStore.token) {
changeTheme(activedTheme.value) changeTheme(activedTheme.value)
} }
}) })
watch(activedTheme, (newVal) => { watch(activedTheme, (newVal) => {
changeTheme(newVal) changeTheme(newVal)
}) })
const router = useRouter() const router = useRouter()
...@@ -49,29 +50,30 @@ const router = useRouter() ...@@ -49,29 +50,30 @@ const router = useRouter()
// @ts-ignore // @ts-ignore
//全局前置守卫 //全局前置守卫
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
const userStore = useUserStore() const userStore = useUserStore()
const token = userStore.token const token = userStore.token
if (token) { if (token) {
// 登录 wsShouldOpen.value = true;
if (to.name == 'Login') { // 登录
next({ path: './' }) if (to.name == 'Login') {
} else { next({path: './'})
next() } else {
} next()
}
} else {
//未登录
if (to.name == 'Login') {
next()
} else { } else {
//未登录 next({name: 'Login'})
if (to.name == 'Login') {
next()
} else {
next({ name: 'Login' })
}
} }
}
}) })
//全局后置守卫 //全局后置守卫
router.afterEach(async (to) => { router.afterEach(async (to) => {
// 动态标题 // 动态标题
let pageTitle = !to.meta.hideBaseTitle ? config.baseTitle + ' - ' : '' let pageTitle = !to.meta.hideBaseTitle ? config.baseTitle + ' - ' : ''
if (to.meta.title != '') pageTitle += to.meta.title if (to.meta.title != '') pageTitle += to.meta.title
window.document.title = pageTitle window.document.title = pageTitle
}) })
</script> </script>
...@@ -5,6 +5,12 @@ ...@@ -5,6 +5,12 @@
// Generated by unplugin-auto-import // Generated by unplugin-auto-import
export {} export {}
declare global { 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 EffectScope: typeof import('vue')['EffectScope']
const computed: typeof import('vue')['computed'] const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp'] const createApp: typeof import('vue')['createApp']
......
...@@ -3,6 +3,10 @@ import App from './App.vue' ...@@ -3,6 +3,10 @@ import App from './App.vue'
import router from './router' import router from './router'
import { setupPinia } from './store/' import { setupPinia } from './store/'
import i18n from './locale' 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'; // import directive from './directive';
...@@ -20,5 +24,46 @@ const app = createApp(App) ...@@ -20,5 +24,46 @@ const app = createApp(App)
app.use(router) app.use(router)
setupPinia(app) setupPinia(app)
app.use(i18n) 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.use(directive);
app.mount('#app') app.mount('#app')
...@@ -2,6 +2,7 @@ import { defineStore } from 'pinia' ...@@ -2,6 +2,7 @@ import { defineStore } from 'pinia'
import type { UserState, UserInfo } from './types' import type { UserState, UserInfo } from './types'
import useAppStore from '@/store/app/index' import useAppStore from '@/store/app/index'
import { activedTheme } from '../../../project.ui.config' import { activedTheme } from '../../../project.ui.config'
import {wsShouldOpen} from "AnyR/states/coreState.js"
const useContactsStore = defineStore('user', { const useContactsStore = defineStore('user', {
state: (): UserState => { state: (): UserState => {
...@@ -31,6 +32,9 @@ const useContactsStore = defineStore('user', { ...@@ -31,6 +32,9 @@ const useContactsStore = defineStore('user', {
const { changeTheme } = useAppStore() const { changeTheme } = useAppStore()
changeTheme(activedTheme.value) changeTheme(activedTheme.value)
this.router.push('/') this.router.push('/')
.then(function () {
wsShouldOpen.value = true;
})
}, },
//退出登录 //退出登录
handleLogOut() { handleLogOut() {
......
...@@ -21,9 +21,11 @@ ...@@ -21,9 +21,11 @@
"noUnusedLocals": false, "noUnusedLocals": false,
"noUnusedParameters": true, "noUnusedParameters": true,
"noFallthroughCasesInSwitch": true, "noFallthroughCasesInSwitch": true,
"allowJs": true,
"paths": { "paths": {
"@/*": ["src/*"] "@/*": ["src/*"],
"AnyR/*" : ["anyremote/*"]
}, },
"baseUrl": "." "baseUrl": "."
}, },
......
...@@ -60,7 +60,8 @@ export default defineConfig({ ...@@ -60,7 +60,8 @@ export default defineConfig({
], ],
resolve: { resolve: {
alias: { alias: {
'@': resolve('src') '@': resolve('src'),
'AnyR': resolve(__dirname, 'anyremote')
} }
}, },
base: './', // 打包路径 base: './', // 打包路径
...@@ -68,5 +69,8 @@ export default defineConfig({ ...@@ -68,5 +69,8 @@ export default defineConfig({
port: 3000, // 启动端口 port: 3000, // 启动端口
open: true, // 自动打开 open: true, // 自动打开
cors: 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